国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

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

lemanli / 1870人閱讀

摘要:回顧一下關鍵詞的過程創建一個新的對象使得的指向構造函數的原型對象執行構造函數中的,改變的指向為如果結果是對象類型,則返回結果,否則返回指向的是調用時傳遞的第一個參數。

this = ?

在JS中,當一個函數執行時,都會創建一個執行上下文用來確認當前函數的執行環境,執行上下文分為 全局執行上下文函數執行上下文。而 this 就是指向這個執行上下文的對象。所以,this是在運行時決定的,可以簡單的理解為 誰調用,this指向誰。

分四種情況來看:

普通函數調用

對象方法調用

構造函數調用

call、apply、bind

普通函數調用

當函數作為函數獨立調用的時候,則是在全局環境中運行,this 則指向全局對象 window

一個簡單的例子

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

demo();

demo 函數獨立調用,所以 this 指向全局對象 window

接著

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

    inner();
}

outer();

雖然在 outer 函數內部聲明了一個 inner 函數,但實際上 inner 函數是獨立調用的,所以依然是在全局環境,this仍然是指向了 window

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

demo函數傳入一個匿名函數,執行匿名函數func的時候,依然是作為函數獨立調用,所以this仍然指向window

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

對象方法調用

當調用一個對象方法時,this 代表了對象本身。

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

    obj.getName();

定義了一個 obj 對象,調用其內部的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();

當用一個變量 getName 接收 obj 對象的 getName方法, 再執行 getName,發現 this 指向了 window,因為此時變量 getName 直接指向了函數本身,而不是通過 obj 去調用,此時就變成了函數獨立調用的情況了。

再看個例子

    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 方法內定義了 fn ,但執行時同樣屬于函數獨立調用,所以 this 指向 window
將函數作為參數傳入 objtest1 方法,也屬于函數獨立調用,this 同樣指向 window

構造函數調用

使用 new 關鍵字調用函數,則是構造函數調用,this 指向了該構造函數新創建的對象。

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

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

回顧一下 new 關鍵詞的過程:

創建一個新的對象 obj

使得 obj__proto__ 指向 構造函數的原型對象

執行構造函數中的 constructor,改變this的指向為 obj

如果結果是對象類型,則返回結果,否則返回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 指向的是 callapplybind 調用時傳遞的第一個參數。

    let obj = {
        name: "invoker"
    }

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

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

箭頭函數在執行時并不會創建自身的上下文,它的 this 取決于自身被定義的所在執行上下文。

例子:

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

    obj.fn()

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

包裹一個函數看看唄?

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

    obj.fn()

箭頭函數 arrow 被定義在 obj.fn 內,所以 fn 中的 this 就是 arrow 中的 this

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

    let obj = { name: "invoker" }

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

    demo.call(obj)

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

為什么會有this的設計

javascript中存在 this 的設計,跟其內存中的數據結構有關系。

假設定義 let obj = { name: "invoker" }

此時會先生成一個對象 { name: "invoker" } 并放在內存當中

{ name: "invoker } 所在的內存地址賦予 obj

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

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

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

value 就是獲得的值。

現在假設對象的屬性是一個函數:

    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 值是一個函數,這個時候,引擎會多帶帶將這個函數放在 內存 當中,然后將函數的內存地址賦予 value

因此可以得知,這個函數在 內存 中是多帶帶的,并不被誰擁有,所以它可以在不同的上下文執行。

由于函數可以在不同上下文執行,所以需要一種機制去獲取當前函數內部的執行上下文。所以,就有了 this,它指向了當前函數執行的上下文。

// 接著上面代碼

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

obj.sayHello() 是通過 obj 找到 sayHello,也就是對象方法調用,所以就是在 obj 環境執行。
let sayHello = obj.sayHello,變量 sayHello 就直接指向函數本身,所以 sayHello() 也就是函數獨立調用,所以是全局環境執行。

總結

this 的出現,跟JS引擎內存中的數據結構有關系。
當發現一個函數被執行時,通過上面的多種情況。

分析函數怎么調用(多帶帶調用、對象方法、構造方法)

是否有使用 call、apply 等間接調用

是否有箭頭函數

甚至還可能分析是否為嚴格模式

這樣就能很好的確認 this 的指向。

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/110291.html

相關文章

  • Python 常用小妙招(一)

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

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

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

    BakerJ 評論0 收藏0
  • Nginx

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

    syoya 評論0 收藏0

發表評論

0條評論

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