Javascript 中 作用域、闭包与 this 指针

内容预览

             1. js 中的作用域

             2.闭包的理解和运用

             3.this 的理解和运用


【一】 js中的作用域 

           一段简单的代码来说明

       var outFunc = function() {
            var out_name = "outFunc";
            var out_num = 130;

            var inFunc = function() {
                var in_name = "inFunc";
                var in_num = 3;

                alert(out_name);
                alert(out_num);
                alert(in_name);
                alert(in_num);
            };

            inFunc();
            // 调用 inFunc 函数执行的结果是,弹出:outFunc、130、inFunc、3
            
            alert(out_name);
            alert(out_num);
            alert(in_name);
            alert(in_num);
        };
        outFunc();
        // 调用 inFunc 函数执行的结果是,弹出:outFunc、130、undefined、undefined
            内部函数可以访问外部函数的变量,外部不能访问内部函数的变量。上面的例子中内部函数inFunc可以访问变量 out_name和out_num,而外部函数 outFunc 不可以访问 inFunc 中的变量 in_name和in_num,因此会抛出没有定义变量的异常。

             很重要的一点,如果忘记 var,那么变量或者函数就会被声明为全局变量或者全局函数了。下面例子的写法,in_name 变量和 test 函数 是全局的变量和全局函数,不属内部作用域了。

       var outFunc = function() {
            var out_name = "outFunc";
            var out_num = 130;
            var inFunc = function() {
                 in_name = "inFunc";
                 var in_num = 3;
            };
            test function(){
                 alert('Test');
            }
        };
【二】 闭包的理解和运用 

            闭包这个概念,在函数式编程里很常见,简单的说常见的两大用处,一是使外部函数可以突破作用域从而访问定义在内部函数中的变量,二是让变量的值始终保存在内存中。当在一个函数中定义另个函数就会产生闭包。如果要深入理解闭包,可以查看这篇博客http://coolshell.cn/articles/6731.html

           

       //javascript 中特殊形式的函数,自调用函数
        var a = function() {
            function setUp() {
                //定义方法时可以做首次的初始化,这个只会调用一次
                alert('初始化');
            }
            setUp();
            function doSomething() {
                alert('要执行的操作')
            }
            return doSomething; //这里返回的不是一个函数,而是一个引用
        }(); //加()进行首次调用初始化,既首次执行setUp函数(自调用函数)
        // a(); //弹出 初始化
        // a(); //弹出  要执行的操作

      //闭包的应用一: 通过闭包突破全局作用域链
        var n;
        function f() {
            var a = 'king'; //这是局部变量
            n = function() { //外部可通过 n 函数访问局部变量a   
                return a;
            };
            //这个test函数 不加var 默认为全局的函数,加var 则为局部的
            test = function() {
                alert('默认全局函数');
            }
        }

        //闭包的应用二: 定义私有变量的取值和赋值
        var setValue, getValue;
        (function() {
            var n = 0; //私有变量
            getValue = function() {
                return n;
            }
            setValue = function(x) {
                n = x;
            }
        })(); //这样写为自调用函数

        //闭包的应用三:迭代器        
        function test(x) {
            var i = 0;
            return function() {
                return x[i++];
            }
        }
        var next = test(['a', 'b', 'c', 'd']);
        // alert(next());//弹出a
        // alert(next());//弹出b
        // alert(next());//弹出c
        // alert(next());//弹出d

       //理解不到位常犯的错误,这种错误通常不容易被发现
        function f() {
            var a = [];
            var i;
            for (var i = 0; i < 3; i++) {
                a[i] = function() {
                    return i; //这里只是对 i 这个指针进行了引用
                };
            }
            return a;
        }
        var test = f();
        // alert(test[0]());//弹出 3
        // alert(test[1]());//弹出 3
        // alert(test[2]());//弹出 3
        //出现这个问题原因在于 i 是一个指针,也就是一个地址,闭包只是引用了这个指针。当for 循环遍历结束 指针 i 指向的值为 3
        // 可采用自调用函数的方式来避免上述的问题,如下所示
        function f() {
            var a = [];
            var i;
            for (var i = 0; i < 3; i++) {
                a[i] = (function(x) {
                    return function() {
                        return x;
                    }
                })(i);
            }
            return a;
        }
        var test = f();
        alert(test[0]()); //弹出 0
        alert(test[1]()); //弹出 1
        alert(test[2]()); //弹出 2 


【三】this 的理解和运用

          在函数执行时,this 总是指向调用该函数的对象。要判断 this 的指向,其实就是判断 this 所在的函数属于谁。

          在《javaScript语言精粹》这本书中,把 this 出现的场景分为四类,简单的说就是:

        1) 有对象就指向调用对象            

       var myObject = {value:111};
        myObject.getValue = function(){
            console.log(this.value);//输出100
            console.log(this);//输出 { value: 100, getValue: [Function] }
        }
        myObject.getValue();
       // getValue() 属于对象 myObject,并由 myOjbect 进行 . 调用,因此 this 指向对象 myObject。

          2) 没调用对象就指向全局对象           

        var myObject = { value: 100 };
        myObject.getValue = function() {
            var foo = function() {
                console.log(this.value) // 输出 undefined
                console.log(this); // 输出全局对象 global  
                 //foo 函数虽然定义在 getValue 的函数体内,但实际上它既不属于 getValue 也不属于 myObject。
                // foo 并没有被绑定在任何对象上,所以当调用时,它的 this 指针指向了全局对象 global。
            };
            foo();
            return this.value; //这个this 在 getValue中,从而指向 myObject。
        };
        console.log(myObject.getValue()); // 输出 100 

          3) 用new构造就指向新对象             

        //js 中,我们通过 new 关键词来调用构造函数,此时 this 会绑定在该新对象上。
        var SomeClass = function() {
            this.value = 100;
        }
        var myCreate = new SomeClass();
        console.log(myCreate.value); // 输出100

          4) 通过 apply 或 call 或 bind 来改变 this 的所指

        // apply 和 call 调用以及 bind 绑定: 指向绑定的对象
        // apply() 方法接受两个参数第一个是函数运行的作用域, 另外一个是一个参数数组(arguments)。
        // call() 方法第一个参数的意义与 apply() 方法相同, 只是其他的参数需要一个个列举出来。
        // 简单来说, call 的方式更接近我们平时调用函数, 而 apply 需要我们传递 Array 形式的数组给它。 它们是可以互相转换的。
        var myObject = { value: 100 };
        var foo = function() {
            console.log(this);
        };
        foo(); // 全局变量 global
        foo.apply(myObject); // { value: 100 }
        foo.call(myObject); // { value: 100 }
        var newFoo = foo.bind(myObject);
        newFoo(); // { value: 100 }</span>






























          

           





















           

  • 8
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值