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

資訊專欄INFORMATION COLUMN

理解 JavaScript this

zombieda / 569人閱讀

摘要:回調函數在回調函數中的指向也會發生變化。在閉包回調函數賦值等場景下我們都可以利用來改變的指向,以達到我們的預期。文章參考系列文章理解閉包理解執行棧理解作用域理解數據類型與變量原文發布在我的公眾號,點擊查看。

這是本系列的第 5 篇文章。

還記得上一篇文章中的閉包嗎?點擊查看文章 理解 JavaScript 閉包 。

在聊 this 之前,先來復習一下閉包:

var name = "Neil";

var person = {
  name: "Leo",
  sayHi: function() {
    return function () {
      return "Hi! My name is " + this.name;
    }
  }
};

person.sayHi()(); // "Hi! My name is Neil"

上一篇文章說,我們可以把閉包簡單地理解為函數返回函數。所以這里的閉包結構是:

// ...
function () {
  return "Hi! My name is " + this.name;
}
// ...

但是你有沒有發現,這個函數執行的結果是 “Hi! My name is Neil” 。等等,我不是叫 Leo 嗎?怎么給我改了個名字?!

我一分析,原來是 this 在其中作祟,且聽我慢慢道來這“改名的由來”。

§ this 從何而來

首先,你得確保你已經清楚執行棧與執行上下文的知識。點擊查看文章 理解 JavaScript 執行棧 。

ECMAScript 5.1 中定義 this 的值為執行上下文中的 ThisBinding。而 ThisBinding 簡單來說就是由 JS 引擎創建并維護,在執行時被設置為某個對象的引用

在 JS 中有三種情況可以創建上下文:初始化全局環境、eval() 和執行函數。

§ 全局中的 this
var num = 1;

function getName () {
  return "Leo";
}

this.num; // 1
this.getName(); // Leo

this == window; // true

當我們在瀏覽器中運行這段代碼,JS 引擎會將 this 設置為 window 對象。而聲明的變量和函數被作為屬性掛載到 window 對象上。當然,在嚴格模式下,全局中 this 的值設置為 undefined。

"use strcit";

var num = 1;
function getName () {
  return "Leo";
}

this.num; // TypeError
this.getName(); // TypeError

this == undefined; // true

開啟嚴格模式后,全局 this 將指向 undefined,所以調用 this.num 會報錯。

§ eval() 中的 this

eval() 不被推薦使用,我現在對其也不太熟悉,這里嘗試著說一下。初學者可以直接跳到下一節。

結合所查閱的資料,目前我對 eval() 的理解如下:

eval(...) 直接調用,被理解為是一個 lvalue,也有說是 left unchanged,字面理解為余下不變。什么是“余下不變”?我理解為直接調用 eval(...),其中代碼的執行環境不變,依舊為當前環境,this 也依舊指向當前環境中的調用對象。

而使用類似 (1, eval)(...) 的代碼,被稱為間接調用。(1, eval) 是一個表達式,你可以這樣認為 (true && eval) 或者 (0 : 0 ? eval)。間接調用的 eval 始終認為其中的代碼執行在全局環境,將 this 綁定到全局對象。

var x = "outer";
(function() {
  var x = "inner";
  // "direct call: inner"
  eval("console.log("direct call: " + x)");
  // "indirect call: outer"
  (1, eval)("console.log("indirect call: " + x)");
})();

關于 eval(),現在不敢確定,如有錯誤,歡迎指正。

§ 函數中的 this ◆ 一般情況

首先,我們需要明確的是,在 JS 中函數也屬于對象,它可以擁有屬性,this 就是函數在執行時獲得的屬性。一般情況下,在全局環境中直接調用函數,函數中的 this 會在調用時被 JS 引擎設置為全局對象 window(同樣在嚴格模式下為 undefined)。

var name = "Leo";

function getName() {
  var name = "Neil";
  console.log(this); // [object Window]
  return this.name;
}

getName(); // Leo
◆ 作為對象的方法

函數可以作為對象的方法被該對象調用,那么這種情況 this 會被設置為該對象。

var name = "Neil";

var person = {
  name: "Leo",
  sayHi: function() {
    console.log(this); // person
    return "Hi! My name is " + this.name;
  }
};

person.sayHi(); // "Hi! My name is Leo"

當 person 對象調用 sayHi() 方法時,this 被指向 person。

◆ 特殊的內置函數

JS 還提供了一種供開發者自定義 this 的方式,它提供了 3 種方式。

Function.prototype.call(thisArg, argArray)

Function.prototype.apply(thisArg [, arg1 [, args2, ...]])

Function.prototype.bind(thisArg [, arg1 [, args2, ...]])

我們可以通過設置 thisArg 的值,來自定義函數中 this 的指向。

var leo = {
  name: "Leo",
  sayHi: function () {
    return "Hi! My name is " + this.name;
  }
}

var neil = {
  name: "Neil"
};

leo.sayHi(); // "Hi! My name is Leo"
?leo.sayHi.call(neil); // "Hi! My name is Neil"

這里,我們通過 call() 將 sayHi() 中 this 的指向綁定為 neil 對象,從而取代了默認 的 this 指向 leo 對象。

關于函數的 call(), apply(), bind() 我將在后面另寫一篇文章,敬請期待。

§ this 引起的令人費解的現象 ◆ 閉包

通過前面的介紹,我想你對 this 已經有了初步的印象。那么,回到文章開頭的問題,this 是怎么改變了我的名字?換句話說,this 在閉包的影響下指向發生了怎樣的變動?

再看一下代碼:

var name = "Neil";

var person = {
  name: "Leo",
  sayHi: function() {
    return function () {
      return "Hi! My name is " + this.name;
    }
  }
};

person.sayHi()(); // "Hi! My name is Neil"

通過上一篇文章 理解 JavaScript 閉包,函數返回函數會形成閉包。在這種情況下,閉包往往所執行的環境與所定義的環境不一致,而 this 的值卻是在執行時決定的。所以,當上面代碼中的閉包在執行時,它所在的執行上下文是全局環境,this 將被設置為 window(嚴格模式下為 undefined)。

怎么解決?我們可以利用 call / apply / bind 來修改 this 的指向。

var name = "Neil";

var person = {
  name: "Leo",
  sayHi: function() {
    return function () {
      return "Hi! My name is " + this.name;
    }
  }
};

person.sayHi().call(person); // "Hi! My name is Leo"

這里利用 call() 將 this 指向 person。OK,我的名字回來了,“Hi! My name is Leo” ^^

當然,我們還有第二種解決方法,閉包的問題就讓閉包自己解決。

var name = "Neil";

var person = {
  name: "Leo",
  sayHi: function() {
    var that = this; // 定義一個局部變量 that
    return function () {
      return "Hi! My name is " + that.name; // 在閉包中使用 that
    }
  }
};

person.sayHi()(); // "Hi! My name is Leo"

在 sayHi() 方法中定義一個局部變量,閉包可以將這個局部變量保存在內存中,從而解決問題。

◆ 回調函數

在回調函數中 this 的指向也會發生變化。

var name = "Neil";

var person = {
  name: "Leo",
  sayHi: function() {
    return "Hi! My name is " + this.name;
  }
};

var btn = document.querySelector("#btn");

btn.addEventListener("click", person.sayHi);
// "Hi! My name is undefined"

這里 this 既不指向 person,也不指向 window。那它指向什么?

btn 對象,它是一個 DOM 對象,有一個 onclick 方法,在這里定義為 person.sayHi。

{
  // ...
  onclick: person.sayHi
  // ...
}

所以,當我們執行上面的代碼,this.name 的值為 undefined,因為 btn 對象上沒有定義 name 屬性。我們給 btn 對象自定義一個 name 屬性來驗證一下。

var btn = document.querySelector("#btn");

btn.name = "Jackson";

btn.addEventListener("click", person.sayHi);
// "Hi! My name is Jackson"

原因說清楚了,解決方案同樣可用過 call / apply / bind 來改變 this 的指向,使其綁定到 person 對象。

btn.addEventListener("click", person.sayHi.bind(person));
// "Hi! My name is Leo"
◆ 賦值
var name = "Neil";

var person = {
  name: "Leo",
  sayHi: function() {
    return "Hi! My name is " + this.name;
  }
};

person.sayHi(); // "Hi! My name is Leo"

var foo = person.sayHi;

foo(); // "Hi! My name is Neil"

當把 person.sayHi() 賦值給一個變量,這個時候 this 的指向又發生了變化。因為 foo 執行時是在全局環境中,所以 this 指向 window(嚴格模式下指向 undefined)。

同樣,我們可以通過 call / apply / bind 來解決,這里就不貼代碼了。

§ 別忘了 new

在 JS 中,我們聲明一個類,然后 new 一個實例。

function Person(name) {
  this.name = name;
}

var her = Person("Angelia");
console.log(her.name); // TypeError

var me = new Person("Leo");
console.log(me.name); // "Leo"

如果我們直接把調用這個函數,this 將指向全局對象,Person 在這里就是一個普通函數,沒有返回值,默認 undefined,而嘗試訪問 undefined 的屬性就會報錯。

如果我們使用 new 操作符,那么 new 其實會生成一個新的對象,并將 this 指向這個新的對象,然后將其返回,所以 me.name 能打印出 “Leo”。

關于 new 的原理,我會在后面的文章分享,敬請期待。

§ 小結

你看,this 是不是千變萬化。但是我們得以不變應萬變。

在這么多場景下,this 的指向萬變不離其宗:它一定是在執行時決定的,指向調用函數的對象。在閉包、回調函數、賦值等場景下我們都可以利用 call / apply / bind 來改變 this 的指向,以達到我們的預期。

接下來,請期待文章《理解 JavaScript call/apply/bind》。

◆ 文章參考

Understand JavaScript"s "this" With Clarity, and Matser It | Richard Bovell

How does the "this" keyword work | Stack Overflow

ECMAScript Language Specification - $11.1.1 The This Keyword

(1, eval)("this") vs eval("this") in JavaScript | Stack Overflow

§ JavaScript 系列文章

理解 JavaScript 閉包

理解 JavaScript 執行棧

理解 JavaScript 作用域

理解 JavaScript 數據類型與變量

Be Good. Sleep Well. And Enjoy.

原文發布在我的公眾號 camerae,點擊查看。

前端技術 | 個人成長

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

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

相關文章

  • 我對JavaScriptthis的一些理解

    摘要:匿名函數的執行環境具有全局性,因此它的對象通常指向。如果對此有疑惑,可以看知乎上的答案知乎匿名函數的指向為什么是作為對象方法的調用,指向該對象當函數作為某個對象的方法調用時,就指這個函數所在的對象。 因為日常工作中經常使用到this,而且在JavaScript中this的指向問題也很容易讓人混淆一部分知識。 這段時間翻閱了一些書籍也查閱了網上一些資料然后結合自己的經驗,為了能讓自...

    focusj 評論0 收藏0
  • javascript技術難點(三)之this、new、apply和call詳解

    摘要:第四點也要著重講下,記住構造函數被操作,要讓正常作用最好不能在構造函數里 4) this、new、call和apply的相關問題 講解this指針的原理是個很復雜的問題,如果我們從javascript里this的實現機制來說明this,很多朋友可能會越來越糊涂,因此本篇打算換一個思路從應用的角度來講解this指針,從這個角度理解this指針更加有現實意義。 下面我們看看在ja...

    ghnor 評論0 收藏0
  • 加深對 JavaScript This理解

    摘要:使用來調用函數,會自動執行下面操作創建一個全新的對象。所以如果是一個函數的話,會是這樣子的創建一個新對象連接新對象與函數的原型執行函數,改變指向新的對象所以,在使用來調用函數時候,我們會構造一個新對象并把它綁定到函數調用中的上。 歡迎來我的博客閱讀:《加深對 JavaScript This 的理解》 我相信你已經看過很多關于 JavaScript 的 this 的談論了,既然你點進來...

    PiscesYE 評論0 收藏0
  • 理解 JavaScript call()/apply()/bind()

    摘要:理解文章中已經比較全面的分析了在中的指向問題,用一句話來總結就是的指向一定是在執行時決定的,指向被調用函數的對象。與和直接執行原函數不同的是,返回的是一個新函數。這個新函數包裹了原函數,并且綁定了的指向為傳入的。 理解 JavaScript this 文章中已經比較全面的分析了 this 在 JavaScript 中的指向問題,用一句話來總結就是:this 的指向一定是在執行時決定的,...

    duan199226 評論0 收藏0
  • javascriptthis理解

    摘要:的關鍵字總是讓人捉摸不透,關鍵字代表函數運行時,自動生成的一個內部對象,只能在函數內部使用,因為函數的調用場景不同,的指向也不同。其實只要理解語言的特性就很好理解。個人對中的關鍵字的理解如上,如有不正,望指正,謝謝。 javascript的this關鍵字總是讓人捉摸不透,this關鍵字代表函數運行時,自動生成的一個內部對象,只能在函數內部使用,因為函數的調用場景不同,this的指向也不...

    jimhs 評論0 收藏0

發表評論

0條評論

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