在 JavaScript 中,ES6 之前不存在 class,所以 JavaScript 的继承是基于原型链实现的.每一个实例的 __proto__ 都指向自己构造函数的 prototype 属性.MDN 上这样解释:
当谈到继承时,JavaScript 只有一种结构:对象.每个对象都有一个私有属性(称之为 [[Prototype]]),它持有一个连接到另一个称为其 prototype 对象(原型对象)的链接.该 prototype 对象又具有一个自己的原型,层层向上直到一个对象的原型为 null.
构造函数与实例
在上面代码中,Person 为构造函数,person 为构造函数的一个实例对象,person.prpto 指向了 Person.prototype 属性.
function Person() {
}
let person = new Person();
person.__proto__ == Person.prototype; // true
Person.__proto__.constructor == Person; // true;
当读取实例属性的时候,如果找不到,就会查找原型中的属性 (即 person.__proto__),也就是在 Person.prototype 中去查找.如果还找不到就去查找原型的原型 (即
Person.prototype.__proto__
), 而它又是什么呢?因为原型也是一个对象,
typeof(Person.prototype) == Object
, 所以
Person.prototype.__proto__ == Object.prototype
, 如果此时还找不到,则去查找
Object.prototype.__proto__
, 最终返回 null.举个栗子:
当 person.name 有值时,首先查找 person.name , 查找成功.
function Person() {
}
let person = new Person();
person.name = 'black';
console.log(person.name); //1. black
// 此时删除 person.name
delete person.name;
Person.prototype.name = '古月';
console.log(person.name); // 2. 古月
// 此时删除 Person.prototype.name
delete Person.prototype.name;
console.log(person.name); // 3.undefined
当 person.name 查找不到时,查找
person.__proto__.name
, 也就是查找
Person.prototype.name
, 查找成功.
当 person.name 查找不到时,查找
person.__proto__.name
, 也就是查找
Person.prototype.name
, 查找不到时,查找
Person.prototype.__proto__
, 继续向上查找,查找到
Object.prototype.name
, 查找失败,返回 undefined;
通过原型模拟 new 的实现
new 作用:
new 运算符创建一个自定义对象或具有构造函数的内置对象的实例.
新建一个对象 obj
function Person(name) {
this.name = name;
}
Person.prototype.sayHi = function() {
console.log(`hi, I am ${this.name}`);
}
function _new(fn) {
var obj = {}
obj.__proto__ = fn.prototype;
fn.apply(obj, [].slice.call(arguments, 1));
return obj;
}
let test = _new(Person, 'black')
console.log(test.name);
test.sayHi();
let test2 = new Person('black')
console.log(test2.name);
test2.sayHi();
将 obj 的原型指向构造函数
使用 apply,改变构造函数 this 的指向到 obj.
返回 obj
来源: http://www.jianshu.com/p/02355219197d