• JavaScript常见引用类型笔记(一):Array类型(上)


      这是我的第一篇博客。在今后将会不断更新自己在学习JavaScript的过程中整理的知识点,算是在博客上做笔记吧。

      由于对这些知识还没有深入的理解,文中可能会大量引用《JavaScript高级程序设计》里描述性的语言,其他部分若是有错误,希望各位小伙伴们指出来并给与建议和意见(指点我怎么写博客也行(*^▽^*))。

      今天整理的是有关Array类型的一部分知识。

    Array类型的特点:

    一、存储的数据的任意性

    ECMAscrip数组的每一项可以保存任意类型的数据:

    C语言或者很多其他类C语言中,数组里保存的所有数据必须保证数据类型一致:例如C语言中的数组:

    int a[4] = [1,2,3,4,5];
    char str[] = "program";

    上述分别是一个整形数组和一个字符串类型的数组,数组里的各项数据都是同一种数据类型,数组a中保存的全是int类型,str中保存的都是char类型。而JavaScript数组中的每一项都可以保存任意的数据类型,下面是一个长度为3的数组,数组第一项保存一个Number类型、第二项保存一个String类型,第三项保存一个Function类型:

    var a = [ 1 , "Jams" , function(sum){console.log(sum);} ];
    console.log(a);
    a[2](a[1]);       //打印“Jams”   

    数组a的输出结果(chrome)为:

    二、数组长度的灵活性

      在此观察上述C语言代码中的数组,发现在声明的时候数组a数组后会跟一个数字,这个数字就是该数组的长度,也就是说,在后续对数组的操作过程中,数组长度是固定的。而str数组由于在声明的过程中初始化了,所以其长度也是固定的,长度为“program”的字符个数7。

      JavaScript中的数组大小可以动态调整,可以直接按索引添加,也可以使用pop()等方法移除。

    创建数组的方式:

    一、使用Array构造函数

      基本语法:

    var 数组名 = [new] Array();              //这时length属性默认为0,[]括起来的内容表示可以省略,即可以省略new

      构建指定初始大小的数组:

    var 数组名 = new Array(长度);       //这个长度会变成length属性的值

      使用构造函数创建并初始化:

    var 数组名 =new Array(数据1,数据2,...,数据n);         //注意,不能仅有一个为Number类型的数据,这样会变成指定初始大小的数组

     二、使用数组字面量

      使用字面量表示法时,不会调用Array构造函数。

      基本语法:

    var 数组名 = [];            //创建一个length为0的空数组

      包含初始数据项:

    var 数组名 = [数据1,数据2,...,数据n]    //创建一个包含n个数据的数组

      注意,不要在最后一项数据末尾添加逗号“,”,类似于这样:var = [1,2,3,4,],也不要不写数据项,仅仅写逗号,类似于这样:var 数组名 = [,,,,,,]。因为这两种写法在不同浏览器上会有不同的显示结果,具体请看《JavaScript高级程序设计》Array类型讲解。

    length属性:

      length属性表示了数组当前的长度。它不是只读的,故而可以使用它改变数组的长度,直接赋值即可。也可以很方便的使用length在数组末尾添加一个数据。方法:

    数组名[数组名.length] = 数据;        //添加完之后,length的值会加一

      这里整理一下,读写数组值和length值的变化:

    //读取:索引小于length,读取存储在数组中原本的数据,索引大于等于length,读取到的值为undefined
    var a = [1,2,3,4,5];
    console.log(a[4],a[7]);          //5 undefined
    //写入:索引小于length值,改变数组中原本的数据,大于等于length值,修改这个位置的数组值,同时数组的length将更新为(索引+1),中间空出来的数组值都设置为undefined
    var b = [1,2,3,4,5];
    b[3] = 7;
    console.log(b);             //[1,2,3,7,5]
    var c = [1,2,3,4,5]
    c[8] = 9;
    console.log(c);            //[1,2,3,4,5,undefined,undefined,undefined,9];
    console.log(c.length);     //9

    检测数组的方法:

    一、使用instanceof

      由于数组是对象,故可以使用instanceof来判断某个数组是否是Array引用类型。方法:

    数组名 instanceof Array        //该表达式返回true或者false

      优点:在单一全局环境中使用方便

      缺点:多个全局环境下,由于Array构造函数在不同环境下可能不相同,那么就不能使用instanceof来进行判断。

      个人猜测(如有理解不当,请不吝赐教,这也算是遗留的问题,在将来还需要深入学习):instanceof仅仅是顺着对象的原型链去查找各个原型对象的constructor属性,各个constructor属性指向的构造函数,就是对象所属的类别。由于不同全局环境下,Array构造函数都不一样,故有很多种数组引用类型。比如在某个环境下,有Array1类型的数组,这时从其他环境中传入了一个Array2类型的数组,他们的构造函数名字在各自的环境中可能都叫Array,这时,使用   数组名 instanceof Array;  怎么判断到底是Array1还是Array2。

    二、使用isArray()方法

      ES5新增的方法,使用Array调用,参数传入待检测的数组。

    Array.isArray(数组名);     //结果返回true或者false

      优点:最终确定某个值到底是不是数组,而不管它在哪个全局执行环境中创建的

      缺点:仅有IE9+、FireFox 4+、Safari 5+、Opera 10.5+和Chrome支持这个方法。

    三、其他方法

      后续再另开一个随笔总结,同时希望真正理解instanceof检测数组的限制。

    转换方法:

    一、使用继承自Object的toString()、toLocalString()、valueOf():

      JS所有对象都有继承自Object的一些默认方法,可以直接拿来使用, 但若是自定义toString()、toLocalString()、valueOf()实例方法来覆盖继承自原型的Object方法之后,这些方法的行为将发生改变(下面用方法重写来表示)。

      下面分几种情况来讨论(是否重写上述三种方法,数组里的数据类型)

    1.数组里存储的全部为基本数据类型(这时也不存在重写了)

    var a1 = [1,true,false,null,undefined,"KOBE"];
    console.log(a1.toString());   
    console.log(a1.valueOf());
    console.log(a1.toLocaleString());
    console.log(a1);
                
    alert(a1.toString());
    alert(a1.valueOf());
    alert(a1.toLocaleString());
    alert(a1);

    使用console.log输出结果为:

     使用alert输出结果为(四个alert均是这样的结果):

    总结:基本数据类型数组

    toString()方法:调用各数据项的toString()方法,将各数据项变成字符串的形式,然后使用逗号连接作为结果返回。

    toLacolaeString()方法:调用各数据项的toLocaleString()方法,将各数据项变成字符串的形式,然后使用逗号连接作为结果返回。

    valueOf()方法:返回该数组。

    注意:alert()打印结果都一样,是因为alert()函数会将结果以字符串的形式打印出来。

    2.数组里全为对象,且都不重写toString()、toLocaleString()和valueOf()方法。

    var obj1 = {};
    var obj2 = {};
    var fun = function(){};
    var a1 = [obj1,obj2,fun];
    console.log(a1.toString());
    console.log(a1.valueOf());
    console.log(a1.toLocaleString());
    console.log(a1);
                
    alert(a1.toString());
    alert(a1.valueOf());
    alert(a1.toLocaleString());
    alert(a1);

    使用console.log的输出结果:

     使用alert的输出结果(四个alert均是这样的结果):

    总结:对象数组,不重写

    toString()方法:调用各数据项的toString()方法,将各数据项变成字符串的形式,然后使用逗号连接作为结果返回。

    toLacolaeString()方法:调用各数据项的toLocaleString()方法,将各数据项变成字符串的形式,然后使用逗号连接作为结果返回。

    valueOf()方法:返回该数组。

    注意:alert()打印结果都一样,是因为alert()函数会将结果以字符串的形式打印出来。

    3.对象数组,重写                          

           var obj1 = {          
              id:
    1, toString: function(){ return "toString"; }, toLocaleString: function(){ return "toLocaleString"; }, valueOf: function(){ return "valueOf"; } }; var obj2 = { id: 2, toString: function(){ return "toString"; }, toLocaleString: function(){ return "toLocaleString"; }, valueOf: function(){ return "valueOf"; } }; var fun = function(){}; fun.id = 3; fun.toString = function(){ return "toString"; }; fun.toLocaleString = function(){ return "toLocaleString"; }; fun.valueOf = function(){ return "valueOf"; }; var a1 = [obj1,obj2,fun]; console.log(a1.toString()); console.log(a1.valueOf()); console.log(a1.toLocaleString()); console.log(a1);

            alert(a1.toString());
            alert(a1.valueOf());
            alert(a1.toLocaleString());
            alert(a1);

     使用console.log输出结果:

     使用alert输出结果:

    String,String,String,String

    String,String,String,String

    toLocaleString,toLocaleString,toLocaleString

    String,String,String,String

    总结:对象数组,重写

    toString()方法:调用各数据项重写后的toString()方法,将各数据项变成字符串的形式,然后使用逗号连接作为结果返回。

    toLacolaeString()方法:调用各数据项重写后的toLocaleString()方法,将各数据项变成字符串的形式,然后使用逗号连接作为结果返回。

    valueOf()方法:返回该数组。

    注意:使用alert打印数组会先调用各数据项的toString方法(在这里是重写后的方法),然后再连接起来打印输出。

    二、join()方法

      join方法和toString()方法类似,只不过该方法可以传入一个字符,该字符将取代toString方法中的 逗号分隔符。不传入参数和传入“,”时,输出结果和toString()方法一样。

    //创建一个Date类型的对象
    var a1 = new Date();
    //创建一个Function类型的对象
    var a2 = function(){};
    //创建一个Obeject类型的对象
    var a3 = {};
    //创建一个数组
    var b = [1,"li",null,undefined,true,a1,a2,a3];
    console.log(b.join());     //不传入参数
    console.log(b.join(","));     //传入一个逗号
    console.log(b.join("||"));      //传入一个其他分隔符

    输出结果:

     注意:无论是join()方法还是toString()方法,数据项如果是null或者undefined,则会返回一个空串""。

     栈方法和队列方法:

      1.栈方法。

      可以将数组想象成一个数据栈,栈遵循LIFO(Last-In-First-Out,后进先出)的规则。

      push()方法:

    //数组名.push(数据1,数据2,数据3,...,数据n);  该方法返回值为插入数据后的length值
    
    var a = ["li","ma","zhang"];
    var b = a.pop("liu","zhao");
    console.log(a);                //["li","ma","zhang","liu","zhao"]
    console.log(a.length); //5
    console.log(b); //5

      pop()方法:

    //数组名.pop();                 该方法返回被弹出的数据
    
    var a = ["li","ma","zhang"];
    var str = a.pop();
    console.log(a);            //["li","ma"]
    console.log(a.length);     //2
    console.log(str);          //"zhang"

      2.队列方法

      也可以将数组想象成一个队列,队列遵循FIFO(First-In-First-Out,先进先出)的规则。

      shift()方法:

    //数组名.shift();         用法和pop()类似,只不过它是在数组最前方剔除数据
    
    var a = ["li","ma","zhang"];
    var str = a.shift();
    console.log(a);            //["ma","zhang"]
    console.log(a.length);     //2
    console.log(str);          //"li"

      unshift()方法:

    //数组名.unshift(数据1,数据2,数据3,...,数据n);    用法与push类似,只不过它是在数组最前方添加数据
    
    var a = ["li","ma","zhang"];
    var b = a.unshift("liu","zhao");
    console.log(a);             //["liu","zhao","li",ma","zhang"]
    console.log(a.length);      //5
    console.log(b);             //5

    重排序方法:

      reverse()方法:

      reverse()方法会反转数组项。调用该方法后,会返回反转之后的数组的引用。

    var a = [1,2,3];
    var b = a.reverse();      //数组a调用reverse()方法,并将反转后的数组引用传给变量b,直接使用a.reverse()也可以,这样a指向的数组内部数据将会被反转
    b.pop(); console.log(a); //[3,2] console.log(b); //[3,2] //剔除b的最后一个数据,发现a也改变了,可见a和b都是指向反转之后的数组

      sort()方法:

      1.不传入参数

      按升序排列数组项,即最小的值位于最前面,最大的值位于最后面。但须要注意:sort()方法会先调用每个数据项的toString方法,然后再对每个转换之后的字符串进行比较。即使数据项是数字,也是对字符串进行比较。

    var a = [1,31,21,18,94,7,4];
    a.sort();
    console.log(a);           //1,18,21,31,4,7,94

      2.给sort()方法传入一个比较函数做为参数

    可以对数值型数组进行排序:

    var a = [1,31,21,18,94,7,4];
    a.sort(function(num1,num2){              //升序排列
       if(num1<num2){
           return -1;             
       }else if(num1>num2){
         return 1;
       }else{
         return 0; 
      }    
    });
    console.log(a);          // 1,4,7,18,21,31,94

    比较函数的原理是:将数据项按照冒泡原理的顺序传入比较函数之后,若比较函数返回值为负数,那么就将sum1对应的数据项将放在前面,sum2对应的数据项放在后面,如果返回值为正数,则sum1对应的数据项在后面,sum2对应的数据项在前面,如果返回值为0,则顺序保持不变。

    也可以指定某个属性,对对象数组进行排序:

    //创建三个对象            
    var obj1 = {            
        id:1,
        name:"孙悟空"
    };
                
    var obj2 = {
        id:2,
        name:"猪八戒"
    };
                
    var obj3 = {
        id:3,
        name:"沙和尚"
    };
    //放进数组中            
    var a = [obj2,obj1,obj3];
    //创建一个返回比较函数的函数,其参数将被比较函数使用,比较函数也称为闭包
    var compare = function(property){
        return function(obj1,obj2){
            var idValue1 = obj1[property];
            var idVulue2 = obj2[property];
            return idValue1 - idVulue2;
        }
    };
    //注意下面compare要加()并传入参数,不然不会返回比较函数
    a.sort(compare("id"));
    console.log(a);

    输出结果(按id值升序排列):

    下篇将总结数组的操作方法、迭代方法等等。

    写在最后:诚心希望各位大佬能指点一二,这篇总结写的我怀疑人生了。花了将近四个小时,你们都是这样吗,还是说我总结的方法不对。另外,有错误请一定要帮我指出来,谢谢你

  • 相关阅读:
    【More Effective C++】Item 4
    【More Effective C++】Item 3
    【More Effective C++】Item 2
    【More Effective C++】Item 1
    ”win7笔记本共享无线网络,手机连接成功却无法上网“的解决之道【亲身经历】
    【RFID防碰撞协议/算法】动态二进制搜索算法
    【RFID防碰撞协议/算法】二进制搜索防碰撞算法
    总结ASP标准控件
    总结ASP控件属性
    ..........
  • 原文地址:https://www.cnblogs.com/lilisblog/p/12418746.html
Copyright © 2020-2023  润新知