成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

萬水千山總是情,看看this行不行

lemanli / 1878人閱讀

摘要:回顧一下關(guān)鍵詞的過程創(chuàng)建一個新的對象使得的指向構(gòu)造函數(shù)的原型對象執(zhí)行構(gòu)造函數(shù)中的,改變的指向為如果結(jié)果是對象類型,則返回結(jié)果,否則返回指向的是調(diào)用時傳遞的第一個參數(shù)。

this = ?

在JS中,當(dāng)一個函數(shù)執(zhí)行時,都會創(chuàng)建一個執(zhí)行上下文用來確認(rèn)當(dāng)前函數(shù)的執(zhí)行環(huán)境,執(zhí)行上下文分為 全局執(zhí)行上下文函數(shù)執(zhí)行上下文。而 this 就是指向這個執(zhí)行上下文的對象。所以,this是在運行時決定的,可以簡單的理解為 誰調(diào)用,this指向誰。

分四種情況來看:

普通函數(shù)調(diào)用

對象方法調(diào)用

構(gòu)造函數(shù)調(diào)用

call、apply、bind

普通函數(shù)調(diào)用

當(dāng)函數(shù)作為函數(shù)獨立調(diào)用的時候,則是在全局環(huán)境中運行,this 則指向全局對象 window

一個簡單的例子

function demo() {
    console.log(this);  // window
}

demo();

demo 函數(shù)獨立調(diào)用,所以 this 指向全局對象 window

接著

function outer() {
    function inner() {
        console.log(this); // window
    }

    inner();
}

outer();

雖然在 outer 函數(shù)內(nèi)部聲明了一個 inner 函數(shù),但實際上 inner 函數(shù)是獨立調(diào)用的,所以依然是在全局環(huán)境,this仍然是指向了 window。

    function demo(func) {
        func();
    }
    demo(function () {
        console.log(this); // window
    });

demo函數(shù)傳入一個匿名函數(shù),執(zhí)行匿名函數(shù)func的時候,依然是作為函數(shù)獨立調(diào)用,所以this仍然指向window。

理解一下什么是作為函數(shù)獨立調(diào)用:
當(dāng)定義一個函數(shù),例如var demo = function () {} 等號右邊的函數(shù)是獨立放在內(nèi)存中的,然后賦予demo變量的指向為函數(shù)所在的內(nèi)存地址,當(dāng)直接調(diào)用 demo(),相當(dāng)于直接找到函數(shù)本身執(zhí)行,所以函數(shù)內(nèi)部創(chuàng)建的上下文為全局上下文,this 則指向了全局對象 window。

對象方法調(diào)用

當(dāng)調(diào)用一個對象方法時,this 代表了對象本身。

    let obj = {
        name: "invoker",
        getName: function () {
            console.log(this);   // obj
            console.log(this.name);  // "invoker"
        }
    }

    obj.getName();

定義了一個 obj 對象,調(diào)用其內(nèi)部的getNamethis 則指向了 obj 對象。

稍微修改一下

    var name = "windowName";
    let obj = {
        name: "invoker",
        getName: function () {
            console.log(this);  // window
            console.log(this.name); // windowName
        }
    }
 
    var getName = obj.getName;
    getName();

當(dāng)用一個變量 getName 接收 obj 對象的 getName方法, 再執(zhí)行 getName,發(fā)現(xiàn) this 指向了 window,因為此時變量 getName 直接指向了函數(shù)本身,而不是通過 obj 去調(diào)用,此時就變成了函數(shù)獨立調(diào)用的情況了。

再看個例子

    let obj = {
        test: function() {
            function fn() {
                console.log(this); // window
            }
            fn();
        },
        test1: function (fn) {
            fn()
        }
    }

    obj.test();
    obj.test1(function () {
        console.log(this) // window
    });

雖然在 obj 對象的 test 方法內(nèi)定義了 fn ,但執(zhí)行時同樣屬于函數(shù)獨立調(diào)用,所以 this 指向 window。
將函數(shù)作為參數(shù)傳入 objtest1 方法,也屬于函數(shù)獨立調(diào)用,this 同樣指向 window。

構(gòu)造函數(shù)調(diào)用

使用 new 關(guān)鍵字調(diào)用函數(shù),則是構(gòu)造函數(shù)調(diào)用,this 指向了該構(gòu)造函數(shù)新創(chuàng)建的對象。

    function person(name) {
        this.name = name
    }

    let p = new person("invoker")
    console.log(p.name) // "invoker"

回顧一下 new 關(guān)鍵詞的過程:

創(chuàng)建一個新的對象 obj

使得 obj__proto__ 指向 構(gòu)造函數(shù)的原型對象

執(zhí)行構(gòu)造函數(shù)中的 constructor,改變this的指向為 obj

如果結(jié)果是對象類型,則返回結(jié)果,否則返回obj

    function myNew(Fn) {
        let obj = {}
        obj.__proto__ = Fn.prototype

        const res = Fn.prototype.constructor.call(obj)
        if (typeof res === "object") {
            obj = res
        }

        return obj
    }
call、apply、bind

this 指向的是 call 、 apply、bind 調(diào)用時傳遞的第一個參數(shù)。

    let obj = {
        name: "invoker"
    }

    function demo() {
        console.log(this.name) // "invoker"
    }

    demo.call(obj)
    demo.apply(obj) 
    demo.bind(obj)() 
箭頭函數(shù)

箭頭函數(shù)在執(zhí)行時并不會創(chuàng)建自身的上下文,它的 this 取決于自身被定義的所在執(zhí)行上下文。

例子:

    let obj = {
        fn: () => {
            console.log(this) // window
        }
    }

    obj.fn()

objfn 指向一個箭頭函數(shù),由于只有函數(shù)可以創(chuàng)建執(zhí)行上下文,而箭頭函數(shù)外部并沒有包裹函數(shù),所以箭頭函數(shù)所在的執(zhí)行上下文為全局的執(zhí)行上下文,this 指向 window

包裹一個函數(shù)看看唄?

    let obj = {
        fn: function () {
            console.log("箭頭函數(shù)所在執(zhí)行上下文", this) // "箭頭函數(shù)所在執(zhí)行上下文" obj
            
            var arrow = () => {
                console.log(this) //obj
            }
            arrow()
        }
    }

    obj.fn()

箭頭函數(shù) arrow 被定義在 obj.fn 內(nèi),所以 fn 中的 this 就是 arrow 中的 this

箭頭函數(shù)一次綁定上下文后便不可更改:

    let obj = { name: "invoker" }

    var demo = () => {
        console.log(this) // window
    }

    demo.call(obj)

雖然使用了 call 函數(shù)間接修改 this 的指向,但并不起作用。

為什么會有this的設(shè)計

javascript中存在 this 的設(shè)計,跟其內(nèi)存中的數(shù)據(jù)結(jié)構(gòu)有關(guān)系。

假設(shè)定義 let obj = { name: "invoker" }

此時會先生成一個對象 { name: "invoker" } 并放在內(nèi)存當(dāng)中

{ name: "invoker } 所在的內(nèi)存地址賦予 obj

所以 obj 其實就是個指向某個對象的地址,如果要讀取 obj.name,則先要找到 obj 所在地址,然后從地址中拿到原始對象,讀取 name 屬性。

對象中每個屬性都有一個屬性描述對象:可通過 Object.getOwnPropertyDescriptor(obj, key) 來讀取。
也就是說上面所說的 objname 屬性實際是下面這樣的

{
  name: {
    [[value]]: "invoker",
    [[configurable]]: true,
    [[enumerable]]: true,
    [[writable]]: true
  }
}

value 就是獲得的值。

現(xiàn)在假設(shè)對象的屬性是一個函數(shù):

    let name = "windowName"
    let obj = {
        name: "invoker",
        sayHello: function () {
            console.log("my name is " + this.name)
        }
    }

    let descriptor = Object.getOwnPropertyDescriptor(obj, "sayHello")
    console.log(descriptor)
    
    //這個sayHello的屬性描述對象為:
      sayHello: {
        [[value]]: ? (),
        [[configurable]]: true,
        [[enumerable]]: true,
        [[writable]]: true
      }

sayHellovalue 值是一個函數(shù),這個時候,引擎會多帶帶將這個函數(shù)放在 內(nèi)存 當(dāng)中,然后將函數(shù)的內(nèi)存地址賦予 value

因此可以得知,這個函數(shù)在 內(nèi)存 中是多帶帶的,并不被誰擁有,所以它可以在不同的上下文執(zhí)行。

由于函數(shù)可以在不同上下文執(zhí)行,所以需要一種機制去獲取當(dāng)前函數(shù)內(nèi)部的執(zhí)行上下文。所以,就有了 this,它指向了當(dāng)前函數(shù)執(zhí)行的上下文。

// 接著上面代碼

    obj.sayHello() // my name is invoker
    
    let sayHello = obj.sayHello
    sayHello() // my name is windowName

obj.sayHello() 是通過 obj 找到 sayHello,也就是對象方法調(diào)用,所以就是在 obj 環(huán)境執(zhí)行。
當(dāng) let sayHello = obj.sayHello,變量 sayHello 就直接指向函數(shù)本身,所以 sayHello() 也就是函數(shù)獨立調(diào)用,所以是全局環(huán)境執(zhí)行。

總結(jié)

this 的出現(xiàn),跟JS引擎內(nèi)存中的數(shù)據(jù)結(jié)構(gòu)有關(guān)系。
當(dāng)發(fā)現(xiàn)一個函數(shù)被執(zhí)行時,通過上面的多種情況。

分析函數(shù)怎么調(diào)用(多帶帶調(diào)用、對象方法、構(gòu)造方法)

是否有使用 call、apply 等間接調(diào)用

是否有箭頭函數(shù)

甚至還可能分析是否為嚴(yán)格模式

這樣就能很好的確認(rèn) this 的指向。

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/110291.html

相關(guān)文章

  • Python 常用小妙招(一)

    摘要:本文記錄一些日常編程中的小妙招,并使用進行交互測試,讓我們更好的了解和學(xué)習(xí)的一些特性。兩變量交換語法測試免去了利用一個臨時變量進行過渡交互。相互轉(zhuǎn)換看看各自的能不能排上用場。 ...

    XFLY 評論0 收藏0
  • Java進階之路 - 收藏集 - 掘金

    摘要:請欣賞語法清單后端掘金語法清單翻譯自的,從屬于筆者的入門與實踐系列。這篇一篇框架整合友好的文章三后端掘金一理論它始終是圍繞數(shù)據(jù)模型頁面進行開發(fā)的。 RxJava 常用操作符 - Android - 掘金 原文地址 http://reactivex.io/documenta... ... RxJava 和 Retrofit 結(jié)合使用完成基本的登錄和注冊功能 - Android - 掘...

    BakerJ 評論0 收藏0
  • Nginx

    摘要:此外,其也能夠提供強大的反向代理功能。是由為俄羅斯訪問量第二的站點開發(fā)的,第一個公開版本發(fā)布于年月日。 keepalived+nginx 實現(xiàn)高可用雙機熱備 + 負(fù)載均衡架構(gòu) 1 準(zhǔn)備4個ubuntu16.04虛擬機(啟用網(wǎng)卡二并使用橋接模式):A服務(wù)器:192.168.0.103 主B服務(wù)器:192.168.0.104 主(備) 前端工程師學(xué)習(xí) Nginx ...

    syoya 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<