美文网首页
你不知道的JavaScript笔记之 this

你不知道的JavaScript笔记之 this

作者: 不大不小的石头 | 来源:发表于2017-05-01 15:57 被阅读0次

    关于this的误解

    • 指向自身
    • 它的作用域

    指向自身

    如果要从函数对象内部引用它自身,那只用this是不够的。一般来说我们需要通过一个指向函数对象的词法标识符(变量)来引用它。

       //不懂this的指向
        function foo(num) {
            console.log('foo:' + num);
            // console.log(this); //此时this指向window
    
            this.count++;
            // foo.count++; //直接用函数的标识符来代替this引用函数对象,可解决。但是回避了this指向的问题
        } 
    
        foo.count = 0;
    
        
        for (var i = 0; i < 10; i++) {
            if(i > 5) {
                foo(i);
                //但是使用call()来强制this指向函数本身,也可解决。 我们在面对this的问题 
                // foo.call(foo, i); 
            }
        }
    
    
        console.log(foo.count); //结果为0,而不是4
    
    

    它的作用域

    需要明确的是,this在任何情况下都不指向函数的词法作用域。每当自己想要把this和词法作用域的查找混合使用的时候,就应该提醒自己,这是无法实现的。

            //完美尴尬案例
            function foo() {
                var a = 3;
                console.log(this.bar());
            }
    
            function bar() {
                return this.a
            }
    
            foo(); // 出错
    

    this到底是什么

    它不是什么

    学习this的第一步就是明白它既不指向函数自身,也不指向函数的词法作用域

    this的绑定是在运行时进行绑定的,而不是在编写时绑定,和函数声明位置没有任何关系,只取决于函数的调用方式,即调用位置。

    调用位置

    调用位置,就是函数被调用的位置。而有些编程模式可能会隐藏真正的调用位置。

    最重要的是分析调用栈,调用位置就在当前正在执行函数的前一个调用中

            function baz() {
                console.log('baz');
                bar();
            }
            function bar() {
                console.log('bar');
                foo();
            }
            function foo() {
                console.log('foo'); // 当前调用栈是baz ->bar -> foo
    
            }
    
            baz();
    
    
    

    this的绑定规则

    默认绑定

    最常用的函数调用:独立函数调用。即函数是直接使用不带任何修饰的函数引用进行调用的。

            // 默认绑定
            function foo() {
                console.log(this.a);
            }
    
            var a = 2;
    
            foo(); // foo是直接使用不带任何修饰的函数引用所调用的
    
            var width = 600;
            var shape = {
                width : 100
            }
    
            var showWidth = function() {
                console.log(this.width);
            }
    
            shape.getWidth = showWidth;
    
            shape.getWidth(); // 前面有修饰,结果为100
    
            var myWidth = shape.getWidth;
            myWidth(); // 前面没有修饰,结果为600
    

    隐式绑定

    函数引用上下文对象时,就会通过隐式绑定规则把函数调用中的this绑定到这个上下文对象上。可以观察调用位置是否被某个对象拥有或者包含。

            // 隐式绑定
            function foo() {
                console.log(this.a);
            }
    
            var obj = {
                a : 2, //this被隐式绑定在这个对象里
                foo : foo
            }
    
    
            obj.foo(); 
    

    隐式丢失问题

    最常见的就是隐式绑定的函数会丢失绑定对象,回到默认绑定。

            // 隐式绑定丢失情况
            function foo() {
                console.log(this.a);
            }
    
            var obj = {
                a : 2,
                foo : foo
            }
    
            var bar = obj.foo; //这里创建了一个函数的别名
            // 虽然bar是obj.foo的引用,但是它引用的其实是foo本身
            var a = '全局下的a';
    
            bar(); // 结果是this又跑到全局去下了
    

    当函数被当作参数传递时,就会发生隐性赋值,从而产生会上面一样的结果。

            // 当函数被当作参数传递时,会发生隐性赋值的情况
            function foo() {
                console.log(this.a);
            }
    
            function doFoo(fn) {
                fn(); //调用位置在这,其实fn引用的就是foo
            }
    
            var a = "a在全局下";
    
            var obj = {
                a : "a在对象里",
                foo : foo
            };
    
            doFoo(obj.foo);
    

    硬绑定

    我们可以在某个对象上,强制调用函数。

    • 典型使用场景,创建一个包裹函数,负责接收参数并返回值。
            function foo(something) {
                console.log(this.a , something);
                return this.a + something;
            }
    
            var obj = {
                a : 2
            };
    
            var bar = function() {
                return foo.apply(obj, arguments); //显式的硬绑定,包裹foo
            };
    
            var b = bar(3);
            console.log(b);
    
    
    • 创建一个可以重复使用的辅助函数
            function foo(something) {
                console.log(this.a , something);
                return this.a + something;
            }
    
    
            // 简单的辅助绑定函数
            function bind(fn, obj) {
                return function() {
                    return fn.apply(obj, arguments);
                };
            }
    
            var obj = {
                a : 2
            };
    
            var bar = bind(foo, obj);
    
            var b = bar(3);
            console.log(b);
    
    
    • 其实我们有内置方法bind
            //ES5给硬绑定提供了一个内置方法Function.prototype.bind
            function foo(something) {
                console.log(this.a , something);
                return this.a + something;
            }
    
    
            var obj = {
                a : 2
            };
    
    
            var bar = foo.bind(obj);
    
    
            var b = bar(3);
            console.log(b);
    

    new绑定

    最后一个绑定规则。

            function foo(a) {
                this.a = a;
                console.log(this); // this指向foo函数
            }
    
            var bar = new foo(2); // new会创建一个新对象并绑定到函数调用的this上
            console.log(bar.a)
    

    绑定规则优先级

    new 绑定 => 显示绑定 => 隐式绑定 => 默认绑定

    [TOC]

    相关文章

      网友评论

          本文标题:你不知道的JavaScript笔记之 this

          本文链接:https://www.haomeiwen.com/subject/wdtawttx.html