读书笔记《你不知道的JavaScript上卷》1.3函数作用域和块作用域

版权声明:本文为博主逝水流光原创,可以转载,请注明出处。 https://blog.csdn.net/javao_0/article/details/57076533

函数作用域和块作用域

函数作用域:属于这个函数的全部变量都可以在整个函数的范围内访问(事实上在嵌套的作用域中也可以访问)。


3.1 函数中的作用域

函数可以形成作用域,这个大家都知道的,如下代码:

function foo() {
    var a = 2;
    console.log("函数foo中的a:" + a);//打印 函数foo中的a:2
}
foo();
console.log("函数foo外的a:" + a);//报错 ReferenceError

函数foo里面形成了一个作用域所以它内部定义的变量a,只有它自己能够访问,外部是无法访问的没有找到该变量故报了一个ReferenceError引用错误。

3.2 隐藏内部实现

由于JS中函数就是一个作用域,同时JS中又有作用域链的存在,因此定义全局的变量或函数是很危险的,当项目庞大的时候过多的全局变量(或全局函数)很可能会发生覆盖,从而导致项目难以维护,所以JS可以在函数中定义另一个函数当某个函数只会在这个函数的内部调用时,通常写在这个函数的内部,这样对于全局来说隐藏了这个函数。如下例中的doSomethingElse方法,全局就无法方法

function doSomething() {
    function doSomethingElse() {
        //一些代码
    }
    doSomethingElse();//函数内部可以调用 但外部不能
}
 doSomethingElse();//报错 这里不能调用

3.3 避免冲突

通常避免冲突有两种方法:

  • 全局命名空间
  • 模块管理

这里我们重点说一下全局命名空间,它在第三方库中运用的比较多,具体做法如下:

var $ = {//全局命名空间为:$
    add:function(){},
    remove:function(){}
};
$.add();//通过全局命名空间调用里面的方法

3.4 立即执行函数

立即执行函数(Immediately Invoked Function Expression),也就是IIFE,表示会立即执行的函数,它在平时写代码的时候用的还是比较多的。

var a = 2;
(function IIFE(){
    var a = 3;
    console.log( a ); // 3
})();
console.log( a ); // 2

如上,立即执行函数可以有效地避免变量地覆盖,其实就是利用作用域来隐藏内部实现。为什么它会立即执行呢,原因在上面代码的第5行,最后的括号表示执行该函数,就跟调用函数一样,当然如果有参数也可以传递参数。上面的函数名IIFE是可以去掉的,在JS中如果函数是声明,那么函数名必须要写以保证之后调用可以用“函数名()”这种形式来调用;如果只是为了返回它的引用(也就是首地址,就跟上面一样,或者当参数传递的时候)。那么名称可以写也可以不写,并且这个名称并不会污染全局,因为个函数并不是声明,所以也就不可以用“函数名()”来调用,不过写上函数名在调试的时候会更直观
立即执行函数还有另外一种形式,如下:

(function(){ .. }())

3.5 立即执行函数的用途

3.5.1 避免undefined被覆盖

undefined = true; // 如果有人if(a == undefined){}时肯定会奔溃的
(function IIFE( undefined ){
    var a;
    if (a === undefined) {
        console.log( "这里的undefined是对的!" );
    }
})();

由于最后一行调用的时候什么也没有传,所以第2行undefined的值是正真的没有声明,所以undefined外面被覆盖也就不起作用了。

3.5.1 倒置代码

可以利用立即执行函数使得传递的参数有我们自己决定,函数的内容由别人来决定,如下代码:

var a = 2;
(function IIFE( def ){
    def( window );
})(function def( global ){
    var a = 3;
    console.log( a ); // 3
    console.log( global.a ); // 2
});

我们定义的IIFE函数传递的参数是一个函数,它调用的时候会传递一个window对象,而当第四行正真传递了一个def的函数进去的时候,其调用是在第三行,那么参数global的值就是window。

3.6 块作用域

块作用域:通常,编程语言用花括号(也就是这个{})括起来所形成的作用域就是块作用域。

通常情况下JS用花括号括起来是没有块作用域的!!!,如下:

for (var i=0; i<10; i++) {
}
console.log( i );//打印 10

for循环10次什么都不做,在它后面打印i也可以得到值,因为上面的花括号并不能形成作用域,这个其他语言如Java有很大的不同。
上面说到的是通常情况下,那么特殊情况有哪些呢?

3.6.1 with

上一节说过with从对象中会创建出自己的作用域。

3.6.2 try/catch

JS中也有异常处理就是try/catch,catch块会形成块作用域,但是try并不会形成块作用域,如下:

try {
    undefined(); // 这行代码会有异常
} catch (err) {
    console.log( err ); // 打印err的值
}
console.log( err ); // ReferenceError: `err` not found      

3.6.2 let/const

let和const是ES6引入的,他们所在的块是拥有作用域的,其中let是变量类似于var,但是所在块有该变量的作用域;const与let类似,但是表示常量,值是不能修改的,修改就报错。这里给的例子是上面循环的例子,如下,这里的第三行代码在花括号外面是访问不到变量i的。

for (let i=0; i<10; i++) {
}
console.log( i ); // ReferenceError     

猜你喜欢

转载自blog.csdn.net/javao_0/article/details/57076533