JS对象继承相关

propertype

在JavaScript中通过构造函数来构造对象
每个函数有他的propertype指向该构造函数构造的原型
每个propertype都有一个constructor方法来构造具体对象
需要在每次修改propertype的时候,注意修正constructor
构造的对象没有propertype(es6中对象有),这个属性是构造函数独有的
构造生成的对象会有一个__ proto __指向当前构造函数的propertype

属于同一个构造函数生成的obj.__ proto __ 相同
而每个prototype也可以有它的__ proto __ 构造函数继承另一个对象
实例化的对象也会顺着prototype生成__ proto __ .__ proto __ .__ proto __ ...
实现继承,也就是原型链
而Object.propertype就是原型链的顶端

继承的具体实现

构造函数绑定

function Man (){
    People.call(this, arguments) // apply
}

Prototype模式

function Man(){}
Man.prototype = new People()
Man.prototype.constructor = Man

如果不修改constructor的话,后辈构造函数会依然使用父辈的constructor而不是新定义的构造函数。

直接继承prototype

function Man(){}
Man.prototype = People.prototype
Man.prototype.constructor = Man

这样写执行效率会高很多,但之后修改prototype会直接修改到父辈的prototype中
第二行扭转constructor也会对父辈生效

空对象做媒介

const f = function(){}
f.prototype = People.prototype
Man.prototype = new f()
Man.prototype.constructor = Man
// Man.uber = People.prototype 备用

es5 Object

es5新增部分方法可以更灵活的创建对象和继承

Object.create()
Object.getPrototypeOf()
Object.setPrototypeOf()
// example
// Object.defineProperty
var Man = function(name) {
  Object.defineProperty(this, 'name', {
    writable: false,
    value: name
  });
};
// Object.create
Man.prototype = Object.create(People.prototype, {
  run: {
    writable: false,
    value: function() { console.log('running...'); }
  }
});
Man.prototype.constructor = Man

es6 class语法

语法糖居多

class People{
    constructor(){}
    toString(){}
}
class Man extends People {}

将类所有方法写入propertype
子类constructor必须写super,否则报错(功能相当于之前的call,apply),而且必须在super函数后才可以写子类的构造逻辑
super函数只能在constructor函数中调用

类同时有propertype和 __ proto __ 两条继承链
前者指向父类的__ proto __ 总是指向父类的__ proto __
后者总是指向父类

多重继承

javascript中不存在多重继承

es6提出可以用mix的模式实现多重继承

const a = {
  a: 'a'
};
const b = {
  b: 'b'
};
const c = {...a, ...b}; // {a: 'a', b: 'b'}
class d extends c {}

更复杂的具体实现

function mix(...mixins) {
  class Mix {
    constructor() {
      for (let mixin of mixins) {
        copyProperties(this, new mixin()); // 拷贝实例属性
      }
    }
  }
  for (let mixin of mixins) {
    copyProperties(Mix, mixin); // 拷贝静态属性
    copyProperties(Mix.prototype, mixin.prototype); // 拷贝原型属性
  }
  return Mix;
}

function copyProperties(target, source) {
  for (let key of Reflect.ownKeys(source)) {
    if ( key !== 'constructor'
      && key !== 'prototype'
      && key !== 'name'
    ) {
      let desc = Object.getOwnPropertyDescriptor(source, key);
      Object.defineProperty(target, key, desc);
    }
  }
}

class d extends mix(a, b) {}

proxy & reflect

顾名思义,为对象架空一层代理,相当于python中的Decorater

const p = new proxy(targe, handler)
// handler为空时直接访问对象

Reflect可以将Object相关的操作变成函数式行为,将target作为对象传输进去,而且也修正了一些返回结果,使其更加合理。

// example
Proxy(target, {
  set: function(target, name, value, receiver) {
    if (Reflect.set(target,name, value, receiver)) {
      console.log('property ' + name + ' on ' + target + ' set to ' + value);
    }
    return success;
  }
});
// 确保对象操作正确执行
// receiver 默认指向target, 是最后
if (Reflect.set(target, name, value, receiver)) {
    // do something
}
// 相当于
try {
    Object.defineProperty(receiver || target, name, value)
    // do something
} catch (e) {
  // failure
}

你可能感兴趣的:(JS对象继承相关)