在JavaScript中,ES6之前不存在class,所以JavaScript的继承是基于原型链实现的。每一个实例的 __proto__
都指向自己构造函数的prototype
属性。MDN上这样解释:
当谈到继承时,JavaScript只有一种结构:对象。每个对象都有一个私有属性(称之为 [[Prototype]]),它持有一个连接到另一个称为其 prototype 对象(原型对象)的链接。该 prototype 对象又具有一个自己的原型,层层向上直到一个对象的原型为
null
。
构造函数与实例
function Person() {
}
let person = new Person();
person.__proto__ == Person.prototype; // true
Person.__proto__.constructor == Person; // true;
在上面代码中,Person为构造函数,person 为构造函数的一个实例对象,person.prpto 指向了Person.prototype 属性。
当读取实例属性的时候,如果找不到,就会查找原型中的属性(即person.__proto__
),也就是在Person.prototype
中去查找。如果还找不到就去查找原型的原型(即Person.prototype.__proto__
),而它又是什么呢?因为原型也是一个对象,typeof(Person.prototype) == Object
,所以Person.prototype.__proto__ == Object.prototype
,如果此时还找不到,则去查找Object.prototype.__proto__
,最终返回null
。举个栗子:
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.name
,查找成功。 - 当
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
运算符创建一个自定义对象或具有构造函数的内置对象的实例。
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
- 将
obj
的原型指向构造函数 - 使用
apply
,改变构造函数this
的指向到obj
。 - 返回
obj
网友评论