JavaScript知识点

1、JavaScript特色javascript

  1. 解释性语言——不须要编译代码,能够跨平台,像php、js、jsp都是解释性语言。
  2. 单线程——js是单线程的语言,同时只能执行一件事情
  3. ECMA标准——为了统一js的规则,推出了ECMA标准,所以js也称为ECMAScript。

2、JavaScript三大部分:(ECMAScript、DOM、BOM)

  1. ECMAScript是符合ECMA标准的基本javascript。
  2. DOM是Document Object Model文档对象模型,能够操做页面的代码,能够操做html和css部分。DOM是很是很是重要的部分。
  3. BOM是Browser Object Model浏览器对象模型,操做浏览器shell的。由于每个浏览器厂家的不一样,致使咱们在每个浏览器操做BOM都不同。

3、JavaScript的基本语法

  1. 变量声明php

  • Js是一种弱数据类型的语言,任何类型的变量都用关键字Var来声明。
1 var arr = [1,2,3];
2 var num = 123;
3 var steing = "abc";
  • 赋值能够在声明的的同时赋值,也能够在后面赋值。
1 var num = 123;
2 var num;
3 num = 123;
  • 这两种方法是同样的。
  • 同时有一种单一Var模式。
1 var num1 = 123,
2     num2 = 234,
3     num3 = 456;
  • 变量名上下对齐,这样结构更清晰,也能节省不少代码。

2.变量命名规则css

  • 以英文字母开头或者_和$符开头。
  • 变量名能够包含数字。
  • 不可使用系统自带的关键字,保留字。

3.数据类型(值类型)html

  • 不可改变的原始值。
  • 主要有 Number String Boolean undefined null 堆数据。
  • 引用值 数组Array 对象Object 函数function 栈数据。

4、JavaScript语句的基本规则

  1. 语句后面要用英文“ ;”结束。
  2. js语法错误会引起后续代码的终止,但不会影响其余的js代码块,这里仅限于逻辑错误和低级语法错误会致使代码所有执行不了。
  3. 书写规范(不一样公司有不一样要求)。

5、JavaScript运算符

  1. “ + ”数学上相加的功能和字符串拼接“- * / % ”数学运算。
  2. 相同的还有“++ == -- += -= > < ...”等等。
  3. 逻辑运算符 && || !
  • && 的做用是结果是true的时候才会继续执行,第一个就错了第二个不会执行,若是都是true的话返回最后一个。
  • || 的做用是结果只要有一个表达式是true的,后面的就不走了,而且返回的结果是这个正确的表达式的结果,全是false表达式返回的结果就是false。
  • && 能够当作一种短路语言使用;|| 能够当作赋初值的使用。

4.默认为false的值java

  • unedfined; null; " "; NaN; 0; false 。

6、类型转换

(一)显示类型转换
  1. 用 typeof 能够检测数据的类型。
1 console.log(typeof(123)); // Number
  • typeof 返回的结果有六种:number string boolear undefined object function 。
  • 数组和 null 都属于object。
  • NaN 属于number ,虽然是非数,但也属于数字。
  • typeof 返回结果是字符串。

2.Number(mix)[混合]es6

  • 这个方法是能够把其余类型的数据转换成数字类型的数据。

3.parseInt(string,radix)[基数]shell

  • 这个方法是将字符串转换成整型类型数字的。其中第二个参数radix基底是能够选择的参数。
  • 当radix为空的时候,这个函数的做用仅仅是将字符串转换成number类型。
  • 当参数string里面既包括数字字符串又包括其余字符串的时候,它会将看到其余字符串就中止了,不会继续转换后面的数字型字符串了。
1 parseInt('123abc123') // 123;
2 parseInt('abc123')    // NaN;
3 parseInt('123')       // 123;
4 parseInt('true')      // NaN;
  • 当radix不为空的时候这个函数能够用做进制转换,把第一个参数的数字当成几进制的数字转换成十进制。
  • radix参考范围是2--36,
1 var demo = 10;
2 parseInt(demo,16) //16

4.parseFloat(radix)数组

  • 这个方法和parseInt相似,是将字符串转换成浮点类型的数字,碰到第一个非数字类型中止。
  • 只能识别第一个小数点及后面的数字,第二个小数点不能识别。
1 parseFloat('123.2.3')  // 123.2
2 parseFloat('132.2abc') // 123.2
3 parseFloat('123.abc1') // 123

5.toString(radix)浏览器

  • 这个方法和前面的不一样,它是对象上的方法,任何数据类型均可以使用,转换成字符串类型,涉及到包装类。
  • 一样是radix基地可选参数,为空仅仅将数据转换成字符串。
1 var demo = 123;
2 typeof demo.toString(); // string123;
3 typeof true.toString(); // stringtrue;
  • 当写了radix时表明要将这个数字转换成几进制的数字型字符串。
1 var dome = 10;
2 demo.toString(16) // A
  • undefined和null没有toString方法

6.String(mix)闭包

  • 和Number相似把任何类型转换成字符串

7.Boolean(mix)

  • 和Number相似把任何类型转换为Boolean
(二)隐式类型转换

1.isNaN()

  • 这个方法能够检测是否是非数类型,调用的Number方法。

2.算数运算符

  • ++就是将现有数据调用Number以后,自身加一。
  • + - * / 执行以前都会先进行类型转换,换成数字在运算。

3.逻辑运算符

  • && || ! 都会调用Boolean转换成布尔值看看结果是ture仍是false,返回结果仍是自己表达式的结果。
  • // !abc; // false

4.不发生类型转换的比较运算符

  • ===严格等于 !==严格不等于

7、预编译【precompile】

函数声明提高:函数声明提高是一种总体提高,他、它会把函数声明和函数体一块儿提到前面。

变量声明提高:变量声明提高是一种局部提高,它仅仅将变量的声明提早了,可是并无将赋值一块儿提高。

 1.js运行三部曲

  • 语法分析
  • 预编译
  • 解析执行

2.预编译前奏

  • imply global
  • 暗示全局变量,若是任何变量未经声明就赋值使用,此变量归window全部,而且成为window对象的一个属性。
  • 一切声明的全局变量,都是window属性。
  • 未经声明的全局变量能够用delete操做来删除。
  • 函数在执行的前一刻一个执行上下文,Activeaction Object对象。
  • 这个对象是空的,可是里面有着一些看不见的隐式属性:this:window属性和arguments[];属性。

3.预编译四步

  • 建立AO对象
  • 寻找形参和变量声明并当作属性名添加到AO对象中,值为undefined。//函数声明不叫变量。
  • 将实参形参相统一
  • 在函数体里寻找函数声明,将函数名当作属性名,值为这个函数的函数体。
复制代码
 1  function test (a,b) {
 2      console.log(a)
 3      function a () {}
 4      a = 222;
 5      console.log(a)
 6      function b () {};
 7      console.log(b)
 8      var b = 111;
 9      var a;
10  } 
11  test(1);
复制代码
  • var b = function () {} 这种不叫函数声明,这个函数是给b赋值的,b变量是声明。
  • 在第四步寻找函数声明并不会把赋值成function(){},执行到这一行的时候才会赋值成这个函数。

10、函数与做用域与闭包

(一)函数部分

1.函数声明有3种方式

1 var demo = function () {}; 函数表达式
2 function demo () {}; 函数声明
3 var demo = function xxx () {};命名函数表达式   //没用
  • 每个函数里面都有一个类数组属性arguments,这个属性里面存的就是实参。
  • 每个函数有一个length属性,这个属性存的是形参的数量。
  • 每个函数都会有一个return,若是不写的话函数会自动加一个return。
  • return的功能有两个:返回这个函数的执行结果、终止函数的执行。
复制代码
1 function test(a,b) {
2     console.log(a + b);
3     return;
4     console.log('hello');
5 }
6 test(1,2);  //  打印结果3   不会打印hello
复制代码
(二)做用域
  • 定义:变量(变量做用域又称为上下文)和函数生效(能被访问)的区域。
  • JavaScript的函数是能够产生做用域的。
  • es5中的做用域只有全局做用域函数做用域两种,es6新添加的块级做用域。
复制代码
1 var demo = 123;  // 全局变量
2 function test () {
3   var demo = 234; // 局部变量
4   console.log(demo);
5   var demo1 = 'hello';
6   }
7 test(demo);  // 打印234    就近打印局部变量,没有局部变量打印全局变量
8 console.log(demo1); // 报错 咱们的全局做用域没法访问局部做用域
复制代码
  • 函数做用域就好像一个屋子,里面的能够拿外面的东西,外面的不能拿里面的东西。
  • 在函数做用域里声明变量没有用var的话,那么就生成了一个全局变量。
  • 两个不一样的做用域(除了全局做用域)是不能互访问的。
(三)做用域链(scope chain)
  • 既然函数存在做用域,函数有能够嵌套,那么做用域就会产生嵌套关系,这个时候就产生做用域链。
  • 当代码在一个环境中执行时,会建立变量的做用域链来保证对执行环境有权访问的变量和函数的有序访问。
  • 做用域链第一个对象始终是当前执行代码所在环境的变量对象。
复制代码
1  function demo () {
2     var dome_a = 1;
3     function test () {
4         var demo_a = 2;
5         console.log(demo_a);
6     }
7     test();
8  }
9  demo();
复制代码
  • 本着对执行环境的有权和有序访问,每一个函数的自身做用域总在做用域链的最顶层,下一层就是这个函数的父级函数做用域,直到全局做用域。
  • 所以test执行的时候打印的demo_a是自己做用域中的是‘2’而不是‘1’,若是自身做用域没有demo_a的话系统就会沿着做用域链向下找demo_a。
(四)闭包【closure】

1.什么是闭包

  • 闭包就是可以读取其它函数内部变量的函数。
  • 不一样的做用有之间不能互相访问,可是若是在一个函数内部再定义一个函数与外部的变量有所关联,那么就能够返回这个函数来访问外部函数里面的变量,因此在本质上闭包就是将函数内部与函数外部链接起来的桥梁。
复制代码
 1  function a (){
 2     var dome1 = 123;
 3     add = function(){
 4         demo1 ++;
 5     }
 6     return function(){
 7         console.log(demo1);
 8     };
 9  }
10 var demo = a ();
11 demo();    // 123
12 add();   
13 demo();    // 124
复制代码
  • 当函数执行完函数的执行上下文就会被销毁,天然就没法访问里面的变量了,可是咱们这个函数返回了一个依赖于这个函数的新函数,也就是说这个没有被销毁的新函数的做用域链中存在着本来函数做用域的引用,就致使本来函数的上下文不会被销毁,返回的新函数是本来函数的闭包函数。

2.使用闭包的注意点

  • 闭包会使函数的变量都保存在内存中,内存消耗很大,不能滥用闭包,不然会形成网页的性能问题,IE会形成内存泄漏。解决的方法就是退出函数时,将不使用的局部变量所有删除。
  • 闭包会在父函数外部改变父函数内部的值,若是把闭包当对象使用,那么就把闭包当作它的公用方法,把内部变量当作它的稀有属性。(不要随便改变函数内部变量的值)
复制代码
 1 var name = 'global';
 2 var obj = {
 3       name:'obj',
 4       getName:function() {
 5             return function () {
 6                  console.log(this.name);
 8                 }
10            }
11     }  
12 obj.getName() ();      
复制代码
  • 累加器的例子:
复制代码
 1  function a () {
 2      var num = 1;
 3      function addNum () {
 4          num ++;
 5          console.log(num);
 6      }
 7      return addNum;
 8  }
 9  var demo = a ();
10  demo();
11  demo();
12  var demo1 = a();
13  demo1();
14  demo1();
复制代码
(五)当即执行函数
  • 当即执行函数是解闭包的一个重要方法,可是注意闭包是没有办法解除的,只能经过一个新的闭包来消除上一个闭包的影响。
  • 当即执行函数不须要被定义,直接执行,执行完释放,常常做用做初始化。
  • 函数声明不能被执行,可是函数表达式能够
复制代码
 1  (function (){}())
 2  function returnB() {
 3      var arr = [];
 4      for(i = 0; i < 10; i ++){
 5          arr[i] = (function(){
 6              console.log(i);
 7          }())
 8      }
 9      return arr;
10  }
11  var save = returnB();
12  console.log(save);
13  for(j = 0; j < 10; j ++){
14      save[j];
15  }
复制代码

11、对象、构造函数与包装类

1.对象的建立方式有三点

  • 对象字面量。
1 var obj ={};
  • 这样的方式是最简单最经常使用的方法。
  • 对象里面有属性,属性之间用逗号相隔,每条属性都有属性名和值,属性名和属性值用分号相隔。

2.构造函数【constructor】

  • 构造函数也分为两种,系统自带的构造函数和自定义的构造函数。
  • 建立对象的构造函数Object()
1 var object = new object();
  • 经过这条语句就建立了一个空对象,它的做用和 var obj = {}; 的做用同样。
  • 系统自带的构造函数还有Number();String();Boolean();Array() 。

3.自定义构造函数

  • 自定义的构造函数是最多见的一种构造函数。
1  var function Person () {};
2  var operson = new Person ();
3  typeof operson  // object
  • 用new操做符创造出来的对象,尽管使用的是一个构造函数,可是之间没有联系。
复制代码
1  function Person (name,age) {
2      this.name = name;
3      this.age = age;
4  }
5  var person = new Person('zhangsan',18);
6  console.log(person.name);
复制代码
  • 建立对象的时候只有new才会有this。
  • 重点:为何能够用new操做符建立出相互独立的对象呢?
  • 用new操做符的时候,这个new在构造函数里面隐式的建立了一个this对象,而且最后返回了这个this对象。
1 function Person (name) {
2         var this = {};
3         this.name = name;
4             return this;
5   }
  • 若是在构造函数首行手动建立一个对象,好比that对象,而后返回that,那么里面的this就没有了,属性值就用that了。
复制代码
1  function Person (name) {
2      var that = {
3          name: 'lisi'
4      };
5      that.name = name;
6      return that;
7  }
8  var person = new Person ('demo');
9  console.log(person.name)
复制代码
  • 若是最后返回的是对象,那么this就失效,可是若是显示返回的是原始值那么this仍是有效的。

4.属性的增删改查

  • 增:能够经过对象名+点属性名的方法来给对象添加新的属性而且赋值。
1 var obj = {};
2 obj.name = 'xiaoming'
  • 改:修改的操做增长是同样的,只要调用相同的属性名而后赋一个新值就能够了。
1  var obj = {
2    name:'demo';
3  }
4  obj.name = 'tan';
  • 查:查看属性的功能console.log(xxx)。
  • 删:删除属性须要借助delete操做符。
复制代码
1  var obj = {
2      name = 'scerlett'
3  }
4  obj.name;  // scerlett
5  delete obj.name;
6  obj.name;  // undefined
复制代码
  • 包装类

12、原型与原型链

(一)原型:prototype

1.原型的定义:原型是function对象的一个属性,它定义了构造函数制造出来的对象的公有祖先,经过该构造函数产生的对象,能够继承原型的属性和方法,原型也是对象。

1 function Person () {}
  • 定义一个构造函数,Person.prototype这个属性就是这个构造函数的原理,这个属性天生就有的,而且这个属性的值也是一个对象。
  • 能够在person.prototype上面添加属性和方法,每一构造出来的对象均可以继承这些属性和方法。
  • 虽然每个对象都是独立的,可是它们都有共同的祖先,当访问这个对象属性的时候,若是它没有这个属性,就会向上查找,找到它原型,而后在原型上访问这个属性。

2.利用原型特色概念,能够提取公有属性

  • 能够把每个对象都有的公有属性不写在构造函数里面,而是提取到原型上,这样当构造函数构造大量的对象的时候就不须要走屡次构造里面的赋值语句了,而只需走一遍,每一个对象调用属性的时候直接上原型上查找就能够了。

3.对象如何查看原型

  • 用构造函数构造对象的时候,就会隐式建立一个this对象,这个this对象里面有一个默认的属性叫作proto属性,这个属性的值就是指向对象的原型。
  • 当查找的属性是自身没有的属性的时候,就会查找proto这个属性,而后这个属性指向原型,因此就到原型上查找属性了。
  • 注意:prototype是函数的属性,proto是对象的属性。

4.如何查看构造自身的构造函数

  • 在prototype里面,有一个隐式的属性叫作constructor,这个属性记录的就是对象的构造器,里面存的就是构造函数。
1 console.log(person.constructor); //person();
(二)原型链

1.有了原型,原型仍是一个对象,那么这个名为原型的对象天然还有本身的原型,这样的原型上还有原型的结构就成了原型链。

复制代码
 1  Gra.prototype.firsName = 'scarlett'
 2  function Gra () {
 3      this.name = 'grandfather';
 4      this.sex = 'male';
 5  }
 6  var grandfoo = new Gra();
 7  garndfoo.word = 'hello'
 8  Foo.prototype = grandfoo;
 9  function Foo () {
10      this.age = '18';
11      this.money = '100';
12  }
13  var father = new Foo();
14  function Son () {
15      this.name = 'son';
16  }
17  Son.prototype = father;
18  var son = new Son();
复制代码
  • Foo创造出来的每个对象都继承来自grandfoo对象,son的每一对象都继承来自father这个由Foo创造出来的对象,这样的son就能够继承上面Foo和Gra的全部属性。
  • 这种链式的查询结构就叫作原型,最终的尽头是Object.prototype这个对象。
  • 若是没有规定原型的对象,它的原型就是Object.prototype。

2.可是并非全部的对象都有原型,好比使用Object.create方法。

  • Object.create()方法须要写一个参数,这个参数就是对象的原型,若是要构造一个var obj = {};同样的对象,就须要写:
1 var obj = Object.create(Object.prototype);
  • 也能够写一个自定义的属性,让它成为原型。

3.原型链上的增删改查

1 Person.prototype.arr[1,2,3];
2 var person1 = new Person();
3 var person2 = new Person();
4 person1.arr.push(4);
5 console.log(person2);//1 2 3 4 
  • 删:删除属性须要借助delete操做符,对象不能删除原型上的属性。

 十3、继承、this

1.this的一些问题:

函数内部的this默认指向window,可使用call / apply来改变this的指向,区别:后面传参形式不一样。

1 function person () {
2   this.name = 'scarlett';
3   console.log(this);
4   }
5   person();

  如今this指向window,name属性天然就是window上的全局属性

var obj = {};

person。call(object)//Object.{name:'scarlett'}

  若是这个函数还有参数的话,只要把实参的值写在call后面而且用逗号隔开

复制代码
 function person(name,age){
     this.name = name;
     this.age = age;
 }
 var obj = {};
 person.call(obj,'scarlett',18);
 console.log(obj.name);
复制代码

  apply和call基本没什么区别,惟一的区别就是call后面的参数是一个一个传的,而apply后面的参数是放在数组里

person.apply(obj['scarlett',18]);

2.继承【inherit】

  圣杯模式

复制代码
function inherit(Target, Origin) {
    function F() {};
    F.prototype = Origin.prototype;
    Target.prototype = new F();
    Target.prototype.constuctor = Target;//让constuctor指向本身的
    Target.prototype.uber = Origin.prototype; //超类,知道本身继承的是谁
复制代码

  yahu封装方法:

复制代码
 1 // var inherit = (function (){
 2 //     var F = function () {};
 3 //     return function (Target, Origin){
 4 //         F.prototype = Origin.prototype;
 5 //         Target.prototype = new F();
 6 //         Target.prototype.constuctor = Target;
 7 //         Target.prototype.uber = Origin.prototype;
 8 //     }
 9 // }());
10 // 
11 //         for (var i = 0; i < 5; i ++) {
12 //             var btn = document.createElement('button');
13 //             btn.appendChild(document.createTextNode('Button' + i));
14 //             btn.addEventListener('click', function(){console.log(i); });
15 //             document.body.appendChild(btn);
16 //         }
复制代码

  对象的枚举与this

1.对象的枚举

  查看对象的属性能够用obj.name查看,也能够用obj['name']类数组方式查看,但事实上是数组模仿了对象的查看方式

2.for-in操做符

  要枚举一个数组的全部属性只需用一个for循环从头至尾遍历一遍就能够了。

  可是对象并不能用for循环来遍历属性,全部就要用到for-in操做了

复制代码
1 // var obj = {
2 //     name: 'scarlett',
3 //     age: 18,
4 //     sex: 'female'
5 // }
6 // for(var prop in obj){
7 //     console.log(prop + ':' + obj[prop]);
8 // }
复制代码
  • for-in循环会按照属性的顺序取出属性名而后赋给prop,全部打印prop都是属性名,obj【prop】则是性对应的属性的值
  • 注意:这里不能写成obj.prop方式,由于在系统底层会转化成obj【‘prop’】的形式,可是并无prop属性,它只是一个变量,因此会打印  undefined,这里必须使用obj['prop']。
  • 在非严格模式中,for-in循环都会把原型里面的一些属性一块儿打印出来,但es5的严格模式不会。

2.三种操做符

  hasOwnProperty这个操做符的做用是查看当前这个属性是否是对象自身的属性,在原型链上的属性会被过滤掉,自身的ture

复制代码
// function Person() {
//     this.name = 'scarlett'
// }
// Person.prototype = {
//     age:18
// }
// var oPerson = new Person();
// for (var prop in oPerson) {
//     if (oPerson.hasOwnProperty(prop)){
//         console.log(oPerson[prop]);
//     }
// }
复制代码

  这样for-in循环就只会打印自身的属性,而不是打印原型上的属性

  in操做符:这个操做符的做用是查看一个属性是否是在这个对象或者它原型里面。

1 // 'name' in oPerson;    //ture
2 // 'sex' in oPerson;   //False

  instanceof操做符:做用是查看前面对象是否是后面的构造函数构造出来的,和constructor很像

1 // oPerson intanceof object;    // ture
2 // {} instanceof oPerson;  // false

3.this

  • 预编译过程当中this执行window
  • 全局做用域里的this指向window
  • call / apply能够改变this指向
  • obj.func()func()里的this指向Obj
复制代码
1 // var obj = {
2 //     height:190,
3 //     eat:function () {
4 //         this.height ++;  // eat在没有执行以前,谁也不知道this指向谁
5 //     }
6 // }
7 // obj.eat(); // 谁调用this,this指向谁
8 // eat.call(obj); // eat里面的this指向obj
复制代码

  若是能理解下面的这段代码的this指向问题,那么就掌握的this的全部知识点了

复制代码
 1 // var name = '222'
 2 // var a = {
 3 //     name:'111',
 4 //     say:function () {
 5 //         console.log(this.name);
 6 //     }
 7 // }
 8 // var fun = a.say;
 9 // fun();   // 此处其实就是把a.say这个函数体赋给fun这个函数,至关于在全局空间写下了一个fun函数,此时this指向window,打印'222'
10 // a.say();  // 按照谁调用指向谁的说法,这里打印'111'
11 // var b = {
12 //     name:'333',
13 //     say:function (fun) {
14 //         fun();
15 //     }
16 // }
17 // b.say(a.say); // 其实和在全局调用a.say的函数体方法差很少,打印'222'
18 // b.say = a.say;
19 // b.say(); // this指向B 因此打印'333'
复制代码

十5、克隆与数组

1.argument.callee

  这个方法是指代函数自己,当在一些匿名函数或者当即执行函数里面进行递归调用函数自己的时候,因为没有名字,就用这种方式调用;

  通常当须要经过计算机进行初始化的时候,写一个当即执行函数,当这个当即执行函数还须要递归调用自身的时候,就用这种方式调用。

2.function.caller

复制代码
// function test () {
//     console.log(test.caller);
// }
// function demo () {
//     test()
// }
// demo();
复制代码

  这是函数自己自带的一个属性,能够指出当前函数的ude运行环境的函数引用,就是这个函数在哪一个函数里面执行的……

3.克隆【clone】

  克隆和继承有一些区别,克隆是复制出来如出一辙的目标对象又分为浅度克隆和深度克隆

复制代码
// function clone (src,tar) {
//     var tar = tar || {};
//     for (var prop in src) {
//         if (src.hasOwnProperty(prop)){
//             tar[prop] = src[prop];
//         }
//     }
//     return tar;
// }
复制代码

  当有一个属性是引用值(数组、对象)时按照这种克隆模式,只是把这个引用值的指向赋给了新的目标对象,一旦改变了原对象或者目标对象的引用属性另外一个也跟着变,这一点就是浅度克隆的缺点;

  深度克隆的原理很简单,只要不克隆引用值的引用而是把引用值也当作一个原对象,把里面的值一个个克隆岛目标对象里面,就解决了两者相同指向的问题;

复制代码
// function deepCopy (src,tar) {
//     var tar = tar || {};
//     for (var prop in src) {
//         if(typeof(src[prop] == 'object')){
//             tar[prop] = (src[prop].constructor === Array) ? [] : {};
//         }else{
//             tar[prop] = src[prop];
//         }
//     }
//     return tar;
// }
复制代码

  这个时候目标对象和原对象的引用值就没有关系了,都是独立值能够进行修改。

4.数组【array】

相关文章
相关标签/搜索