Javascript-函数(上)

重点:函数和方法、作用域和作用域链、闭包

一、函数和方法
1.函数

2.方法:保存在一个对象的属性里的Javascript函数。如果函数挂载在一个对象上,作为对象的一个属性,就称它为对象的方法。

3.函数调用和方法调用的区别:调用上下文。


二、作用域
1.在函数体内,局部变量的优先级高于同名的全局变量。即,如果在函数内声明的一个局部变量或者函数参数中带有的变量和全局变量重名,那么全局变量就被局部变量所遮盖。

var scope="global";//全局变量
function checkScope(){
    var scope="local";//局部变量
    return scope;
}
checkScope();//=>"local"

2.函数作用域:变量在声明它们的函数体以及这个函数体嵌套的任意函数体内都是有定义的。

3.声明提前:函数里声明的所有变量(但不涉及赋值)都被“提前”至函数体的顶部。

var scope="global";
function f(){
    console.log(scope);//=>"undefined"
    var scope='local';//变量在这里赋值,但因为变量声明提前,声明被提前至第一行并覆盖全局变量,所以第一行的输出相当于没有定义的赋值,即"var scope;"
    console.log(scope);//=>"local"
}

三、作用域链
1.含义:每一段js代码都有一个与之关联的作用域链。这个作用域链是一个对象列表或者链表,这组对象定义了这段代码“作用域中”的变量。

2.变量解析:当js需要查找变量x的值的时候,它会从作用域链中的第一个对象开始查找,如果这个对象有一个名为x的属性,则会直接使用这个属性的值,如果第一个对象中不存在名为x的属性,js会继续查找作用域链上的下一个对象。以此类推。如果作用域链上没有任何一个对象含有属性x,那么就认为这段代码的作用域链上不存在x,并最终抛出一个引用错误(ReferenceError)异常。

3.不同情况下的作用域链:

  • 在js的最顶层代码中:一个全局对象;
  • 在不包含嵌套的函数体内:定义函数参数和局部变量的对象、全局对象;
  • 在一个嵌套的函数体内:至少有三个对象。

4.对象链的创建规则
当定义一个函数时,它实际上保存一个作用域链。当调用这个函数时,它创建一个新的对象来存储它的局部变量,并将这个对象添加至保存的那个作用域链上,同时创建一个新的更长的表示函数调用作用域的“链”。


四、闭包
1.含义:函数对象可以通过作用域链相互关联起来,函数体内部的变量都可以保存在函数作用域内,这种特性在计算机科学文献中称为“闭包”。

2.特点

  • 可以捕捉到局部变量,并一直保存下来。
  • 在同一个作用域链中定义两个闭包,这两个闭包共享同样的私有变量或变量。

3.原理:每次调用函数时,都会为之创建一个新的对象用来保存局部变量,把这个对象添加至作用域链中。当函数返回时,就从作用域链中将这个绑定变量的对象删除。

  • 如果不存在嵌套的函数,也没有其他引用指向这个绑定对象,它就会被当做垃圾回收掉。
  • 如果定义了嵌套的函数,每个嵌套的函数都各自对应一个作用域链,并且这个作用域链指向一个变量绑定对象。但如果这些嵌套的函数对象在外部函数中保存下来,那么它们也会和所指向的变量绑定对象一样当做垃圾回收。但是如果这个函数定义了嵌套的函数,并将它作为返回值返回或者存储在某处的属性里,这时就会有一个外部引用指向这个嵌套的函数。它就不会被当做垃圾回收,并且它所指向的变量绑定对象也不会被当做垃圾回收。

4.常见问题:试图将循环代码移入定义这个闭包的函数之内。

function constfuncs(){
    var funcs=[];
    for (var i = 0; i <10; i++) 
        funcs[i]=function(){return i;}
    return funcs;
}
var funcs=constfuncs();
console.log(funcs[5]());//=>10

解析:上面这段代码创建了10个闭包,并将它们存储到一个数组中。这些闭包都是在同一个函数调用中定义的,因此它们可以共享变量 i 。当constfuncs()返回时,变量 i 的值是10。所有闭包都共享这一个值。

——阅读《Javascript权威指南》第三章、第八章

猜你喜欢

转载自blog.csdn.net/sinat_38783046/article/details/82356149