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

資訊專欄INFORMATION COLUMN

講清楚之 javascript中的this

selfimpr / 340人閱讀

摘要:講清楚之中的這一節來探討。所以當函數作為構造函數調用,則函數內部的綁定到該函數上。在通過構造函數實例化對象時,對象內部的也同樣指向該實例對象。

講清楚之 javascript中的this

這一節來探討this。 在 javascript 中 this 也是一個神的存在,相對于 java 等語言在編譯階段確定,而在 javascript 中, this 是動態綁定,也就是在運行期綁定的。這導致了 javascript 中 this 的靈活性,而且對識別對象不同的調用場景下 this 指向帶來了一些困擾。

在全局環境中this指向window,即this === window。this 的靈活性主要體現在函數環境中,容易判定出錯的也是函數環境下的 this 指向.

this 是函數內部的可見屬性之一(另一個是 arguments), 在函數內部我們可以直接使用this訪問指定對象的屬性。那么指定對象是如何確定的?

下面就圍繞 this 的指向對象來梳理

this 是怎么確定的?

首先 this 是在函數被調用時確定的, 也就是在進入函數后,函數內表達式、語句執行前的變量對象創建階段確定的。

而它指向什么取決于函數在哪里被調用(在什么對象上被調用).

一般情形需要關注函數在哪里被調用、被怎么調用.

下面主要分析函數在不同調用場景下this的指向.

當函數作為方法被對象擁有并調用時 this 指向該對象,否則 this 為 undefind
把標題展開描述就是: 當函數調用時是被某一個對象所擁有,函數內的this將綁定到該對象上。如果函數是獨立調用的,則函數內部的 this 在嚴格模式下為 undefind, 在非嚴格模式下 this 會指向 window(node.js中指向global)。

根據上面的原則,我們首要判斷的是函數被所擁有,舉幾個栗子更好理解:

栗子1:

let a = 1
function foo () {
    console.log(this.a)
}

foo() // 1

foo() 是在全局環境下獨立調用的,此時函數 foo 被全局對象擁有(this 指向 window),所以this.a獲取的是 window 全局對象下面的 a.

栗子2:

var a = 1
var foo = function (){
    console.log(this.a)
}
var too = {
    a: 2,
    b: foo
}
var bar = too.b

foo() // 1
too.b() // 2
bar() // 1

函數執行時確定 this 指向的大致邏輯:

foo() :

在全局對象 window 下調用,所以輸出1。

too.b():

對象 too 的屬性 b 指向函數 foo,此時函數 foo 是 對象 too 內部的一個方法;

too.b()執行時,b 是被對象 too調用的,此時內部的 this 指向 對象 too;

所以this.a獲取的是too.a,輸出2;

bar():

對象 too 的方法被賦值給 bar, 即此時 bar 標識符同 foo 標識符一樣都指向同一個棧地址所代表的函數。

執行bar()此時在全局對下 window 下調用,所以輸出1。

栗子3:

var a = 1
var foo = function () {
    console.log(this.a)
}
var too = function (fn) {
    var a = 2
    fn()
}
too(foo) // 1

too(foo) :這里函數 foo 作為參數被傳遞到函數 too的內部執行, fn()執行時并沒有被其他對象顯示擁有,所以我們隱式的判定fn()是在全局對象 window 下面執行的,所以輸出 1 。

這個栗子很容易搞錯(我自己感覺每過一段時間再看還是會錯o(︶︿︶)o),第一印象輸出的應該是2,那是應為把 this 與作用域鏈弄混淆了。始終要記住作用域鏈是在源代碼編碼階段就確定了,而 this 是在函數運行階段才確定,屬于執行上下文的概念,是在運行階段依據 this所在函數被誰調用來確定的。

我們再來把上面的栗子稍微修改一下

栗子4:

var a = 1
var foo = function () {
    console.log(this.a) // 輸出 1
    console.log(a) // 區別在這里, 輸出 1
}
var too = function (fn) {
    var a = 2
    fn()
}
too(foo) // 1, 1
表達式 - -
console.log(this.a) 基于上下文 this 表達式所屬 foo 函數在 too 函數內調用時 this 指向 window 1
console.log(a) 基于作用域鏈 全局上下文中的變量 a 在 foo 函數作用域鏈上 1

不知道你理解了沒有,這個栗子也體現了上下文作用域在進行變量/屬性查找時的區別

栗子5:

let c = 1
let foo = {
    c: 2
}
let too = function () {
    console.log(this.c)
}
foo.a = {
    b: too,
    c: 3
}

foo.a.b() // 3

this的綁定只受最靠近的成員引用的影響。foo.a.b()函數b作為對象foo.a的方法被調用,所以此時的this綁定到foo.ab與對象foo的包含成員沒有多大關系,最靠近的對象才決定this的綁定。

最后console.log(this.c)取到的是foo.ac的值 3 .

栗子5:

let a = 1
let foo = {
    a: 2,
    msg: function () {
        console.log(`hi, ${this.a}`)
    }
}
let too = Object.create(foo)

too.msg() // hi, 2

上面用對象foo作為原型創建新對象too, 所以對象 too 繼承對象 foo 的所有屬性、方法。too.msg()執行時,msg 函數被 too 調用,此時this就指向對象too, 所以console.log(hi, ${this.a})訪問的是從對象foo繼承來的 a.

所以對于在對象原型鏈上某處定義的方法,同樣的概念也適用。如果該方法存在于一個對象的原型鏈上,那么對象實例的this指向的是調用這個方法的對象,通過this可以訪問到原形鏈上的方法。

通過上面的幾個栗子驗證了我們的總結:

當函數作為對象方法調用時 this 指向該對象,作為函數獨立調用時 this 指向全局對象 window (嚴格模式下 this 為 undefind )。

大部分時候依據上面的原則來判斷 this 的指向是沒有問題,但是 this 還有以下幾種特殊場景需要注意。

當函數作為構造函數調用,此時函數內部的 this 指向函數自身
函數也是對象

栗子:

function Foo (a) {
    this.a = a // 實例化后 this 指向 too
}
let too = new Foo(1)

我們知道函數 this 在運行期確定,而構造函數實例化時在內部其實是為我們創建了一個新的對象,通過一系列的操作后將 this 指向了這個新對象。

new操作符執行時的邏輯推導如下:

創建一個新的空對象;

將構造函數的 this 指向這個新對象;

將構造函數的原形添加到新對象的原形鏈里,將屬性、方法掛載在新對象上;

返回這個新對象

返回的新對象就是我們實例化的對象。即, new 操作符調用構造函數時,this 是指向內部創建的新對象,最后會將新創建的對象返回給實例變量。

所以當函數作為構造函數調用,則函數內部的 this 綁定到該函數上。在通過構造函數實例化對象時,對象內部的 this 也同樣指向該實例對象。

當函數使用 cal、apply 方法調用執行,此時 this 指向 call、apply 方法傳入的對象
在 javascript 里函數也是對象。 所有函數都繼承于 Function 構造函數,而  call、apply 是 Function.prototype 原形的方法,所以函數都從原形的原形里繼承了 call、apply 方法。

call、apply 用于向函數注入 this 對象和變量(call 與 apply 的區別在于傳遞的參數不一樣,其他沒有區別)。

let a = 1
let too = {
    a: 2
}
function foo () {
    console.log(this.a)
}
foo.call(too) // 2

函數 foo 里面的 this 此時指向call傳遞進來的對象 too,所以this.a打印的是 2.

如果傳遞給 this 的值不是一個對象,JavaScript 會嘗試使用內部 ToObject 操作將其轉換為對象。因此,如果傳遞的值是一個原始值比如 7"foo",那么就會使用相關構造函數將它轉換為對象,所以原始值 7 會被轉換為對象: new Number(7) ,而字符串 "foo" 轉化成 new String("foo")

function bar() {
  console.log(this, Object.prototype.toString.call(this));
}

//原始值 7 被隱式轉換為對象
bar.call(7); // Number {[[PrimitiveValue]]: 7}__proto__: Number[[PrimitiveValue]]: 7 "[object Number]"

ECMAScript 5 引入了 Function.prototype.bind。當函數調用f.bind(someObject)會創建一個與f具有相同函數體和作用域的函數,但是在這個新函數中,this將永久地被綁定到了bind對象someObject

栗子:

let a = 1
let too1 = {
    a: 2
}
function foo () {
    console.log(this.a)
}
let bar = foo.bind(too1)
let bar2 = {
    a: 4,
    b: bar
}

bar() // 2
bar.call({a: 3}) // 2
bar2.b() // 2

foo 通過bind創建一個新函數時,新函數的this強制綁定到了傳入的對象too1, 后續執行中bar即使是作為對象方法調用還是使用 call、apply 都無法替換使用 bind 綁定的 this。

當函數是以箭頭函數方式創建的,此時的 this 指向箭頭函數執行時的宿主函數的上下文

栗子:

function foo () {
    let that = this
    let too = () => {
        console.log(this === that) // true
    }
    too()
}
foo()

too 為箭頭函數,內部的 this 被指向為他創建時的上下文,即 foo 的 this 。反過來說就是箭頭函數沒有自己的上下文,他共享的是封閉詞法上下文。

注意這里提到的 “this 是動態綁定,在運行期綁定的” 主要是指進入函數后,函數運行前的上下文創建階段(預處理),此時函數內的表達式、語句并沒有執行。但這里都統稱為函數運行期,詳細請關注變量對象一節的描述(^.^)。

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

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

相關文章

  • 講清楚之執行上下文

    摘要:棧底為全局上下文,棧頂為當前正在執行的上下文。位于棧頂的上下文執行完畢后會自動出棧,依次向下直至所有上下文運行完畢,最后瀏覽器關閉時全局上下文被銷毀。 講清楚之執行上下文 標簽 : javascript 什么是執行上下文? 當 JavaScript 代碼執行一段可執行代碼時,會創建對應的上下文(execution context)并將該上下文壓入上下文棧(context stack...

    3fuyu 評論0 收藏0
  • 講清楚之 javascript 對象繼承

    摘要:中的繼承并不是明確規定的,而是通過模仿實現的。繼承中的繼承又稱模擬類繼承。將函數抽離到全局對象中,函數內部直接通過作用域鏈查找函數。這種范式編程是基于作用域鏈,與前面講的繼承是基于原型鏈的本質區別是屬性查找方式的不同。 這一節梳理對象的繼承。 我們主要使用繼承來實現代碼的抽象和代碼的復用,在應用層實現功能的封裝。 javascript 的對象繼承方式真的是百花齊放,屬性繼承、原型繼承、...

    Jonathan Shieber 評論0 收藏0

發表評論

0條評論

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