為什麼細微的語法的變化就可以改變this的值?
掃書時看到這句話。背景:
var name = "The Window";
var object = {
name : "My Object",
getName : function(){
return this.name;
}
}object.getName();
(object.getName)();// "My Object"
(object.getName = object.getName)();// "The Window"
第三句先執行了一句賦值語句,為何this的值就發生了改變?
瀉藥
哎
大白話就是
func 在沒call apply bind 的情況下
this 是指 函數調用時候 "點" (「[]」中括弧)前頭那個對象
而函數直接調用時候 (前頭沒點和[])
this 就是全局對象
(object.getName = object.getName)();
賦值語句執行結果是拿到 getName函數
這個函數()執行下
前頭沒點和[]
那 this 就是全局對象
==== 補充 ====
評論里有人問第二個(object.getName)() 解釋不通
話說能看看規範,就別瞎猜了
分組運算符不進行求值(GetValue)
第三個求值是賦值運算符乾的
分組跟他這裡的this改變沒啥關係(不影響)
這個我記得微博上有過這個問題,當時貘大@貘吃饃香已經給了正確的原因...
以下是正經回答:
第三行 『(object.getName = object.getName) 』圓括弧里的內容是AssignmentExpression,它的返回值是『GetValue(等號右邊的表達式)』
注意這個GetValue是規範中的抽象操作,object.getName經過這個GetValue操作之後就不是Reference type了,丟失了它的this信息。
而第二行實際和第一行是一樣的。這個圓括弧在規範中叫grouping operator,它不執行GetValue操作,所以函數調用的時候函數知道自己是通過object進行調用的。
(實際上你可以試一下,『(object.foo) = 1)』是合法的語句)
規範中的相應部分:
[1] 關於函數調用的部分,在這裡你可以看出來function call在不同情況下對this的處理
http://www.ecma-international.org/ecma-262/7.0/index.html#sec-function-calls-runtime-semantics-evaluation
[2] AssignmentExpression的執行過程 http://www.ecma-international.org/ecma-262/7.0/index.html#sec-assignment-operators-runtime-semantics-evaluation
[3] Grouping operator的執行過程 http://www.ecma-international.org/ecma-262/7.0/index.html#sec-grouping-operator-runtime-semantics-evaluation
JavaScript This 的六道坎
誰調用,this 就指向誰。
在 Javascript 中,this的指向一句話就可以說明,不知道為什麼到了部分人的手裡就成了痛點。
在 JS 中,所有的調用都可以看做屬性的調用,函數也是一樣,如果沒有直接調用者,那麼 this 就指向 window。
var name = "The Window";
var object = {
name : "My Object",
getName : function(){
return this.name;
}
}
object.getName();
(object.getName)();// "My Object"
(object.getName = object.getName)();// "The Window"
以上述例子為例,
* object.getName: 調用者為 object
* (object.getName):調用者為 object* object.getName = object.getName, 賦值語句更改了引用,調用者不在是object,但有沒有指定的調用者,所以 this 指向window.所以無論怎麼變,最終只要關注調用者是誰即可。js中的this確實很麻煩,不過我總結了兩條簡單的規則:this屬於哪個函數該函數是如何被調用的
在沒有var、const、let的情況下執行賦值語句,會返回一個值,就是賦值的值。在第三句執行賦值語句後,直接返回getName。再調用就是在window下調用。就跟以下語句等效:
var fn = object.getName; fn() // "The Window"
瀉藥。
關於 this 的指向,記住誰調用函數,它就指向誰。
看上去第三個調用和第二個沒有區別。其實有區別。
object.getName 是一個方法,賦值給 object.getName後,object.getName就是一個函數了,然後在掉用它,this的指向就是 Window了。
把第三句執行的 object.getName 改一下,就不具備那麼迷惑性了
var name = "Window Object";
var object = {
name: "My object",
getName: function getName() {
return this.name;
}
}
var h=object.getName;
h(); //"Window Object"
h; //getName(),h經過賦值,成為一個函數
(p=object.getName)(); //"Window Object"
p; //getName(),p是函數
js的this飄來飄去是日常,強行改變this指向也是日常,習慣了就好。
對於這個第三個賦值語句,本菜雞試著用大白話來回答一下吧:
(object.getName = object.getName)();
對於等號右邊的object.getNamejs會對他進行RHS查詢,就是引擎告訴編譯器試著找object.getName的值,編譯器在object那個作用域找到了,對引擎說:看 !!值是 function(){return this.name}
然後等式的返回值是等式右邊的值於是object.getName = object.getName 返回值就是function (){return this.name} 所以等式就變成了(function (){return this.name})()
引擎接著執行這段,然後告訴編譯器,幫我找找 this.name 是多少?
編譯器這時候會在當前作用域,(全局)下找name ,(試著想在空白js文件中寫入(function(){return this.name})())發現有了,告訴引擎,找到了,是the window ,這時候語句執行完了,返回the window
因為賦值表達式的結果是這個函數。這個函數是返回this.name啊,這this是全局
推薦閱讀:
※在 103 個數中有 50 個數出現了兩次、3 個數出現了一次,如何找出出現了一次的 3 個數?
※產品經理面試題——人人網的?
※項目經理面試問題解析?
※HR 臨時取消面試的真正原因是什麼?
※我準備做銷售,面試需要準備什麼,最厲害的面試技巧是怎樣的?
TAG:JavaScript | 前端入門 | 面試問題 | 閉包 |