美文网首页
你不知道的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