浅析JavaScript中的原型链与继承

在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
  1. person.name有值时,首先查找person.name ,查找成功。
  2. person.name 查找不到时,查找person.__proto__.name,也就是查找Person.prototype.name,查找成功。
  3. 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();
  1. 新建一个对象obj
  2. obj的原型指向构造函数
  3. 使用apply,改变构造函数this的指向到obj
  4. 返回obj
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容