涉及prototype,constructor和instanceof前端js面試難題
原創(chuàng)提問者:自己遇到的前端面試問題,請高手來幫忙解決。其他的感興趣的同學也可以來看看,自己能不能答對。
- var A = function() {};
- A.prototype = {};
- var B = {};
- console.log(A.constructor);//Function
- console.log(B.constructor);//Object
- var a = new A();
- A.prototype = {};
- var b = new A();
- b.constructor = A.constructor;
- console.log(a.constructor == A);//false
- console.log(a.constructor == b.constructor);//false
- console.log(a instanceof A);//false
- console.log(b instanceof A);//true
小弟對***兩個console.log的結果不明白,我覺得應該是
- console.log(a instanceof A);// true
- console.log(b instanceof A);//true
但是在瀏覽器中試過了,確實是上面的答案,求解,提前謝謝各位。
解答1:
首先說明 instanceof 和 constructor 沒有半毛錢關系,所以題主的問題有效代碼如下:
- var A = function() {};
- A.prototype = {};// 這里的空對象為對象1
- var a = new A();
- A.prototype = {};// 這里的空對象為對象2
- var b = new A();
- console.log(a instanceof A);//false
- console.log(b instanceof A);//true
特別注意我添加的兩個注釋,對象1和對象2并非同一個對象!
再來解釋instanceof,具體可以參考ECMAScript官方文檔和IBM 開發(fā)者社區(qū)的解釋,簡而言之,instanceof運算符返回 A 的 prototype 對象是否存在 a 的原型鏈中。
那么上面代碼就可以用下面的圖示說明:
可以看到,a 的原型鏈上已經不存在 A 的 prototype 對象,因此console.log(a instanceof A);//false,而 b 的原型鏈上存在 A 的 prototype 對象,因此console.log(b instanceof A);//true
解答2:
1) a instancof A 檢查a的原型鏈中是否存在A.prototype
2)每一個js對象都有一個proto屬性(標準表示[[prototype]])
proto是普通對象的隱式屬性,在new的時候,會指向prototype所指的對象;new出來的對象是沒有prototype屬性的
proto實際上是某個對象的屬性,而prototype則是屬于構造函數的屬性,prototype指向的是一個實體對象,也就是其有proto屬性;
通過proto屬性的串聯構建了一個對象的原型訪問鏈,起點為一個具體的對象,終點在Object.prototype,其proto( [[ prototype ]]) )為null
3)constrcutor 為對象的構造函數對象,存在于prototype對象(原型對象)中,只要不對prototype對象重新復制,constructor都指向構造函數自身
默認的構造函數為function object()
那么我們來分析下題目
- //和 function A(){} 相同,只不過原題通過匿名函數表達式的方式而非函數聲明的方式來生成一個函數對象
- var A = function() {};
- A.prototype = {};
- //此時對構造函數對象A的prototype屬性重新復制,constructor屬性不見了,此時 console.log(A.prototype.constructor == A);//false, console.log(A.prototype.constructor);// function Object()
- //如果不執(zhí)行 A.prototype = {}; 那么 console.log(A.prototype.constructor == A);//true , console.log(A.prototype.constructor);// function A()
- //為了和第2次出現 A.prototype = {};有直觀的區(qū)別,我們添加以下語句
- A.prototype = {first:'first'};
- var B = {};
- console.log(A.constructor);//Function 函數的構造函數為 function Function()
- console.log(B.constructor);//Object 普通object的構造函數為 function Object()
- var a = new A();//新建一個對象a,
- //此時執(zhí)行
- console.log(a.constructor);//function Object()
- console.log(a.constructor==A);//false
- console.log(a instanceof A);//true a.__proto__指向A構造函數的prototype對象 Object {first: "first"}
- A.prototype = {};//修改構造函數A的prototype屬性,與第1次出現有所區(qū)別,添加以下語句
- A.prototype = {second:"second"};//此時的A構造函數的prototype屬性值和定義A的時候就不同了
- //這個時候我們再調用
- //console.log(a.constructor==A);
- //console.log(a instanceof A);
- // 會出現什么情況呢
- console.log(a.constructor==A);//false
- console.log(a instanceof A);//false
- console.log( a.__proto__ );//Object {first: "first"} 和 當前A.prototype已經不同了,也就是說構造函數prototype的變話不影響已經創(chuàng)建的對象,
- //這個道理和 var b=2,a=b;console.log(a); console.log(b); b=3; ;console.log(a); console.log(b);相同
- console.log(a.constructor);//function Object()
- console.log(A.constructor);//function Function ()
- var b = new A();//在新建一個對象B,在修改了的A.prototype的基礎上
- console.log( b.__proto__ );//Object {second:"second"}
- b.constructor = A.constructor;//此時不會修改原型鏈上的constructor屬性,實在對象不上添加了一個 名為constructor的普通屬性,和原型上的constructor完全無關
- //多說一句,讀取屬性值或調用方法時會涉及到原型鏈上屬性的查找規(guī)則,設置屬性不適用,直接把屬性添加到b上 (會有些細小的不同,具體可參考你不知道的javascript P144 5.1.2)
- // b.constructor 為 Function
- console.log(a.constructor == A);//false a.constructor 為 Object
- console.log(a.constructor == b.constructor);//false b.constructor 為 Function
- // A.prototype -> {second:"second"};
- // b.__proto__ -> Object {second:"second"}
- // a. __proto__ ->Object {first: "first"}
- console.log(a instanceof A);//false
- console.log(b instanceof A);//true
解答3
.首先,instanceof 到底比較的什么?
instanceof 比較的是否能在實例的原型對象鏈中找到 與構造函數(第二個參數)的prototype屬性所指向的原型對象,能找到就返回true,反之false;
2. 方法A的原型被篡改為 Object (A.prototype = {})經過這一步之后,
實例 a.[[proto]] = function A(){}.prototype !!//注意,此時這個加粗的prototype已經變成了{}了!
而constructor是原型對象的屬性,所以 a.constructor == function Object(){} !!// {}根據自身的原型鏈找到
A.[[proto]] = function Function(){}.prototype //
A.constructor = function Function(){} //
顯然 A.constructor != a.constructor ;
下一個比較就同理了。
解答4
constructor是掛在prototype下的,當A.prototype={}的時候,constructor被刪除了。所以a是false,而b又從新設置了constructor指向A,這時候b是true