javascript中那些折磨人的面試題

前端工程師有時候面試時會遇到一類面試官,他們問的問題對於語言自己很是較真兒,每每不是候選人可能期待的面向實際的問題(有些候選人強調能幹活就行,至於知不知道其中原因是無關痛癢的)。這類題目,雖然沒有邏輯,但某種程度說,確實考察了候選人對於javascript這門語言的理解。javascript

忽然想到這個話題是無聊在翻本身的Github,看看之前都寫過什麼醜貨。而後翻到了這篇解釋Javascript quiz的文章quiz-legend,反正沒事兒,就想搬過來供你們學習、理解、背誦、批判。前端

問題一

(function(){
    return typeof arguments;//"object"
})();

arguments是一個Array-like對象,對應的就是傳入函數的參數列表。你能夠在任何函數中直接使用該變量。java

typeof操做符只會返回string類型的結果。參照以下列表可知對應不一樣數據,typeof返回的值都是什麼:git

類型 結果
undefined 'undefined'
null 'object'
Boolean 'boolean'
Number 'number'
String 'string'
Symbol (new in ECMAScript 2015) 'symbol'
Host object (provided by the JS environment) Implementation-dependent
Function object (implements [[Call]] in ECMA-262 terms) 'function'
Any other object 'object'

由此咱們推斷出,typeof argumentsobjectgithub

問題二

var f = function g(){ return 23; };
typeof g();//報錯

這是一個名字是gfunction expression,而後又被賦值給了變量f面試

這裏的函數名g和被其賦值的變量f有以下差別:express

  • 函數名g不能變更,而變量f能夠被從新賦值數組

  • 函數名g只能在函數體內部被使用,試圖在函數外部使用g會報錯的前端工程師

問題三

(function(x){
    delete x;
    return x;//1
})(1);

delete操做符能夠從對象中刪除屬性,正確用法以下:ide

delete object.property
delete object['property']

delete操做符只能做用在對象的屬性上,對變量和函數名無效。也就是說delete x是沒有意義的。

你最好也知道,delete是不會直接釋放內存的,她只是間接的中斷對象引用

問題四

var y = 1, x = y = typeof x;
x;//"undefined"

咱們試圖分解上述代碼成下面兩步:

var y = 1; //step 1
var x = y = typeof x; //step 2

第一步應該沒有異議,咱們直接看第二步

  1. 賦值表達式從右向左執行

  2. y被從新賦值爲typeof x的結果,也就是undefined

  3. x被賦值爲右邊表達式(y = typeof x)的結果,也就是undefined

問題五

(function f(f){
    return typeof f();//"number"
})(function(){ return 1; });

直接上註釋解釋:

(function f(f){
    //這裏的f是傳入的參數function(){ return 1; }
    //執行的結果天然是1
    return typeof f(); //因此根據問題一的表格咱們知道,typeof 1結果是"number"
})(function(){ return 1; });

問題六

var foo = {
    bar: function() { return this.baz; },
    baz: 1
};

(function(){
    return typeof arguments[0]();//"undefined"
})(foo.bar);

這裏你可能會誤覺得最終結果是number。向函數中傳遞參數能夠看做是一種賦值,因此arguments[0]獲得是是真正的bar函數的值,而不是foo.bar這個引用,那麼天然this也就不會指向foo,而是window了。

問題七

var foo = {
    bar: function(){ return this.baz; },
    baz: 1
}
typeof (f = foo.bar)();//"undefined"

這和上一題是同樣的問題,(f = foo.bar)返回的就是bar的值,而不是其引用,那麼this也就指的不是foo了。

問題八

var f = (function f(){ return '1'; }, function g(){ return 2; })();
typeof f;//"number"

逗號操做符 對它的每一個操做對象求值(從左至右),而後返回最後一個操做對象的值

因此(function f(){ return '1'; }, function g(){ return 2; })的返回值就是函數g,而後執行她,那麼結果是2;最後再typeof 2,根據問題一的表格,結果天然是number

問題九

var x = 1;
if (function f(){}) {
    x += typeof f;
}
x;//"1undefined"

這個問題的關鍵點,咱們在問題二中談到過,function expression中的函數名f是不能在函數體外部訪問的

問題十

var x = [typeof x, typeof y][1];
typeof typeof x;//"string"
  1. 由於沒有聲明過變量y,因此typeof y返回"undefined"

  2. typeof y的結果賦值給x,也就是說x如今是"undefined"

  3. 而後typeof x固然是"string"

  4. 最後typeof "string"的結果天然仍是"string"

問題十一

(function(foo){
    return typeof foo.bar;//"undefined"
})({ foo: { bar: 1 } });

這是個純粹的視覺詭計,上註釋

(function(foo){
    
    //這裏的foo,是{ foo: { bar: 1 } },並無bar屬性哦。
    //bar屬性是在foo.foo下面
    //因此這裏結果是"undefined"
    return typeof foo.bar;
})({ foo: { bar: 1 } });

問題十二

(function f(){
    function f(){ return 1; }
    return f();//2
    function f(){ return 2; }
})();

經過function declaration聲明的函數甚至能夠在聲明以前使用,這種特性咱們稱之爲hoisting。因而上述代碼實際上是這樣被運行環境解釋的:

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

問題十三

function f(){ return f; }
new f() instanceof f;//false

當代碼new f()執行時,下面事情將會發生:

  1. 一個新對象被建立。它繼承自f.prototype

  2. 構造函數f被執行。執行的時候,相應的傳參會被傳入,同時上下文(this)會被指定爲這個新實例。new f等同於new f(),只能用在不傳遞任何參數的狀況。

  3. 若是構造函數返回了一個「對象」,那麼這個對象會取代整個new出來的結果。若是構造函數沒有返回對象,那麼new出來的結果爲步驟1建立的對象,

ps:通常狀況下構造函數不返回任何值,不過用戶若是想覆蓋這個返回值,能夠本身選擇返回一個普通對象來覆蓋。固然,返回數組也會覆蓋,由於數組也是對象。

因而,咱們這裏的new f()返回的仍然是函數f自己,而並不是他的實例

問題十四

with (function(x, undefined){}) length;//2

with語句將某個對象添加的做用域鏈的頂部,若是在statement中有某個未使用命名空間的變量,跟做用域鏈中的某個屬性同名,則這個變量將指向這個屬性值。若是沒有同名的屬性,則將拋出ReferenceError異常。

OK,如今咱們來看,因爲function(x, undefined){}是一個匿名函數表達式,是函數,就會有length屬性,指的就是函數的參數個數。因此最終結果就是2

寫在最後

有人以爲這些題坑爹,也有人以爲開闊了眼界,見仁見智吧。但有一件事是真的,不管你是否堅決的實踐派,缺了理論基礎,也鐵定走不遠 - 你永遠不會見到哪一個熟練的技術工人忽然成了火箭專家。

看文檔、讀標準、結合實踐,纔是同志們的決勝之道

相關文章
相關標籤/搜索