原型和原型链

100 阅读2分钟

原型及原型链

JS原型是为其他对象提供共享访问属性的对象,在创建对象时,每个对象都创建了一个隐式引用指向他的原型对象或者null。原型也是一个对象,也有他的原型,构成了原型链。

原型链的作用

在访问一个对象的属性的时候,会访问其原型链,它本身是原型链的第一个元素。检查它是否含有要查找的属性,如果包含则返回属性值,否则查找原型链上的第二个元素,以此类推,知道最后一个元素null,返回undefined

如何实现原型继承

显式实现

Object.create(a)

Object.setPrototypeOf(a,b)

隐式实现

另一种是通过 constructor 构造函数,在使用 new 关键字实例化时,会自动继承 constructor 的 prototype 对象,作为实例的原型。

手动实现一个new

new出来的对象能够:

  1. 访问构造函数里的属性;
  2. 访问构造函数原型上的属性;
function myNew(constructor, ...args) {
  const obj = Object.create(constructor.prototype);
  const result = constructor.apply(obj, args);
  if (typeof result === 'object' && result !== null) {
    return result;
  }
  return obj;
}

其中const obj = Object.create(constructor.prototype) 等价于:
const F = function() {};
F.prototype = constructor.prototype;
const obj = new F();

自己实现一个继承

实现继承有三个需要注意的点:

  1. 构造函数中调用父亲构造函数,先父后子(为了在子中复制一份父亲的属性供自己所有);
  2. 设置原型关系,将父类实例设置为自己的原型。
  3. 修改子类原型构造函数的指向,只想子类构造函数自身。 代码如下:
// 父类person
function Person(name, age) {
  this.name = name;
  this.age = age;
}
Person.prototype.sayHi = function() {
  console.log('hi,my name is: '+ this.name + ', my age is: '+this.age);
}

// 子类Man,继承父类Person
function Man(name, age) {
  Person.call(this, name, age);
  this.sex = 'male';
}

Man.prototype = new Person(); 
// 有一个缺点,就是要创建一个无用的Person对象,占用内存,可改用以下方式:
// const F = function() {};
// F.prototype = Person.prototype;
// Man.prototype = new F();
// 上面三行等价于 Man.prototype = Object.create(Person.prototype);

Man.prototype.constructor = Man;

理解instanceof并手动实现

obj instanceof Constructor 用来判断Constructor.prototype是否存在obj的原型链上。

手写实现如下:

function myInstanceof(obj, Constructor) {
  let current = Object.getPrototypeOf(obj);
  while(current !== null) {
    if (current === Constructor.prototype) { return true; }
    current = Object.getPrototypeOf(current);
  }
  return false;
}
/ 定义构造函数
function C(){} 
function D(){} 

var o = new C();
console.log(myInstanceof(o, C)); // true,因为 Object.getPrototypeOf(o) === C.prototype
console.log(myInstanceof(o, D)); // false,因为 D.prototype 不在 o 的原型链上
console.log(myInstanceof(o, Object)); // true,因为 Object.prototype.isPrototypeOf(o) 返回 true

参考文献: zhuanlan.zhihu.com/p/87667349