亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

JavaScript中this的錯誤認識和綁定規則以及常見問題是怎樣的

發布時間:2021-09-30 15:04:35 來源:億速云 閱讀:144 作者:柒染 欄目:web開發

JavaScript中this的錯誤認識和綁定規則以及常見問題是怎樣的,很多新手對此不是很清楚,為了幫助大家解決這個難題,下面小編將為大家詳細講解,有這方面需求的人可以來學習下,希望你能有所收獲。

相信 Javascript 中的 this  會使很多同學在工作學習中產生困惑,筆者也同樣是,經過閱讀各種資料及實際工作中的應用,做了以下梳理,主要內容包括長期以來大家對 this 的錯誤認識及 this  的綁定規則,箭頭函數、實際工作場景中遇到的問題,希望對于有此困惑的你能有所幫助。

JavaScript中this的錯誤認識和綁定規則以及常見問題是怎樣的

一、兩種錯誤認識

1. 指向自身

this 的第一個錯誤認識是,很容易把 this 理解成指向函數自身,其實 this 的指向在函數定義階段是無法確定的,只有函數執行時才能確定 this  到底指向誰,實際 this 的最終指向是調用它的那個對象。

下面示例,聲明函數 foo(),執行 foo.count=0 時,像函數對象 foo 添加一個屬性 count。但是函數 foo 內部代碼  this.count 中的 this 并不是指向那個函數對象,for 循環中的 foo(i) 掉用它的對象是 window,等價于  window.foo(i),因此函數 foo 里面的 this 指向的是 window。

function foo(num){   this.count++; // 記錄 foo 被調用次數 } foo.count = 0; window.count = 0; for(let i=0; i<10; i++){   if(i > 5){     foo(i);   } } console.log(foo.count, window.count); // 0 4

2. 指向函數的作用域

對 this 的第二種誤解就是 this 指向函數的作用域

以下這段代碼,在 foo 中試圖調用 bar 函數,是否成功調用,取決于環境。

  • 瀏覽器:在瀏覽器環境里是沒有問題的,全局聲明的函數放在了 window 對象下,foo 函數里面的 this 代指的是 window  對象,在全局環境中并沒有聲明變量 a,因此在 bar 函數中的 this.a 自然沒有定義,輸出 undefined。

  • Node.js:在 Node.js 環境下,聲明的 function 不會放在 global 全局對象下,因此在 foo 函數里調用 this.bar  函數會報 TypeError: this.bar is not a function 錯誤。要想運行不報錯,調用 bar 函數時省去前面的 this。

function foo(){   var a = 2;   this.bar(); } function bar(){   console.log(this.a); } foo();

二、This 四種綁定規則

1. 默認綁定

當函數調用屬于獨立調用(不帶函數引用的調用),無法調用其他的綁定規則,我們給它一個稱呼 “默認綁定”,在非嚴格模式下綁定到全局對象,在使用了嚴格模式  (use strict) 下綁定到 undefined。

嚴格模式下調用:

'use strict' function demo(){   // TypeError: Cannot read property 'a' of undefined   console.log(this.a); } const a = 1; demo();

非嚴格模式下調用:

在瀏覽器環境下會將 a 綁定到 window.a,以下代碼使用 var 聲明的變量 a 會輸出 1。

function demo(){   console.log(this.a); // 1 } var a = 1; demo();

以下代碼使用 let 或 const 聲明變量 a 結果會輸出 undefined

function demo(){   console.log(this.a); // undefined } let a = 1; demo();

在舉例子的時候其實想要重點說明 this 的默認綁定關系的,但是你會發現上面兩種代碼因為分別使用了 var、let  進行聲明導致的結果也是不一樣的,歸其原因涉及到 頂層對象的概念

在 Issue: Nodejs-Roadmap/issues/11 里有童鞋提到這個疑問,也是之前的疏忽,再簡單聊下頂層對象的概念,頂層對象(瀏覽器環境指  window、Node.js 環境指 Global)的屬性和全局變量屬性的賦值是相等價的,使用 var 和 function 聲明的是頂層對象的屬性,而 let  就屬于 ES6 規范了,但是 ES6 規范中 let、const、class 這些聲明的全局變量,不再屬于頂層對象的屬性。

2. 隱式綁定

在函數的調用位置處被某個對象包含,擁有上下文,看以下示例:

function child() {   console.log(this.name); } let parent = {   name: 'zhangsan',   child, } parent.child(); // zhangsan

函數在調用時會使用 parent 對象上下文來引用函數 child,可以理解為child 函數被調用時 parent 對象擁有或包含它。

隱式綁定的隱患:

被隱式綁定的函數,因為一些不小心的操作會丟失綁定對象,此時就會應用最開始講的綁定規則中的默認綁定,看下面代碼:

function child() {   console.log(this.name); } let parent = {   name: 'zhangsan',   child, } let parentparent2 = parent.child; var name = 'lisi'; parent2();

將 parent.child 函數本身賦給 parent2,調用 parent2() 其實是一個不帶任何修飾的函數調用,因此會應用默認綁定。

3. 顯示綁定

顯示綁定和隱式綁定從字面意思理解,有一個相反的對比,一個表現的更直接,一個表現的更委婉,下面在看下兩個規則各自的含義:

  • 隱式綁定:在一個對象的內部通過屬性間接引用函數,從而把 this 隱式綁定到對象內部屬性所指向的函數(例如上例中的對象 parent 的 child  屬性引用函數 function child(){})。

  • 顯示綁定:需要引用一個對象時進行強制綁定調用,js 有提供 call()、apply() 方法,ES5 中也提供了內置的方法  Function.prototype.bind。

call()、apply() 這兩個函數的第一個參數都是設置 this 對象,區別是 apply 傳遞參數是按照數組傳遞,call  是一個一個傳遞。

function fruit(...args){   console.log(this.name, args); } var apple = {   name: '蘋果' } var banana = {   name: '香蕉' } fruit.call(banana, 'a', 'b')  // [ 'a', 'b' ] fruit.apply(apple, ['a', 'b']) // [ 'a', 'b' ]

下面是 bind 綁定的示例,只是將一個值綁定到函數的 this 上,并將綁定好的函數返回,只有在執行 fruit 函數時才會輸出信息,例:

function fruit(){   console.log(this.name); } var apple = {   name: '蘋果' } fruitfruit = fruit.bind(apple); fruit(); // 蘋果

除了以上 call、apply、bind 還可以通過上下文 context,例:

function fruit(name){   console.log(`${this.name}: ${name}`); } const obj = {   name: '這是水果', } const arr = ['蘋果', '香蕉']; arr.forEach(fruit, obj); // 這是水果: 蘋果 // 這是水果: 香蕉

4. new 綁定

new 綁定也可以影響 this 調用,它是一個構造函數,每一次 new 綁定都會創建一個新對象。

function Fruit(name){   this.name = name; }  const f1 = new Fruit('apple'); const f2 = new Fruit('banana'); console.log(f1.name, f2.name); // apple banana

三、優先級

如果 this 的調用位置同時應用了多種綁定規則,它是有優先級的:new 綁定 -> 顯示綁定 -> 隱式綁定 -> 默認綁定。

四、箭頭函數

箭頭函數并非使用 function 關鍵字進行定義,也不會使用上面所講解的 this 四種標準規范,箭頭函數會繼承自外層函數調用的 this  綁定。

執行 fruit.call(apple) 時,箭頭函數 this 已被綁定,無法再次被修改。

function fruit(){   return () => {     console.log(this.name);   } } var apple = {   name: '蘋果' } var banana = {   name: '香蕉' } var fruitfruitCall = fruit.call(apple); fruitCall.call(banana); // 蘋果

五、This 使用中的幾個常見問題

1. 通過函數和原型鏈模擬類

以下示例,定義函數 Fruit,之后在原型鏈上定義 info 方法,實例化對象 f1 和定義對象 f2 分別調用 info 方法。

function Fruit(name) {   this.name = name; } Fruit.prototype.info = function() {   console.log(this.name); } const f1 = new Fruit('Apple'); f1.info(); const f2 = { name: 'Banana' }; f2.info = f1.info; f2.info()

輸出之后,兩次結果是不一樣的,原因是 info 方法里的 this  對應的不是定義時的上下文,而是調用時的上下文,根據我們上面講的幾種綁定規則,對應的是隱式綁定規則。

Apple Banana

2. 原型鏈上使用箭頭函數

如果使用構造函數和原型鏈模擬類,不能在原型鏈上定義箭頭函數,因為箭頭函數的里的 this 會繼承外層函數調用的 this 綁定。

function Fruit(name) {   this.name = name; } Fruit.prototype.info = () => {   console.log(this.name); } var name = 'Banana' const f1 = new Fruit('Apple'); f1.info();

3. 在事件中的使用

舉一個 Node.js 示例,在事件中使用時,當我們的監聽器被調用時,如果聲明的是普通函數,this 會被指向監聽器所綁定的 EventEmitter  實例,如果使用的箭頭函數方式 this 不會指向 EventEmitter 實例。

const EventEmitter = require('events'); class MyEmitter extends EventEmitter {   constructor() {     super();     this.name = 'myEmitter';   } } const func1 = () => console.log(this.name); const func2 = function () { console.log(this.name); }; const myEmitter = new MyEmitter(); myEmitter.on('event', func1); // undefined myEmitter.on('event', func2); // myEmitter myEmitter.emit('event');

看完上述內容是否對您有幫助呢?如果還想對相關知識有進一步的了解或閱讀更多相關文章,請關注億速云行業資訊頻道,感謝您對億速云的支持。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

永平县| 双江| 杭锦后旗| 汝城县| 吴忠市| 雅江县| 玉溪市| 宁远县| 仁化县| 牙克石市| 武安市| 镇康县| 鱼台县| 黄大仙区| 美姑县| 东丰县| 福贡县| 井陉县| 英德市| 布拖县| 清苑县| 淮南市| 常宁市| 清新县| 增城市| 嘉祥县| 遂平县| 孝感市| 南昌市| 宁陵县| 嵊泗县| 虹口区| 彭水| 仲巴县| 射洪县| 延津县| 古田县| 临城县| 洪江市| 延庆县| 安陆市|