國外最具爭議的十三道 JavaScript 題,你能全做對嗎?

題目一

——————————


(function(){

return typeof arguments;

})();

答案:“object”

arguments是對象,僞數組有兩件事要注意這裏:

參數不是數組,它是一個數組一樣的物體,你可以使用方括號和整數索引的元素,但方法通常可在一個如推上不存在參數數組
Array.prototype.slice.call(arguments); 轉成數組,當然arguments即使是數組,返回的依然是”object”,因爲數組也是對象。
附加:typeof 對類型的判斷

https://developer.mozilla.org/zh-CN/docs/JavaScript/Reference/Operators/typeof

題目二

——————————


var f = function g(){ return 23; };

typeof g();

答案:會發生錯誤

因爲function g(){ return 23; }是函數表達式,事實上只有事一個名字,不是一個函數聲明

函數實際上是綁定到變量f,不是g。

指定的標識符在函數表達式雖然有其用途:堆棧跟蹤是清晰而不是充斥着無名的函數,你可以有一個匿名函數遞歸調用本身不使用argument.callee

附非常詳細的帖子函數表達式,http://kangax.github.io/nfe/

題目三

——————————


(function(x){

delete x;

return x;

})(1);

答案:1

題目四

——————————


var y = 1, x = y = typeof x;

x;

答案:”undefined”

通過重寫代碼如下結果:

var a, b; 展開就是 var a; var b;.

A = B = C;相當於 B = C = B;
知道了這一點,我們重寫並得到:



var y = 1;

y = typeof x;

var x = y;

x;

當執行,y = typeof x時,x 還沒有被定義,所以y成爲字符串”undefined”,然後被分配到x。

題目五

——————————


(function f(f){

return typeof f();

})(function(){ return 1; });

答案:”number”

爲了便於理解我們繼續分解:

第一部分


var baz = function(){ return 1; };

第二部分


(function f(f){

return typeof f();

})(baz);

在這裏,函數f接受一個參數是另一個函數,f函數內部執行這個實參函數並且返回類型

無論是從調用該函數返回,即使參數名稱f與函數名衝突,函數接受本身作爲自己的參數,然後調用,此時就看誰更具有更高的優先級了,顯然,參數的優先級更高,所以實際執行的是return typeof 1

題目六

——————————


var foo = {

bar: function() { return this.baz; },

baz: 1

};

(function(){

return typeof arguments[0]();

})(foo.bar);

答案: “undefined”

爲什麼是”undefined”?我們必須要知道this運算符是怎麼工作的。

JS語言精粹總結的很精煉:

1 純粹的函數調用

2 作爲對象方法的調用

3 作爲構造函數調用

4 apply調用

我們看看題目是屬於那種環境?

在arguments0中執行了一個方法,arguments[0]就是foo.bar方法,注意:這在foo.bar中的this是沒有綁定到foo。雖然 foo.bar 傳遞給了函數,但是真正執行的時候,函數 bar 的上下文環境是 arguments,並不是 foo。

arguemnts[0] 可以理解爲 arguments.0(不過寫代碼就不要這樣了,語法會錯誤的),所以這樣看來,上下文環境是 arguemnts 就沒問題了,所以在執行baz的時候自然this就是window了,window 上沒有baz屬性,返回的就是undefined,typeof調用的話就轉換成”undefined”了。

題目七

——————————


var foo = {

bar: function(){ return this.baz; },

baz: 1

}

typeof (f = foo.bar)();

答案 “undefined”

繼續改寫一下:


var foo = {

bar: function(){ return this.baz; },

baz: 1

}

f = foo.bar;

typeof f();

把foo.bar存儲給f然後調用,所以this在foo.bar引用的是全局對象,所以就沒有baz屬性了。換句話說,foo.bar執行的時候上下文是 foo,但是當 把 foo.bar 賦值給 f 的時候,f 的上下文環境是 window ,是沒有 baz 的,所以是 ”undefined”。

題目八

——————————


var f = (function f(){ return "1"; }, function g(){ return 2; })();

typeof f;

答案 “number”

逗號操作符的使用可以很混淆,但這段說明它的行爲:


var x = (1, 2, 3);

x;

x的值是3,這表明,當你有一系列的組合在一起,並由逗號分隔的表達式,它們從左到右進行計算,但只有最後一個表達式的結果保存。由於同樣的原因,這個問題可以改寫爲減少混亂:


var f = (function g(){ return 2; })();

typeof f;

題目九

——————————


var x = 1;

if (function f(){}) {

x += typeof f;

}

x;

答案 “1undefined”

這裏有個難點,if 中的 function f(){} 要如何處理?函數聲明的實際規則如下:

函數聲明只能出現在程序或函數體內。從句法上講,它們 不能出現在Block(塊)({ … })中,例如不能出現在 if、while 或 for 語句中。因爲 Block(塊) 中只能包含Statement語句, 而不能包含函數聲明這樣的源元素。另一方面,仔細看一看規則也會發現,唯一可能讓表達式出現在Block(塊)中情形,就是讓它作爲表達式語句的一部分。但是,規範明確規定了表達式語句不能以關鍵字function開頭。而這實際上就是說,函數表達式同樣也不能出現在Statement語句或Block(塊)中(因爲Block(塊)就是由Statement語句構成的)。

假設代碼我們不妨變一下:


var x = 1;

if (function(){}) {

x += typeof f;

}

x;

var x = 1;

x += typeof f;

x;

f在這了沒有被定義,所以typeof f 是字符串”undefined” ,字符與數字相加結果也是一個字符串,所以最後的x就是”1undefined”了。

題目十

——————————


(function f(){

function f(){ return 1; }

return f();

function f(){ return 2; }

})();

答案 2

如果是一直看下來的話,這個題目應該是比較簡單。簡單的來說在執行return之前,函數聲明會在任何表達式被解析和求值之前先被解析和求值,即使你的聲明在代碼的最後一行,它也會在同作用域內第一個表達式之前被解析/求值。

參考如下例子,函數fn是在alert之後聲明的,但是在alert執行的時候,fn已經有定義了


 alert(fn());

function fn() {

return 'Hello world!';

}

所以題目中函數提升了兩次,第二次把第一次覆蓋了,所以 return 後面的 f 是 return 語句的下一條語句聲明的函數 f 。注意自執行函數 (function f (){})(); 中的 f 並沒有函數提升效果,它是表達式。

題目十一

——————————


function f(){ return f; }

new f() instanceof f;

答案 false

怎樣去理解?

new f() , 首先這個操作會創建一個新對象並調用構造函數函數這一新的對象作爲它的當前上下文對象。簡單的說 ,

new f();

依稀記得高級程序設計裏面是這麼說的:

1 創建空對象。

2 將類的prototype中的屬性和方法複製到實例中。

3 將第一步創建的空對象做爲類的參數調用類的構造函數

默認如果沒有覆蓋這個空對象的話,返回this

var a = new Object;

a instanceof Object 爲 true
我們在看 f() 返回了 return f;那麼也就是說這個新的對象是是自身,構造函數本身在 new 的過程中會返回一個表示該對象的實例。但是函數的返回值覆蓋了這個實例,這個new 就形同虛設。果f的形式爲 function f(){return this}或function f(){}就不一樣。


var a = new f();

a instanceof f  // false

值得注意的是 instanceof 檢測的是原型。

題目十二

——————————


  var x = [typeof x, typeof y][1];

typeof typeof x;

這題目比較簡單,注意下返回類型即可。x = [,][1];即 x = typeof y = ‘undefind’。

typeof 返回的是string類型就可以了 ,typeof typeof必然就是’string’了。

題目十三

——————————


function(foo){

return typeof foo.bar;

})({ foo: { bar: 1 } });

答案 “undefined”

又是一個噁心的題目,純文字遊戲,大家看仔細看。

先分解一下


var baz = { foo: { bar: 1 } };

 

(function(foo){

return typeof foo.bar;

})(baz);

去掉函數關聯



var baz = { foo: { bar: 1 } };

var foo = baz;

typeof foo.bar;

最後,通過替代我們除去中間變量foo


var baz = { foo: { bar: 1 } };

typeof baz.bar;

所以現在就很清晰了,屬性中沒有定義baz;它被定義爲baz.foo上了,所以結果是:”undefined”。

自己是一名從事了6年開發的老程序員,業餘的時候在這裏分享一些互聯網資訊給大家,不少人私下問我,2019年前端該怎麼學,方法有沒有?

沒錯,年初我花了一個多月的時間整理出來的學習資料,希望能幫助那些想學習前端,卻又不知道怎麼開始學習的朋友。

這裏推薦一下我的前端學習交流q羣:767273102 ,裏面都是學習前端的從最基礎的HTML+CSS+JS【炫酷特效,遊戲,插件封裝,設計模式】到移動端HTML5的項目實戰的學習資料都有整理,送給每一位前端小夥伴。2019最新技術,與企業需求同步。好友都在裏面學習交流,每天都會有大牛定時講解前端技術!

點擊:加入

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章