JavaScript 原型和原型链
就在我第100次以为我弄懂了原型和原型链,第101次又被面试官问到自闭。
先说结论:原型链是基于__proto__
形成的,继承是通过prototype
(原型)实现的。
那么,什么是prototype
,什么是__proto__
,两者关系又是怎样的呢?
prototype
prototype
是只有函数才有的属性- 函数的
prototype
指向一个对象(原型对象),其他对象可以通过它实现属性和方法的继承。
proto
__proto__
是浏览器非标准属性,只有部分浏览器实现了此属性,对应的标准属性是[[Prototype]]
__proto__
是每个对象都具有的属性- 由
__proto__
连接起来的对象,组成的一个有继承关系的链条,叫做"原型链"。
proto & prototype
- 对象的
__proto__
属性指向对象的构造函数的prototype
属性,也就是原型对象。 - 由于每个
JavaScript
函数实际上都是一个Function
对象(MDN),因此函数也有__proto__
属性,函数的__proto__
属性,指向Function.prototype
。
那么,普通函数、构造函数、Object、Function之间到底有什么关系呢?它们的__proto__
和prototype
之间的指向又是怎样的呢?
// 定义函数 a,a的本质是由Function函数构造出的js对象
function a(){}
// 对象的__proto__属性指向其构造函数的prototype属性,下面为true
console.log(a.__proto__ === Function.prototype) // true
// 所有的函数都是Function生成的,Object构造函数和Function自己也不例外,它们的__proto__属性都指向Function.prototype,所以下面两个为true
console.log(Object.__proto__ === Function.prototype); // true
console.log(Function.__proto__ === Function.prototype); // true
// Function.prototype是一个对象,它的__proto__属性指向原型链的最顶端Object.prototype
console.log(Function.prototype.__proto__ === Object.prototype); // true
console.log(Object.prototype.__proto__ === null); // true
看下面图会更加清晰一些
完整的原型关系图
弄懂了了这些,再看下面的题目,就是 so easy~
题目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); // 1
console.log(b.m); // undefined
console.log(c.n); // 2
console.log(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(); // 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');
p.__proto__等于什么?---> Person.prototype
Person.__proto__等于什么?---> Function.prototype
题目4
var foo = {},
F = function(){};
Object.prototype.a = 'value a';
Function.prototype.b = 'value b';
console.log(foo.a); // value a
console.log(foo.b); // undefined
console.log(F.a); // value a
console.log(F.b); // value b