關於JS中this作為方法調用?

在學習JS時遇到了下面這段代碼:

運行結果為後面注釋,百度上告訴我這是this作為方法被調用,但是有一些不解。以下是本人猜想:

①o.sayColor=sayColor;

這行代碼意思是「相當於給o對象新添加一個名為sayColor的屬性,屬性的值為sayColor函數」?

②o.sayColor();

這是把o對象的sayColor屬性當作方法調用的嗎?

為了證實②的猜想,我在想,是不是上面的sayColor();這段代碼也是被當作某個對象的方法來調用的,而毫無疑問,sayColor();的對象是window。

於是,我把sayColor();改為window.sayColor();,得到的結果和sayColor()的結果相同。不知道是不是驗證了②的猜想。

另外,我在搜索關於this的調用方法時,看到一句話:this指的是包含它的函數作為方法被調用時所屬的對象。

結合好幾個例子,我發現這句話的確挺有道理,不知道各位大神怎麼認為?

以上就是我的全部問題,主要是希望有大神幫我驗證。。。

PS:①本人剛接觸JS沒多久,可能提出的問題比較小白,望見諒。

②代碼出自《JS高程3》,P114。

鞠躬,不勝感激!


window.sayColor()的時候this是window

o.sayColor()的時候this是o

在瀏覽器裡面,當你沒有明確指定this是誰的時候,this就是window。

再加上

window.color == "red"

o.color == "blue"

這也沒什麼難以理解的。


實例化的對象中,this指的是對象本身;未實例化中,this指的是實際調用者的對象。

算是一種比較簡便的判斷this含義的思路。

關於你的猜想,現階段的確可以這麼理解。即:o對象執行了一個獲取該對象color屬性值的方法。


如果只針對你說的這兩句話,樓上很多答案都有說過原因了。

對應規範裡面的解釋,正好你這個問題就是我在 根治JavaScript中的this-ECMAScript規範解讀 - leon lee的文章 - 知乎專欄 文章實戰篇中對應的兩種情況:

  • foo();
  • foo.bar();

如果你希望刨根知底,一勞永逸,可以再去看看這篇文章,正如 @魯小夫 所說,這篇文章裡面遠不能覆蓋到this的方方面面,但是如果你能學到如何從規範中尋找答案,以後這種問題就都能自己搞定了。


這個案例中,或許用 this 指向中的就近原則來解釋可能會更好一點。

在對象方法中的 this,this 的綁定只受最靠近的成員引用的影響,總結就是就近原則。

舉個非嚴格模式下的栗子:

function sayNmae() {
console.log(this.name);
}
let obj = {
aa: {
name: "aa",
sayNmae: sayNmae,
bb: {
name: "bb",
sayNmae: sayNmae,
cc: {
name: "cc",
sayNmae: sayNmae
}
}
}
};

obj.aa.sayNmae(); // aa
obj.aa.bb.sayNmae(); // bb
obj.aa.bb.cc.sayNmae(); // cc

不知道這麼說題主理解沒有。

剛好最近寫了一篇博客:不愛吃西紅柿的魚的博客

防炸預警。

絕大部分都是來自this - JavaScript | MDN,只做了點微小的工作,謝謝大家。


lz如果能深入了解下JS引擎就能有點理解了

JS代碼在運行時需要設置

1. 全局執行棧(ECStack)用數組表示和全局執行環境(EC),並將EC壓棧

2. 全局對象GO(主要是系統內置的對象如String,Number等)

GO = {

String: {},

...,

window: this

}

3. 創建於EC關聯的全局變數對象(VO),它有指針指向GO,同時包含全局變數和函數的定義

注意函數定義時其內部的[[Scope]]屬性指向其定義所在的執行環境

則ECStack = [

EC(G) = {

VO(G):{

GO,

o: {color:true},

sayColor : function sayColor() {...},

sayColor[[Scope]]: this//this為VO(G)

}

]

執行函數sayColor()

1.創建函數執行環境EC(sayColor)並將其壓入ECStack(此時處於棧頂)

2.創建函數sayColor的作用域鏈(prototype鏈)用於查找變數等標識符,初始化為當前函數[[Scope]]所指向對象

3.創建函數活動對象AO(sayColor) 包含函數中變數或函數定義(處理方式同全局方式3)並插入作用域鏈頂端

此時ECStack = [

EC(sayColor) = {

[[Scope]]: VO(G),

AO(sayColor): {

arguments:[],

this:window

},

scopeChain: &

},

EC(G): {

...

}

]

可以發現此時this為window對象

對於o.sayColor()注意其this指向o對象本身

總結一條就是this指向函數調用棧的次一級(最低為全局(瀏覽器內是window)對象)

如果改為

function test(fn) {

return fn();

}

test(o.sayColor);//red

lz可以試一下,注意test()在調用結束後會從ECStack刪除

因而在運行o.sayColor()之前調用棧為ECStack = [EC(sayColor), EV(G)],

其this指向window


其實判斷「this指的是什麼」有四個規則,分別是new Binding、explicit binding、implicit binding和default binding。而這裡用到最後兩種隱式綁定(優先順序第三)和默認綁定(優先順序最低)。

o.sayColor()由於被o調用,所以this指向o。

window.sayColor()同o.sayColor(),this指向window。

這兩個都是隱式綁定,this指向調用該函數的對象。

而sayColor()由於沒有隱式綁定,所以默認綁定規則生效,簡單來說,在非strict模式下這裡this指全局對象,strict模式下為undefined。

隱式綁定有個地方要注意的,就是上面說到o.sayColor()輸出為blue,但是如果是使用var say = o.sayColor; say(); 的話,那輸出就是red了。

此外的Explicit binding則是由call和apply等指定this具體的指代對象。優先順序排第二。有趣的是一旦通過這層綁定,後續再調用this也會指向剛才指定的對象。

而最高的就是new binding了。通過new產生的對象自動綁定this到該對象身上,如果沒有特殊處理的話。

this還有其他很多內容。總之,this非常有趣!


謝邀。

this 是 JS 中最複雜的內容,涉及到函數、函數調用、eval 、call/apply/bind、基本包裝類型、構造函數實例化、嚴格模式等等方方面面,蔚為大觀。

而 ES6 引入的 arrow functionclass 更是把 this 複雜化了。

昨天我看到 @leon lee 為此寫了一篇專欄,雖然內容很好,但依然沒能覆蓋到關於 this 的方方面面。

根治JavaScript中的this-ECMAScript規範解讀 - leon lee的文章 - 知乎專欄

網上關於 this 的文章也是千千萬萬,其中不乏錯漏之處。

就是開車多年的老司機,也難免在關於 this 的一些邊邊角角上翻車。

所以在這個問題上,我已經不指望能靠教程、科普把初學者掰過來了,我也不推薦任何此類文章。

我的建議就是,先啃完 《JavaScript 高級程序設計》(第三版),英文版風味更佳,把 ES3、ES5 中的內容消化掉,再看看 ES6 in depth,這就差不多了。

初學者要想紮實地掌握 JS ,除了看權威和全面一點的書之外,沒有捷徑。

在基礎不紮實的情況下,去看那些水平層次不齊的網文和博客都只會擾亂你的思考,而直接去看規範又是千頭萬緒、細密繁瑣。

只能等 《JavaScript 高級程序設計》 更新第四版,把 ES 後續的內容補足,可能會有一個全面的梳理。

相關內容:

《JavaScript高級程序設計(第4版)》什麼時候出版? - 魯小夫的回答

《javascript高級程序設計》能先跳過第六章面向對象和第七章函數表達式,然後看BOM和DOM嗎? - 魯小夫的回答

《JavaScript高級程序設計》 第 18 章 JavaScript 與 XML太暈了怎麼辦? - 魯小夫的回答

為什麼不能直接把一個原型對象賦給另一個原型對象?看JavaScript高級程序設計的疑問 - 魯小夫的回答

ES6 In Depth Articles
Mozilla Hacks


嚴格模式下情況已經不太一樣,直接定義的函數如果不指明 this,會變成 undefined。

咱們還是跟著潮流走吧。


this是運行時當前對象的指代。

通常的錯誤出現在定義時與運行時的差別。

以問題例子看。

js中默認的this為window。

如果直接調用saycolor()。會在當前運行對象中查找saycolor(),所以是window.saycolor()。這是this.color.為red。

o.saycolor(),這裡調用對象o的saycolor。那麼

this會從window轉換為o。然後在當前運行對象o中查找saycolor。所以是o.saycolor()。this.color為blue。函數調用返回後this切換會window。

點語法(.)會切換運行時當前對象。將運行時當前對象壓棧,點語法執行完後,彈出當前運行時對象,獲取上個運行時對象。


理解調用的Env

多多畫這樣的圖

圖來自於 Structure and Interpretation
of Computer Programs


開始學的時候就簡單點記吧,this指代的就是調用函數的對象

sayColor() 是全局的方法,就是window.sayColor()

o.sayColor是對象o的方法,

你要確定this指代的是誰 你就看方法的.前面的對象就可以了


記住一點,this 指向當前調用的對象。


請參考 "js權威指南" 隨便哪一版

js在運行的時候,會有一個全局對象,對於瀏覽器來說這個全局對象就是window。

聲明的全局變數,函數什麼的都會成為他的屬性或方法,所以能寫window.saycolor()

把函數賦給對象相當於給對象添加方法

this的作用域就是它所在的對象


直接在全局中調用 sayColor()時,sayColor的this-&>window(非嚴格模式下),

因此this.color===window.color-&>"red"

當o.sayColor()調用時,調用位置有上下文(context),被某個對象(o)"擁有"或者"包含",會隱式綁定到這個上下文對象

此時o.sayColor()-&>this.color===o.color-&>"blue"


你就記住誰調用就指向誰,反正你如果想徹底弄明白,你需要把js裡面一些比較容易混的地方都徹底弄懂,作用域阿,執行上下文阿什麼的,而且js這門語言還和c. Java不一樣,總之你就多讀那本高程3就對了,你能想到的所有令你疑惑的問題那本書里基本上都有很好的解釋了


this指的是當前環境對象 關於環境對象建議回頭看看高程第四章的內容


可以看下 Mozilla 的官方文檔,this - JavaScript

它把使用到的場景都介紹的很清楚了 ,主要是

  • Global context
  • Function context

  • Arrow functions

  • As an object method

  • As a constructor

  • call and apply

  • The bind method

  • As a DOM event handler

  • In an in–line event handler

看完這些基本就都清楚了


我最近開始看了Javascript,剛看了倆月。有些觀點可能有出入的地方多包涵吶。

回答問題:

第四行,在那個sayColor()的函數中,它僅僅是在定義而已,它沒被實例化成對象,也沒運行。所以誰調用它,裡面那個this就指代誰(的上下文)。

問題①:對沒錯。當屬性是函數的時候,我們稱這個屬性為「方法」。

問題②:對,不過描述得有點怪,它就是方法,不需要「當做」方法。

當調用函數而沒指定對象的時候,就默認是在全局對象下調用,瀏覽器的全局對象就是window。

this我覺得是指代一種上下文,就像你這個返回顏色的函數,我總得知道你想要的是誰的顏色的吧?這個「誰」就由this來給出啦。如果你要把你這段函數alert(this.color)裡面的this刪掉了,那它運行的時候,它就只能默認你想要的是全局對象下的color屬性,就總是返回window.color了。

另外後面兩行可以簡化為:sayColor.apply(o); 這樣就不用非得讓o多一個sayColor方法啦。


看來你需要這篇博客 深入理解函數之動態的this - MaoTr - 博客頻道 - CSDN.NET


1.把apply函數仔細看看,第一個參數就是你能用的this。

2.你可以認為所有函數都被用apply方式調用。

3.你可以認為你的所有代碼都在一個大函數里。

4.現在簡單了,無非就是傳哪個東西作為this,把你能調用函數的方式各寫一個,跑一下全明白了。


你應該理解形參和實參吧?

this是一個隱藏的、預設為window對象的形參。js提供五種語法來指定調用函數時傳遞給this的實參:

func()

// window被傳遞給this

obj.func(...)

// obj被傳遞給this

func.call(obj, ...)

// 顯式指定obj傳遞給this

func.apply(obj, [...])

// apply是call的爸爸

func_for_only_obj=func.bind(obj)

// copy一個func,但不管怎麼調,this都是obj


this如果在對象裡邊,我都當做c++的this。

不在對象裡邊,就是對象包含這個對象的那個東西(可以是對象,系統,巴拉巴拉的)


個人理解,A調用了B,那麼B裡面的this就指向A。B如果是全局函數,那麼B中的this指向window。錯了就刪。


推薦閱讀:

如何評價 TypeScript 1.7?
npm、bower、jamjs 等包管理器,哪個比較好用?
js 數組賦值問題 :值傳遞還是引用?
在自學前端,但是沒有什麼實踐的資源,大家來推薦一下論壇或者別的可供練習的資源吧?
JS立即執行如何使用?還是說圓括弧本身是用來改變JS的執行上下文環境?

TAG:前端開發 | JavaScript | 編程 |