重温《js权威指南》 第7,8章

第七章 数组

        数组是值的有序集合。js数组是无类型的,数组元素可以是任意类型,同一个数组中不同元素也可能有不同的类型。数组可以动态增长或缩减,创建时无须生命那个一个固定的大小并且数组大小变化时也无须重新分配空间。

        js数组可能是稀疏的:数组的索引不一定连续。针对稀疏数组,数组的length属性可能不管用。

        数组索引实际上和碰巧是整数的属性名差不多,但是有些特殊的优化,比访问常规的对象属性要快很多。

        7.1 创建数组

        数组直接量创建。

var empty=[];

var primes=[1,2,3,4];

var misc=[1.1,true,'a'];

var b=[[1,{x:1,y:2}],[2,{x:3,y:4}]];

var count=[1,,3]//长度为三

var specCount=[,,]//因为数组允许有可选的逗号做结尾,所以长度为2

         调用构造函数Array()创建数组

var a=new Array();

var b=new Array(10);

var c=new Array(1,2,3);

         7.2 数组元素的读和写

                  使用 [] 读写

var a=["world"];

var value=a[0];

a[1]=3.14;

i=2;

a[i]=3;

a[i+1]="hello";

a[a[i]]=a[0];

                 数组是对象的特殊形式。使用方括号访问数组元素就像用方括号访问对象的属性一样。js将指定的数字索引值转换成字符串——索引值1变成"1"——然后将其作为属性名来使用

                 清晰地区分数组的索引和对象的属性名是非常有用的。所有的索引都是属性名,但只有在0~232-2之间的整数属性名才是索引。所有的数组都是对象,可以为其创建任意名字的属性。但如果使用的属性是数组的索引,则数组会特殊的维护它的属性length

                 js数组没有“越界的概念”,访问没有的对象时,返回undefined

        7.3 稀疏数组

                 跟正常的数组有一些区别,但更像是有一些undefined值的数组

var a=new Array(5);//length=5

var b=[];//长度为0

b[1000];//长度为1001

var  a1=[,,,];

var  a2=new Arrays(3);

alert(0 in a1)//true;

alert(0 in a2)//false;

        7.4 数组长度

                 数组的length是数组与js普通对象的区别。数组的length一定大于等于数组的长度(存在稀疏数组)

当插入数据时,length+1;

当length比数组的长度小时,数组会删除多于length索引的数组值

var a=[1,2,3,4,5,];

a.length=3;//a[1,2,3]

alert(a[4]);//undefined

a.length=5;

alert(a[4]);//undefined

        7.5 数组元素的添加和删除

var a=[]; //空数组

a[0]='0';//添加一个元素

a.push("zero");//在末尾添加元素

a.push("two","three");//在末尾添加多个元素

//=============删除分界线==================

a=[1,2,3];

delete a[1];

1 in a;//false

a.length//3   delete操作不会修改length

        7.6 数组遍历

                 使用for循环

                 使用for/in循环处理稀疏数组(不推荐,因会遍历Array.prototype所有的属性)

                 ECMAScript 5定义了一些遍历数组元素的新方法,如forEach()

var data=[1,2,3,4,5];

var sumOfSquares=0;

data.forEach(function(x){

             sumOfSquares+=x*x;//平方相加

})

sumOfSquares;//55

        7.7 多维数组

              js不支持真正的数组,但可以用数组的数组来模拟。

        7.8 数组的方法(ECMAScript 3)

join();//默认调用valueOf 然后‘,’拼接

reverse();//数组反转

sort();//默认按照字母表排序,'1'<'a',undefined排到尾部。可以传入比较函数

concat();//连接数组

slice(a,b);//返回的数组包含[a,b)范围的数组,并且a默认为0

splice();//插入/删除元素的通用方法

               var a=[1,2,3,4,5,6,7,8];

               a.splice(4);//返回[5,6,7,8]  a是[1,2,3,4]

               a.splice(1,2);//返回[2,3],a是[1,4]

               a.splice(1,1);//返回[4],a是[1]

          

                var b=[1,2,3,4,5];

                b.splice(2,0,'a','b');//返回[],b是[1,2,'a','b',3,4,5]

                b.splice(2,2,[1,2],3);//返回['a','b'],b是[1,2,[1,2],3,3,4,5]

push()//末尾添加新元素,length+1

pop()//返回末尾元素,length-1

unshift();//头部添加新元素,其他索引下移一位

shift();//头部删除新元素,其他索引上移一位

toString();//=join();

toLocaleString();

        7.9 数组中的方法(ECMAScript 5)

forEach();//遍历数组

map();//返回数组每个元素都执行完函数后的结果数组

filter();//返回调用数组的一个子集,若传入函数返回true,则该元素添加进要返回的子集中

every();//若数组每个元素都使传入函数返回true,则every()函数返回true

some();//若数组中有一个元素使传入函数返回true,则some()函数返回true

reduce();//使用指定的函数将数组元素进行组合,生成单个值

reduceRight();//

indexOf();//搜索整个数组中具有给定值的元素,返回找到的第一个元素的索引,没找到-1,从头搜索

lastIndexOf();//搜索整个数组中具有给定值的元素,返回找到的第一个元素的索引,没找到-1,从尾搜索

         7.10 数组类型

                 ECMAScript 5   Array.isArray()

                 ECMAScript 3  

var isArray=Function.isArray||function(o){

                 return typeof o==='object'&&object.prototype.toString().call(o)==='[object Array]';

}

          7.11 类数组对象

                 js数组有一些特性是其他对象所没有的:

                    当有新元素添加时,自动维护length属性

                    类属性为“Array”

                    设置length为较小值时,截断数组

                    继承自Array.prototype

           7.12 作为数组的字符串

                 字符串的行为类似于只读数组

第八章  函数

           函数的每次调用会拥有另一个值——本次调用的上下文——这就是this关键字的值。

           如果函数挂载在一个对象上,作为一个对象的属性,就称它为对象的方法。当通过这个对象来调用函数时,该对象就是此次调用的上下文。

           js的函数可以嵌套在其他函数的定义中,这样他们就可以访问它们被定义时所处的作用域中的任何变量,即“闭包”。

           8.1 函数定义

                 函数声明语句,表达式定义

                 嵌套函数

           8.2 函数调用

                 8.2.1 函数调用

                        即直接调用函数,通常不适用this。在ECMAScript3中,this是全局对象,ECMAScript5种,this是undefined。

可以使用此方法判断当前是否是严格模式

                 8.2.2 方法调用

                        通过对象调用。任何函数只要作为方法调用实际上都会传入一个隐式的实参——方法调用的母体,通过this来引用。this是一个关键字,不是变量,也不是属性名。

                         this没有作用域的限制,嵌套的函数不会从调用它的函数中继承this,其this值不是全局对象就是undefined。

var o={

       m:function(){

            var self=this;

            console.log(this===o);//true

            f();

            function f(){
                  console.log(this===o);//false

                  console.log(self===o);//true

            }

       }

}

                 方法链

                        当方法不需要返回值时,最好直接返回this。如果api中一直采用这种方法,是用api就可以进行链式编程

                 8.2.3 构造函数调用

                        使用new关键字,即调用构造函数。

                        构造函数调用和普通函数调用以及方法调用在实参处理、调用上下文和返回值方面都有不同

                         1.若构造函数没有形参,js允许构造函数省略实参列表和括号

var  o=new object();

var  j=new object;

                 8.2.4 间接调用

                        js函数即对象,函数对象也可以包含方法:apply()   call()

                        这两个方法都允许显式指定调用所需的this值,也就是说,任何函数可以作为任何对象的方法来调用,即使这个对象不是那个对象的方法。call方法使用它自有的实参列表作为函数的实参,apply()方法则要求以数组的形式传入参数。

        8.3  函数的实参和形参

                函数定义并未指定函数形参的类型,函数调用也未对传入的实参值做任何类型检查。实际上,js调用甚至不检查传入形参的个数。

使用“||”代替if语句的前提是a必须预先声明,否则a=a||[]会报引用错误

                 8.3.2 可变长的实参列表:实参对象

                       argument对象

                       callee和caller ECMAScript5 会直接报错;ECMAScript3中,callee代表正在执行的函数,caller非标准,代表正在执行的函数的函数

                       用处可以方便的在匿名函数中,调用匿名函数自身,实现递归

                       自定义函数属性

                       当函数需要一个“静态”变量来在调用时保持某个值不变,最方便的方式就是给函数定义属性,而不是定义全局变量

        8.5 作为命名空间的函数

               在js中,是无法声明只在一个代码块内可见的变量的。所以有时用函数做临时的命名空间,在这个命名空间内定义的变量都不会污染到全局命名空间。

(function(){}()); //直接定义的函数会立即调用

        8.6 闭包

               函数对象可以通过作用域链相互关联起来,函数体内部的变量都可以保存在函数作用域内。

               理解闭包,就是理解:“函数定义时的作用域链到函数执行时依然有效”

               从技术角度上说,所有的js函数都是闭包:它们都是对象,它们都关联到作用域链。定义大多数函数时的作用域链在调用函数时仍然有效,但这并不影响闭包。当调用函数时,闭包所指向的作用域链和定义函数时的作用域链不是同一个作用域链时,会很有意思。

              当一个函数嵌套了另外一个函数,外部函数将嵌套的函数对象作为返回值返回的时候往往会发生这种事。

var scope="global scope";             

function checkScope(){

    var  scope="local scope";

function f(){

      return scope;

}

return f();
}

checkScope();//"local scope"

===================================================

var scope="global scope";

function checkScope(){

var scope="local scope";

function f(){

return scope;

}

return f;
}

checkScope()();//"local scope"

                   js函数的执行用到了作用域链,这个作用域链是函数定义的时候创建的。嵌套的函数f()定义在这个作用域链里,其中的变量scope一定是局部变量,不管在何时何地执行函数f(),这种绑定在执行f()时依然有效:函数定义时的作用域链到函数执行时依然有效。

实现闭包

我们将作用域链描述为一个对象列表,不是绑定的栈。每次调用js函数的时候,都会为之创建一个新的对象用来保存局部变量,把这个对象添加至作用域链中。当函数返回的时候,就从作用域链中将这个绑定变量的对象删除。如果不存在嵌套的函数,也没有其他引用指向这个绑定对象,它就会被当做垃圾回收掉。如果定义了嵌套的函数,每个嵌套的函数都各自对应一个作用域链,并且这个作用域链指向一个变量绑定对象。如果这些嵌套的函数对象没有在外部函数中保存下来,那么它们也会和所指向的变量绑定对象一样当作垃圾回收。但是如果这个函数定义了嵌套的函数,并将它作为返回值返回或者储存在某处的属性里,这时会有一个外部引用指向这个嵌套的函数。它就不会被当作垃圾回收,并且它所指向的变量绑定对象也不会被当作垃圾回收

 

                  

///原uniqueInteger,容易被重置或污染counter

uniqueInteger.counter=0;

function uniqueInteger=(function(){

       return  uniqueInteger.counter++;

});

///使用闭包

var  uniqueInteger=(function(){

         var  counter=0;//函数返回后,counter 成为私有变量,只有函数内部可以访问

         return function(){ return  counter++;};

})

///闭包内多个嵌套函数共享变量

function counter(){

        var num=0;

        return {

              count:function(){return num++;},

               reset:function(){ num=0;}

         }

}

var b=counter();

var c=counter();

console.log('b:'+b.count());//0

console.log('c:'+c.count());//0    互不影响

console.log('b:'+b.count());

console.log('c reset:'+c.reset());

console.log('c:'+c.count());//0  reset  count  共享

        8.7 函数属性、方法和构造函数

              8.7.1 length属性

                 arguments.length 表示 传入函数的实参的个数

                 function.length 表示  定义函数时期望的实参个数

              8.7.2 prototype属性

                  每个函数都包含一个prototype属性,这个属性指向一个对象的引用,称作原型对象。

              8.7.3 call()和 apply()方法

                  call() 和 apply() 的第一个实参是要调用函数的母对象,它是调用上下文,在函数体内通过this来获得对它的引用

f.cal(o)    等价于     o.m=f;

                             o.m();

                             delete o.m;             

                   apply()  call()的区别是,第二个参数是直接传入参数,还是传入数组

              8.7.4 bind()

        8.8 函数式编程

               1.高阶函数

               2.不完全函数

               3.记忆            

原文地址:https://www.cnblogs.com/qiuyeyaozhuai/p/3479863.html