你不知道的JavaScript筆記之 this

關(guān)于this的誤解

  • 指向自身
  • 它的作用域

指向自身

如果要從函數(shù)對象內(nèi)部引用它自身,那只用this是不夠的。一般來說我們需要通過一個指向函數(shù)對象的詞法標識符(變量)來引用它。

   //不懂this的指向
    function foo(num) {
        console.log('foo:' + num);
        // console.log(this); //此時this指向window

        this.count++;
        // foo.count++; //直接用函數(shù)的標識符來代替this引用函數(shù)對象,可解決。但是回避了this指向的問題
    } 

    foo.count = 0;

    
    for (var i = 0; i < 10; i++) {
        if(i > 5) {
            foo(i);
            //但是使用call()來強制this指向函數(shù)本身,也可解決。 我們在面對this的問題 
            // foo.call(foo, i); 
        }
    }


    console.log(foo.count); //結(jié)果為0,而不是4

它的作用域

需要明確的是,this在任何情況下都不指向函數(shù)的詞法作用域。每當自己想要把this和詞法作用域的查找混合使用的時候,就應該提醒自己,這是無法實現(xiàn)的。

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

        function bar() {
            return this.a
        }

        foo(); // 出錯

this到底是什么

它不是什么

學習this的第一步就是明白它既不指向函數(shù)自身,也不指向函數(shù)的詞法作用域。

this的綁定是在運行時進行綁定的,而不是在編寫時綁定,和函數(shù)聲明位置沒有任何關(guān)系,只取決于函數(shù)的調(diào)用方式,即調(diào)用位置。

調(diào)用位置

調(diào)用位置,就是函數(shù)被調(diào)用的位置。而有些編程模式可能會隱藏真正的調(diào)用位置。

最重要的是分析調(diào)用棧,調(diào)用位置就在當前正在執(zhí)行函數(shù)的前一個調(diào)用中。

        function baz() {
            console.log('baz');
            bar();
        }
        function bar() {
            console.log('bar');
            foo();
        }
        function foo() {
            console.log('foo'); // 當前調(diào)用棧是baz ->bar -> foo

        }

        baz();


this的綁定規(guī)則

默認綁定

最常用的函數(shù)調(diào)用:獨立函數(shù)調(diào)用。即函數(shù)是直接使用不帶任何修飾的函數(shù)引用進行調(diào)用的。

        // 默認綁定
        function foo() {
            console.log(this.a);
        }

        var a = 2;

        foo(); // foo是直接使用不帶任何修飾的函數(shù)引用所調(diào)用的
        var width = 600;
        var shape = {
            width : 100
        }

        var showWidth = function() {
            console.log(this.width);
        }

        shape.getWidth = showWidth;

        shape.getWidth(); // 前面有修飾,結(jié)果為100

        var myWidth = shape.getWidth;
        myWidth(); // 前面沒有修飾,結(jié)果為600

隱式綁定

函數(shù)引用上下文對象時,就會通過隱式綁定規(guī)則把函數(shù)調(diào)用中的this綁定到這個上下文對象上??梢杂^察調(diào)用位置是否被某個對象擁有或者包含。

        // 隱式綁定
        function foo() {
            console.log(this.a);
        }

        var obj = {
            a : 2, //this被隱式綁定在這個對象里
            foo : foo
        }


        obj.foo(); 

隱式丟失問題

最常見的就是隱式綁定的函數(shù)會丟失綁定對象,回到默認綁定。

        // 隱式綁定丟失情況
        function foo() {
            console.log(this.a);
        }

        var obj = {
            a : 2,
            foo : foo
        }

        var bar = obj.foo; //這里創(chuàng)建了一個函數(shù)的別名
        // 雖然bar是obj.foo的引用,但是它引用的其實是foo本身
        var a = '全局下的a';

        bar(); // 結(jié)果是this又跑到全局去下了

當函數(shù)被當作參數(shù)傳遞時,就會發(fā)生隱性賦值,從而產(chǎn)生會上面一樣的結(jié)果。

        // 當函數(shù)被當作參數(shù)傳遞時,會發(fā)生隱性賦值的情況
        function foo() {
            console.log(this.a);
        }

        function doFoo(fn) {
            fn(); //調(diào)用位置在這,其實fn引用的就是foo
        }

        var a = "a在全局下";

        var obj = {
            a : "a在對象里",
            foo : foo
        };

        doFoo(obj.foo);

硬綁定

我們可以在某個對象上,強制調(diào)用函數(shù)。

  • 典型使用場景,創(chuàng)建一個包裹函數(shù),負責接收參數(shù)并返回值。
        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);

  • 創(chuàng)建一個可以重復使用的輔助函數(shù)
        function foo(something) {
            console.log(this.a , something);
            return this.a + something;
        }


        // 簡單的輔助綁定函數(shù)
        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);

  • 其實我們有內(nèi)置方法bind
        //ES5給硬綁定提供了一個內(nèi)置方法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綁定

最后一個綁定規(guī)則。

        function foo(a) {
            this.a = a;
            console.log(this); // this指向foo函數(shù)
        }

        var bar = new foo(2); // new會創(chuàng)建一個新對象并綁定到函數(shù)調(diào)用的this上
        console.log(bar.a)

綁定規(guī)則優(yōu)先級

new 綁定 => 顯示綁定 => 隱式綁定 => 默認綁定

[TOC]

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容