阅读 155

js继承方式讲解

类分为 私有属性 公有属性 静态方法

使用对象方式,继承公有属性

let obj2 = {
   age: 9,
   name:'jw'
};
let obj = {
  name:'zfpx',
  getPName(){ // 可以通过super关键字获取到父属性
    return super.name
  },
  __proto__:obj2
}
console.log(obj.getPName());
复制代码

只继承公有属性

Child.prototype.__proto__ = Parent.prototype;
复制代码
Object.setPrototypeOf(Child.prototype, Parent.prototype)
复制代码

上面两个等价,一个是es5一个是es6

只继承共有属性

Child.prototype = Object.create(Parent.prototype,{constructor:{value:Child}});
let child = new Child;
child.smoking();
console.log(child.constructor);
复制代码

实现原理:

function create(parentPrototype,props){
  function Fn() {}
  Fn.prototype = parentPrototype;
  let fn = new Fn();
  for(let key in props){
    Object.defineProperty(fn, key, {
      ...props[key],
      enumerable:true  //不加这句枚举不出来child.constructor(undefined)
    });
  }
  return fn;
}
// defineProperty中加了set get就不能加 writable和value了。
Child.prototype = create(Parent.prototype,{constructor:{value:Child}});
let child = new Child();
console.log(child.constructor);
复制代码

只继承私有属性 再子类中调用父类的方法即可 Parent.call(this)

function Parent(){
    this.parent = 'parent';
}
Parent.prototype.smoking = function () {
    console.log('吸烟')
}
function Child(){
    Parent.call(this)
}
console.log(new Child().parent)
复制代码

child继承父类的所有的属性

function Parent(){
    this.parent = 'parent';
}
Parent.prototype.smoking = function () {
    console.log('吸烟')
}
function Child(){}
 Child.prototype = new Parent;
let child = new Child();
Child.prototype.eat = function () {
 console.log('吃')
 }
 console.log(child.parent)
 console.log(child.smoking)
 child.__proto__.eat();
 console.log(child.__proto__=== Child.prototype)
 console.log(Child.prototype.constructor === Child)
复制代码

为了追本溯源, 我顺便研究了new运算符具体干了什么?发现其实很简单,就干了三件事情.

var obj  = {};
obj.__proto__ = F.prototype;
F.call(obj);
复制代码

第一行,我们创建了一个空对象obj;

第二行,我们将这个空对象的proto成员指向了F函数对象prototype成员对象;

第三行,我们将F函数对象的this指针替换成obj,然后再调用F函数.

我们可以这么理解: 以 new 操作符调用构造函数的时候,函数内部实际上发生以下变化:

1、创建一个空对象,并且 this 变量引用该对象,同时还继承了该函数的原型。

2、属性和方法被加入到 this 引用的对象中。

3、新创建的对象由 this 所引用,并且最后隐式的返回 this

function Otaku (name, age) {
    this.name = name;
    this.age = age;

    this.habit = 'Games';
}

Otaku.prototype.strength = 60;

Otaku.prototype.sayYourName = function () {
    console.log('I am ' + this.name);
}

// 模拟new
function objectFactory() {

    var obj = new Object(),

    Constructor = [].shift.call(arguments);

    obj.__proto__ = Constructor.prototype;

    var ret = Constructor.apply(obj, arguments);//对返回指值做处理,如果是引用对象则返回对象,如果是基本类型则忽略返回值,依然返回对象obj

    return typeof ret === 'object' ? ret : obj;

};

var person = objectFactory(Otaku, 'Kevin', '18')

console.log(person.name) // Kevin
console.log(person.habit) // Games
console.log(person.strength) // 60

person.sayYourName(); // I am Kevin
复制代码

es6中的class继承公有属性和私有属性和静态方法

class Child extends Parent{ // 要求继承父亲的私有和有公有
  constructor(){
    super(); // Parent.call(this);
    this.age = 9; // 私有属性
  }
  static a(){ // 属于类上的方法
    return 1;
  }
  smoking(){ // 原型上的方法
    console.log('smoking')
  }
}
let child = new Child();
复制代码