function Foo(){ getName = function () {alert(1);} return this; } Foo.getName = function() {alert(2);}; Foo.prototype.getName = function(){alert(3);}; var getName = function(){alert(4);}; function getName(){alert(5)}; Foo.getName(); getName(); Foo().getName(); getName(); new Foo.getName(); new Foo().getName(); new new Foo().getName();
2 ----Foo.getName(); 4 ----getName(); 1 ----Foo().getName(); 1 ----getName(); 2 ----new Foo.getName(); 3 ----new Foo().getName(); 3 ----new new Foo().getName();
爲了閱讀效益最大化,請先了解執行環境
和變量對象
的文字性
概念。html
執行環境
挺常見的,它是長這樣的。它的特性是先進後出(stack)。函數
上述圖片是來源於代碼執行到Foo( ).getName( )。this
(anonymous function) 其實就是global context
spa
表示方法:prototype
ECStack = [ functionContext(Foo), /*這不是函數*/ GlobalContext ]
變量對象
也挺常見,在Chrome中長這樣。指針
表示方法一般是:code
//以上述代碼還沒有執行時爲例 VO = { Foo: { <reference to function>, return this } getName: <reference to function> }
代碼執行有兩個階段htm
進入環境(代碼未執行,已編譯)對象
代碼執行blog
如今一塊兒來看看每一行代碼的執行
上述代碼未執行時,變量對象是這樣的。
VO = { Foo: { <reference to function>, return this } getName: <reference to function(){alert(5)}> }
該行代碼執行後VO會變成這樣。
VO = { Foo: { <reference to function>, getName: <reference to function() {alert(2)}, return this } getName: <reference to function(){alert(5)}> }
VO的Foo圖示是這樣的
該行代碼執行後VO會變成這樣。
VO = { Foo: { <reference to function>, getName: <reference to function() {alert(2)}, prototype: { getName: <reference to function(){alert(3)} }, return this, } getName: <reference to function(){alert(5)}> }
VO的Foo圖示是這樣
該行代碼執行後VO會變成這樣。
VO = { Foo: { <reference to function>, getName: <reference to function() {alert(2)}, prototype: { getName: <reference to function(){alert(3)} }, return this } getName: <reference to function(){alert(4)}> }
直接去VO裏尋找結果發現alert 2。
getName() //等於 window.getName();
一樣直接在VO裏能夠直接找到答案 alert 4。
這裏比上述多了一個函數調用,Foo()調用返回this(指向window),因此此時
Foo().getName(); //等於 window.getName()
同時注意:
因爲Foo()調用,致使VO發生了變化。最後alert 1.
VO = { Foo: { <reference to function>, getName: <reference to function() {alert(2)}, prototype: { getName: <reference to function(){alert(3)} }, return this } getName: <reference to function(){alert(1)}> }
結果同上
最後三問考察了new、屬性訪問符、及函數調用優先順序和new運算符的做用。
優先順序
參考以下,或點這
不管是用哪一種屬性訪問表達式,在"."和"[]"以前的表達式老是會先計算的。
對於new Foo.getName()
來講,點運算級最高,因此先進行計算表達式
Foo的值。若是先運算new的話,就證實了new優先級高於點號,與規範不和。
而對於new Foo().getName()
來講,Foo()與new Foo()相比,new優先級更高,因此先算new Foo(),new出來的新對象繼承
了Foo.prototype屬性,所以新對象訪問getName時會彈出3.
此處要明白new的做用
建立新的空對象
將新對象繼承構造函數的prototype屬性,並調用構造函數初始化
將構造函數的this指針指向新建對象。
最後一個問題同理倒數第二個。
謝謝ID:李衛
的提醒。