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

資訊專欄INFORMATION COLUMN

JavaScript之例題中徹底理解this

Hwg / 824人閱讀

摘要:最后重點理解結論箭頭函數的,總是指向定義時所在的對象,而不是運行時所在的對象。輸出,箭頭函數不會綁定所以傳入指向無效。原因是,要徹底理解應該是建立在已經大致理解了中的執行上下文,作用域作用域鏈,閉包,變量對象,函數執行過程的基礎上。

本文共 2025 字,看完只需 8 分鐘
概述

前面的文章講解了 JavaScript 中的執行上下文,作用域,變量對象,this 的相關原理,但是我后來在網上看到一些例題的時候,依然沒能全做對,說明自己有些細節還沒能掌握,本文就結合例題進行深入實踐,討論函數在不同的調用方式 this 的指向問題。

老規矩,先給結論 1 和 結論2:

this 始終指向最后調用它的對象

“箭頭函數”的this,總是指向定義時所在的對象,而不是運行時所在的對象。

特別提示:
本文的例子,最好自己在瀏覽器控制臺中去試一遍,看完過兩天就會忘的,一定要實踐。

一、隱式綁定
// 例 1
var name = "window";

function foo() {
    var name = "inner";

    console.log(this.name);
}

foo();  // ?

輸出:

window

例 1 中,非嚴格模式,由于 foo 函數是在全局環境中被調用,this 會被默認指向全局對象 window;

所以符合了我們的結論一:

this 始終指向最后調用它的對象
二、一般函數和箭頭函數的對象調用
// 例 2
var name = "window";

var person = {
    name: "inner",
    show1: function () {
        console.log(this.name);
    },
    show2: () => {
        console.log(this.name);
    }
}

person.show1();  // ?
person.show2();  // ?

輸出:

inner  
window

person.show1() 輸出 inner 沒毛病,person.show2() 箭頭函數為什么會輸出 window 呢。MDN 中對 this 的定義是:

箭頭函數不綁定 this, 箭頭函數不會創建自己的this,它只會從自己的作用域鏈的上一層繼承this。

再看本文前面給的結論:

“箭頭函數”的this,總是指向定義時所在的對象,而不是運行時所在的對象。

由于 JS 中只有全局作用域和函數作用域,箭頭函數在定義時的上一層作用域是全局環境,全局環境中的 this 指向全局對象本身,即 window。

三、call
// 例 3
var name = "window"

var person1 = {
  name: "person1",
  show1: function () {
    console.log(this.name)
  },
  show2: () => console.log(this.name),
  show3: function () {
    return function () {
      console.log(this.name)
    }
  },
  show4: function () {
    return () => console.log(this.name)
  }
}
var person2 = { name: "person2" }

person1.show1()  // ?
person1.show1.call(person2)  // ?

person1.show2()  // ?
person1.show2.call(person2)  // ?

person1.show3()()  // ?
person1.show3().call(person2)  // ?
person1.show3.call(person2)()  // ?

person1.show4()()  // ?
person1.show4().call(person2)  // ?
person1.show4.call(person2)()  // ?

輸出:

person1  
person2

window
window

window
person2
window

person1
person1
person2

上面 10 行打印,你對了幾個呢?

首先:
person1.show1()person1.show1.call(person2) 輸出結果應該沒問題,call 的作用就是改變了調用的對象 為 person2

其次:
person1.show2()person1.show2.call(person2),由于調用的是箭頭函數,和本文例 2 中是一樣的,箭頭函數定義時 this 指向的是上一層,也就是全局對象, 并且 箭頭函數不綁定自己的 this, 所以通過 call()apply() 方法調用箭頭函數時,只能傳遞參數,不能傳遞新的對象進行綁定。故打印的值都是 window。

進而:

function foo () {
    return function () {
      console.log(this.name)
    }
  }

foo()();

博客前面的文章有講過閉包,上面這段代碼也是典型的閉包運用,可以看作:

function foo () {
    return function () {
      console.log(this.name)
    }
  }

var bar = foo();
bar();

所以,很明顯,被返回的內部函數其實是在全局環境下被調用的。回到前面看我們的結論 1,this 始終指向最后調用函數的對象,這句話的關鍵詞應該是什么?我覺得應該是 調用,什么時候調用,誰調用。

再回過頭來看:
person1.show3()() 輸出 window,因為內部函數在全局環境中被調用。

person1.show3().call(person2) 輸出 person2, 因為內部函數被 person2 對象調用了。

person1.show3.call(person2)() 輸出 window,也是因為內部函數在全局環境中被調用。

最后:
重點理解結論 2:

“箭頭函數”的this,總是指向定義時所在的對象,而不是運行時所在的對象。
show4: function () {
    return () => console.log(this.name)
  }

這段代碼中,箭頭函數是在 外層函數 show4 執行后才被定義的。為什么?可以翻看我前面關于作用域鏈,執行上下文,變量對象的文章,函數在進入執行階段時,會先查找內部的變量和函數聲明,將他們作為變量對象的屬性,關聯作用域鏈,并綁定 this 指向。

所以:
person1.show4()() 輸出 person1,因為外部函數在執行時的 this 為 person1, 此時定義了內部函數,而內部函數為外部函數的 this。

person1.show4().call(person2) 輸出 person1,箭頭函數不會綁定 this, 所以 call 傳入 this 指向無效。

person1.show4.call(person2)() 輸出 person2,因為外部函數在執行時的 this 為 person2,此時定義了內部函數,而內部函數為外部函數的 this。

四、構造函數中的 this
// 例 4
var name = "window"

function Person (name) {
  this.name = name;
  this.show1 = function () {
    console.log(this.name)
  }
  this.show2 = () => console.log(this.name)
  this.show3 = function () {
    return function () {
      console.log(this.name)
    }
  }
  this.show4 = function () {
    return () => console.log(this.name)
  }
}

var personA = new Person("personA")
var personB = new Person("personB")

personA.show1()  // 
personA.show1.call(personB)  // 

personA.show2()  // 
personA.show2.call(personB)  // 

personA.show3()()  // 
personA.show3().call(personB)  // 
personA.show3.call(personB)()  // 

personA.show4()()  // 
personA.show4().call(personB)  // 
personA.show4.call(personB)()  //

輸出:

personA  
personB

personA
personA

window
personB
window

personA
personA
personB

例 4 和 例 3 大致一樣,唯一的區別在于兩點:

構造函數中 this 指向被創建的實例

構造函數,也是函數,所以存在作用域,所以里面的箭頭函數,它們的 this 指向,來自于上一層,就不再是全局環境 window, 而是構造函數 的 this。

五、setTimeout 函數
// 例 5
function foo(){
  setTimeout(() =>{
    console.log("id:", this.id)
      setTimeout(() =>{
        console.log("id:", this.id)
      }, 100);
  }, 100);
}

foo.call({id: 111});  // 

輸出:

111   
111

注意一點:
setTimeout 函數是在全局環境被 window 對象執行的,但是 foo 函數在執行時,setTimtout 委托的匿名箭頭函數被定義,箭頭函數的 this 來自于上層函數 foo 的調用對象, 所以打印結果才為 111;

六、setTimeout 函數 2
// 例 6
function foo1(){
  setTimeout(() =>{
    console.log("id:", this.id)
      setTimeout(function (){
        console.log("id:", this.id)
      }, 100);
  }, 100);
}


function foo2(){
  setTimeout(function() {
    console.log("id:", this.id)
      setTimeout(() => {
        console.log("id:", this.id)
      }, 100);
  }, 100);
}

foo1.call({ id: 111 });  // ?
foo2.call({ id: 222 });  // ?

輸出:

111  
undefined

undefined
undefined

例 5 中已經提到,setTimeout函數被 window 對象調用,如果
是普通函數,內部的 this 自然指向了全局對象下的 id, 所以為 undefined,如果是箭頭函數,this 指向的就是外部函數的 this。

七、嵌套箭頭函數
// 例 7
function foo() {
  return () => {
    return () => {
      return () => {
        console.log("id:", this.id);
      };
    };
  };
}

var f = foo.call({id: 1});

var t1 = f.call({id: 2})()();  // 
var t2 = f().call({id: 3})();  // 
var t3 = f()().call({id: 4});  // 

輸出:

1  
1
1

這段代碼是為了鞏固我們的結論2:

“箭頭函數”的this,總是指向定義時所在的對象,而不是運行時所在的對象。

foo.call({}) 在執行時,內部的第一層箭頭函數才被定義

箭頭函數無法綁定 this, 所以 call 函數指定 this 無效

箭頭函數的 this 來自于上一層作用域(非箭頭函數作用域)的 this

總結

有本書中有提到,當理解 JavaScript 中的 this 之后,JavaScript 才算入門,我深以為然。

原因是,要徹底理解 this, 應該是建立在已經大致理解了 JS 中的執行上下文,作用域、作用域鏈,閉包,變量對象,函數執行過程的基礎上。

有興趣深入了解上下文,作用域,閉包相關內容的同學可以翻看我之前的文章。

參考鏈接:

1:this、apply、call、bind
2: 從這兩套題,重新認識JS的this、作用域、閉包、對象
3: 關于箭頭函數this的理解幾乎完全是錯誤的
4: 深入JS系列

歡迎關注我的個人公眾號“謝南波”,專注分享原創文章。

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

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

相關文章

  • JS專題數組去重

    摘要:將元素作為對象的鍵,默認鍵對應的值為如果對象中沒有這個鍵,則將這個元素放入結果數組中去。 前言 數組去重在日常開發中的使用頻率還是較高的,也是網上隨便一抓一大把的話題,所以,我寫這篇文章目的在于歸納和總結,既然很多人都在提的數組去重,自己到底了解多少呢。又或者是如果自己在開發中遇到了去重的需求,自己能想到更好的解決方案嗎。 這次我們來理一理怎么做數組去重才能做得最合適,既要考慮兼容性,...

    only_do 評論0 收藏0
  • JavaScript函數調用的經典例題

    摘要:第二問直接調用函數,相當于調用,那么與函數無關。第三問先執行了函數,然后調用函數的返回值對象的屬性函數。第四問再次調用函數時,此時函數已經被第三問執行時修改,所以結果為。 JavaScript函數調用的經典例題 很多初學JavaScript的人對函數的調用理解有些模糊的,話不多說,直接上題: function Foo() { getName = function...

    cyqian 評論0 收藏0
  • 面向對象的 JavaScript

    摘要:是完全的面向對象語言,它們通過類的形式組織函數和變量,使之不能脫離對象存在。而在基于原型的面向對象方式中,對象則是依靠構造器利用原型構造出來的。 JavaScript 函數式腳本語言特性以及其看似隨意的編寫風格,導致長期以來人們對這一門語言的誤解,即認為 JavaScript 不是一門面向對象的語言,或者只是部分具備一些面向對象的特征。本文將回歸面向對象本意,從對語言感悟的角度闡述為什...

    novo 評論0 收藏0
  • javascript對象不完全探索記錄01:this! which?

    溫馨提示:作者的爬坑記錄,對你等大神完全沒有價值,別在我這浪費生命 這一切,源于阮大神博文學習Javascript閉包(Closure)- 阮一峰中的一道思考題 //問題1: var name = The Window; var object = {   name : My Object,   getNameFunc : function(){     return function(){    ...

    rubyshen 評論0 收藏0
  • JavaScript深入淺出

    摘要:理解的函數基礎要搞好深入淺出原型使用原型模型,雖然這經常被當作缺點提及,但是只要善于運用,其實基于原型的繼承模型比傳統的類繼承還要強大。中文指南基本操作指南二繼續熟悉的幾對方法,包括,,。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。 怎樣使用 this 因為本人屬于偽前端,因此文中只看懂了 8 成左右,希望能夠給大家帶來幫助....(據說是阿里的前端妹子寫的) this 的值到底...

    blair 評論0 收藏0

發表評論

0條評論

Hwg

|高級講師

TA的文章

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