function fn();
return this;
fn.getname =function ();
fn.portotype.getname = function ();
var getname = function ();
function getname();
//請寫出以下輸出結果:
fn.getname();
getname();
fn().getname();
getname();
new fn.getname();
new fn().getname();
new new fn().getname();
此題涉及的知識點眾多,包括變數定義提公升、this指標指向、運算子優先順序、原型、繼承、全域性變數汙染、物件屬性及原型屬性優先順序等等。
此題包含7小問,分別說下:
第一問先看此題的上半部分做了什麼,首先定義了乙個叫fn的函式,之後為fn建立了乙個叫getname的靜態屬性儲存了乙個匿名函式,之後為fn的原型物件新建立了乙個叫getname的匿名函式。之後又通過函式變數表示式建立了乙個getname的函式,最後再宣告乙個叫getname函式。
第一問的fn.getname自然是訪問fn函式上儲存的靜態屬性,自然是2,沒什麼可說的。
第二問第二問,直接呼叫getname函式。既然是直接呼叫,那麼就是訪問當前上文作用域內的叫getname的函式,所以1 2 3都沒什麼關係。此題有無數面試者回答為5。此處有兩個坑,一是變數宣告提公升,二是函式表示式。
變數宣告提公升:
即所有宣告變數或者宣告函式都會被提公升到當前函式的頂部。
例如下**:
console.log('a' in window);//true
var a;
a=0;
**執行時js引擎會將宣告語句提公升至**最上方,變為:
var a;
console.log('a' in window);//true
a=0;
函式表示式:
var getname與function getname都是宣告語句,區別在於var getname是函式表示式,而function getname是函式宣告。關於js中的各種函式建立方式可以看 大部分人都會做錯的經典js閉包面試題 這篇文章有詳細說明。
函式表示式最大的問題,在於js會將此**分拆為兩行**分別執行。
例如下**:
console.log(a);//輸出:function a(){}
var a=1;
function a(){}
實際執行的**為,先將var a=1拆分為var a;和a=1;兩行,再將var a;和function a(){}兩行提公升至最上方變成:
var a;
function a(){}
console.log(a);
x=1;
所以最終函式宣告的a覆蓋了變數宣告的a,log輸出為a函式。
同理,原題中**最終執行時的是:
function fn();
return this;
var getname;//只提公升變數宣告
function getname();//提公升函式宣告,覆蓋var的宣告
fn.getname = function ();
fn.prototype.getname = function();
getname = function();//最終的賦值再次覆蓋function getname宣告
getname();//最終輸出4
第三問第三問的fn().getname();先執行了fn函式,然後呼叫fn函式的返回值物件的getname屬性函式。
fn函式的第一句getname = function();是一句函式賦值語句,注意它沒有var宣告,所以先向當前fn函式作用域內尋找getname變數,沒有。再向當前函式作用域上層,即外層作用域內尋找是否含有getname變數,找到了,也就是第二問中的alert(4)函式,將此變數的值賦值為function()。
此處實際上是將外層作用域內的getname函式修改了。
注意:此處若依然沒有找到會一直向上查詢到window物件,若window物件中也沒有getname屬性,就在window物件中建立乙個getname變數。
之後fn函式的返回值是this,而js的this問題中已經有非常多的文章介紹,這裡不再多說。
簡單地講,this的指向是由所在函式的呼叫方式決定的。而此處的直接呼叫方式,this指向window物件。
遂fn函式返回的是window物件,相當於執行window.getname(),而window中的getname已經被修改為alert(1),所以最終會輸出1.
此處考察了兩個知識點,乙個是變數作用域問題,乙個是this指向問題。
第四問直接呼叫getname函式,相當於window.getname(),因為這個變數已經被fn函式執行時修改了,遂結果與第三問相同,為1.
第五問new fn.getname();,此處考察的是js的運算子優先順序問題。實際上將getname函式作為了建構函式來執行,遂彈出2.
第六問new fn().getname();,首先看運算子優先順序括號高於new,實際執行為(new fn()).getname();
遂先執行fn函式,而fn此時作為建構函式卻有返回值,原題中,返回的是this,而this在建構函式中本來就代表當前例項化物件,遂最終fn函式返回例項化物件。
之後呼叫例項化物件的getname函式,因為在fn建構函式中沒有為例項化物件新增任何屬性,遂到當前物件的原型物件(prototype)中尋找getname,找到了。
遂最終輸出3.
第七問new new fn().getname();,同樣是運算子優先順序問題。
最終實際執行為:
new (new fn()).getname();
先初始化fn的例項化物件,然後將其原型上的getname函式作為建構函式再次new。
遂最終結果為3.
每日進步一點點 偏函式的學習使用
usr bin env python coding utf 8 devversion python3.6.8 date 2021 11 16 22 39 pycharm test from functools import partial 偏函式的學習 1.解決某些方法呼叫只能傳函式名,但傳的函式需...
每天進步一點點
很多朋友總喜歡問 成功靠什麼?其實,成功很難單一的歸納為靠什麼條件,如果一定要回答,只能從某種意義上說 很多人的成功就是靠他們每天比別人 多做一點點 正如古人有云 業精於勤,荒於嬉。這裡所說的勤,也就是比別人多做一點點,即付出多一點的勞動和努力。不要小看這一點點,又如古語說 集腋成裘,積沙成丘。如果...
每天進步一點點
在模組化程式設計時,在子模組中宣告變數 例如unsigned char aa 不需要在標頭檔案中宣告 要在主函式中呼叫,要寫成 extern unsigned char aa 而不能寫成 extern aa 寫成extern aa 則無法改變aa的值。2014年9月22日 21 12 00 品質因數...