想知道自己Js原型與原型鏈掌握的怎麼樣?來做個題試試吧!
Js原型與原型鏈圖示:
問題集錦:
問題1:
var A = function() {};
A.prototype.n = 1;
var b = new A();
A.prototype = {
n: 2,
m: 3
}
var c = new A();
console.log(b.n);
console.log(b.m);
console.log(c.n);
console.log(c.m);
答案1:
b.n -> 1
b.m -> undefined;
c.n -> 2;
c.m -> 3;
問題2:
var F = function() {};
Object.prototype.a = function() {
console.log('a');
};
Function.prototype.b = function() {
console.log('b');
}
var f = new F();
f.a();
f.b();
F.a();
F.b();
答案2:
f.a() -> a
f.b() -> f.b is not a function
F.a() -> a
F.b() -> b
問題3:
function Person(name) {
this.name = name
}
let p = new Person('Tom');
問題1: p.__proto__
等於什麼?
問題2:Person.__proto__
等於什麼?
答案3:
答案1:Person.prototype
答案2:Function.prototype
問題4:
var foo = {},
F = function(){};
Object.prototype.a = 'value a';
Function.prototype.b = 'value b';
console.log(foo.a);
console.log(foo.b);
console.log(F.a);
console.log(F.b);
答案4:
foo.a => value a
foo.b => undefined
F.a => value a
F.b => value b
問題5:
function Fn() {
var num = 500;
this.x = 100;
}
Fn.prototype.getX = function () {
console.log(this.x);
}
Fn.aaa = 1000;
var f = new Fn;
console.log(f.num)
console.log(f.aaa)
var res = Fn();
console.log(res)
答案5:
f.num => undefined
f.aaa => undefined
var res = Fn(); // res是undefined Fn中的this是window
問題6:一個靈魂面試題
function Person(name) {
this.name = name
}
var p2 = new Person('king');
// 核心點:__proto__是求原型對象的,也就是求構造器的prototype屬性
// ===>原型對象是構造器的一個屬性,本身是個對象
//constructor 是求構造器的 ====> 構造器的prototype屬性的對象集合裏也有constructor,
//這個prototype裏的constructor指向構造器自己
console.log(p2.__proto__)//Person.prototype
console.log(p2.__proto__.__proto__)
//結合上題,也就是Person.prototype的__proto__,Person.prototype本身是個對象,
//所以這裏輸出:Object.prototype
console.log(p2.__proto__.__proto__.__proto__)
//同理,這裏是求Object.prototype的__proto__,這裏輸出:null
console.log(p2.__proto__.__proto__.__proto__.__proto__)
//null後面沒有了,報錯
console.log(p2.__proto__.__proto__.__proto__.__proto__.__proto__)
//null後面沒有了,報錯
console.log(p2.constructor)//Person
console.log(p2.prototype)
//undefined p2是實例對象,不是函數對象,是沒有prototype屬性滴
console.log(Person.constructor)//Function 一個空函數
console.log(Person.prototype)
//打印出Person.prototype這個對象裏所有的方法和屬性
console.log(Person.prototype.constructor)//Person
console.log(Person.prototype.__proto__)
//Person.prototype是對象,所以輸出:Object.prototype
console.log(Person.__proto__)//Function.prototype
console.log(Function.prototype.__proto__)//Object.prototype
console.log(Function.__proto__)//Function.prototype
console.log(Object.__proto__)//Function.prototype
console.log(Object.prototype.__proto__)//null
問題7:
function A() {
B = function () { console.log(10) }
return this
};
A.B = function () {
console.log(20)
};
A.prototype.B = function () {
console.log(30)
};
var B = function () {
console.log(40)
};
function B() {
console.log(50)
}
A.B() // 20
B() // 40
A().B() // 10
B() // 10
new A.B() // 20
new A().B() // 30
答案7解析:
A.B() // answer 20 【原型與原型鏈】
// 在`A`的原型對象中查找是否有`B`函數並且調用,這裏並未執行`A`函數。
// A.B = function () {console.log(20)};
// 在A的原型對象中添加了`B`函數,停止查找,所以答案爲 20
B() // answer 40 【函數表達式和函數聲明】
// var B = function () {console.log(40)}
// function B() {console.log(50)}
// 同名 -> 函數提升會 > 變量提升
// 換言之 同名的函數表達式和函數聲明同時存在時 總是執行表達式
A().B() // answer 10 【函數表達式和函數聲明】
// A() 執行函數A ==> 1.變量B重新賦值函數 2.返回this(window)
// .B() 執行全局下的B函數 已經被重新賦值 所以輸出10
B() // answer 10
// 上面的代碼執行過A函數了,此時全局下的B函數輸出10
new A.B() // answer 20【函數表達式和函數聲明】
// new 執行了 A.B = function () {console.log(20)};
new A().B() // answer 30
// new 執行構造函數 A ,全局變量 B 重新賦值函數10
// 此時A() 指針指向哪裏?
// 首先要知道 new 做了什麼事?
// ==> 創建空對象objA objA.__proto__ = A.prototype
// .B() 在A的原型對象中查找 B; A.prototype 指向函數的原型對象
// A.prototype.B = function () {console.log(30)} 輸出 30
未完待續。。。