2020 年我碰到的原型鏈的面試題.md

寫作背景

猛然間發現都需要在牛客網上視頻面試了。

好氣人呀,一週內面試筆者居然再原型鏈問題上被連續絆倒兩次,然後被判定爲 JS 基礎薄弱。真的好氣人呀,所以筆者研究了一下午的原型鏈,打算之後再也不會被這個絆倒,其遇到的題目和大家分享。

題目

  • 題目1,來自快手
Function.prototype.a = () => {
  console.log(1);
}
Object.prototype.b = () => {
  console.log(2);
}
function A() {}
const a = new A();

a.a();
a.b();
A.a();
A.b();

真的再很多地方出現了,我一搜才發現其他朋友在 JD 的面試上也遇到過。我遇到的當晚也寫了一份解答思路:面試:Function.prototype.a 請給出下列函數的執行輸出

對於 new 出來的對象 a 的屬性,原型鏈查找的順序應該是

1. a 自身
2. `a.__proto__` 相當於 A.prototype
3. `A.prototype.__proto__` 相當於 Object.prototype
4. `Object.prototype.__proto__` 這個爲 null,原型鏈查找到頭。

對於 function 定義的函數 A 的屬性,原型鏈查找順序應該是

1. A 自身
2. `A.__proto__` 相當於 Function.prototype
3. `Function.prototype.__proto__` 等於 Object.prototype
4. `Object.prototype.__proto__` 這個爲 null,原型鏈查找到頭。

  • 題目2,來自網易雲音樂
function A() {
}

A.prototype.n = 0;

A.prototype.add = function () {
  this.n += 1;
}

a = new A();
b = new A();
a.add();
console.log(b.add())

這是在快手後的網易面試,自從有了題1,我對這一套就開始疑神疑鬼的,想的複雜了。

構造函數 new 出來的對象,其方法 this 都指向他的實例。所以調用完 add 方法,遇到 this.n += 1;,這個 this 指向的又是實例對象。所以我們的 a 對象 和 b 對象都有獨屬於自己的 n。

  • 題目3
function Person(name, age) {
  this.name = name;
  this.age = age;
  this.eat = function() {
    console.log(age + "歲的" + name + "在吃飯。");
  }
}

Person.run = function () {}
Person.prototype.walk = function () {}

let p1 = new Person("jsliang", 24);
let p2 = new Person("jsliang", 24);

console.log(p1.eat === p2.eat); // false
console.log(p1.run === p2.run); // true
console.log(p1.walk === p2.walk); // true

new 操作符使得構造函數內的 eat 函數(對象),是在堆中新開一份空間放置,所以兩個實例對象它自然不共享。

而原型上兩個實例對象自然都是同一份,walk 方法相同。

需要注意的是 p1.run 和 p2.run 都是 undefined。因爲 run 方法只是作爲 Person 自己的靜態屬性,p1 和之後的原型鏈上是找不到的。

  • 題目4
function A() {
  this.test = 1
}

var a = new A();
a.test

a = new A;
a.test

a = A()
a.test

A.test

提示讀者們,的是 new A 等價與 new A(),MDN上這麼說

使用指定的參數調用構造函數 Foo,並將 this 綁定到新創建的對象。new Foo 等同於 new Foo(),也就是沒有指定參數列表,Foo 不帶任何參數調用的情況。

a = A() 只是把 A 作爲普通函數執行了,這個普通函數內部並無 return 出什麼來,所以 a 只是 undefined,a.test 就會報錯。

至於 A.test, A 只是個函數定義,A 本身沒得到執行,自然不會有什麼 test 屬性,只能往 Function.prototype 上找,自然還是找不到了。

要是 Java 後三個都得報語法錯誤,我開始沒那麼喜歡 JS 了。

  • 題5
function A() {}
function B(a) {
    this.a = a;
}
function C(a) {
    if (a) {
        this.a = a;
    }
}
A.prototype.a = 1;
B.prototype.a = 1;
C.prototype.a = 1;

console.log(new A().a); // 1
console.log(new B().a); // undefined
console.log(new C(2).a); // 2

console.log(new B().a); // undefined,你需要知道此時 B 它自身屬性裏已經有了一個 a 屬性了

  • 題6

問 foo1 上究竟都掛着什麼屬性

function foo() {
    this.some = '222'
    let ccc = 'ccc'
    foo.obkoro1 = 'obkoro1'
    foo.prototype.a = 'aaa'
}
foo.koro = '扣肉'
foo.prototype.test = 'test'
let foo1 = new foo() 
foo.prototype.test = 'test2' 

foo1 上掛着屬性 some,其原型鏈上掛着 test 和 a,至於 foo.obkoro1 只是靜態屬性不影響 foo1,ccc 更是閉包裏的變量更沒關係。

思考題

  • 原型鏈查找的終點在哪兒?
  • __proto__ 非標準,有什麼能替代它獲取原型鏈?
  • new 操作符做了什麼?
  • 構造函數中的 this 指向何方?

總結

去年開始出門面試,那時候被卡的是框架源碼和實現細節;之後就被問各種基建系統的實現;等年初出門面幾家,發現全都做算法題了;等我花了一陣子把什麼鏈表堆棧的 leetcode 題刷過,發現最近面的沒有一個問算法題,卻都在問這種 “JS 基礎題”。面試真的是一門玄學,怎麼準備都不夠。

哦,對了,還有 promise 微任務組合起來的輸出的問題,也坑了我好多次,留給後面的篇幅吧。真的好討厭這樣的問題啊!

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