javascript-class使用和实现原理

class

其实 es6 的 class 就是一个语法糖,是基于原型去实现的。先创建一个关于 Animal 的类

class Animal {
  constructor(name) {
    // 这里面的this会指向实例
    this.name = name;
  }
  static parentName = "Animal"; // 静态属性
  static getParentName() {
    // 1.静态方法的this只会指向父类
    // 2.可以通过父类调用
    // 3.静态方法不能被实例继承,但可以被子类继承
    console.log(this.parentName);
    return this.parentName;
  }
  getName() {
    console.log(this.name);
    return this.name;
  }
}
class Cat extends Animal {
  constructor(name, age) {
    super(name); // 相当于 Animal.prototype.constructor.call(this, name, age)
    this.age = age;
  }
  getItsName() {
    super.getName(); // 相当于 Animal.prototype.getName()
  }
}

实现

function createClass(Constructor, protoProps, staticProps) {
  if (protoProps) {
    Object.defineProperties(Constructor.prototype, protoProps);
  }
  if (staticProps) {
    Object.defineProperties(Constructor, staticProps);
  }
  return Constructor;
}
function Animal(name) {
  // 实例属性赋值
  this.name = name;
}

// 在构造函数的原型对象上挂载实例方法
createClass(
  Animal,
  {
    getName: {
      value: function getName() {
        console.log("调用实例方法,获取实例属性", this.name);
        return this.name;
      },
    },
  },
  {
    getParentName: {
      // 在构造函数上挂载静态属性和方法
      value: function getParentName() {
        console.log("调用静态方法,获取静态属性", this.parentName);
        return this.parentName;
      },
    },
    parentName: {
      value: "Animal",
    },
  }
);

let animal1 = new Animal("animal1");

// 调用实例方法
animal1.getName();
// 调用静态方法
Animal.getParentName();

在创建对象实例时 let animal1 = new Animal('animal1'),主要会经历几个步骤

// 1.新建空对象
let newObj = new Object();
// 2.指向构造函数的原型对象,共享实例方法
newObj.__proto__ = Animal.prototype;
// 3.以新对象为上下文执行构造函数
let result = Animal.call(newObj, "animal1");
// 4.返回一个新对象
// 如果构造函数返回一个对象或函数,对象实例就是该对象或函数;否则返回一个新对象
return result instanceof Object ? result : newObj;

继承

下面通过 extends 关键字实现对 Animal 的继承

class Animal {
  constructor(name) {
    // 实例属性赋值,这里面的this会指向实例
    this.name = name;
  }
  static parentName = "Animal"; // 静态属性
  getName() {
    console.log("调用实例方法,获取实例属性", this.name);
    return this.name;
  }
}

class Cat extends Animal {
  constructor(name) {
    super(name);
  }
}

let cat = new Cat("jack");
cat.getName();
console.log(Cat.parentName);
// 可以发现,静态属性和方法也被子类继承了

实现 extends

extends 本质上是基于寄生式组合继承来实现的

  1. new 一个实例时,调用父类构造函数,继承实例属性
  2. 通过原型链继承父类实例方法
  3. 设置子类的 proto = 父类,让子类可以调用父类静态属性和方法
// 已知 Animal 这个父类
function _inherits(child, parent) {
  let proto = Object.create(parent.prototype);
  proto.constructor = child;
  child.prototype = proto;
}

function Cat(name) {
  // 调用父类的构造函数,继承实例属性
  Animal.call(this, name);
}

// 继承父类实例方法
_inherits(Cat, Animal);
// 设置子类的 __proto__ = 父类,让子类可以调用父类静态属性和方法
Object.setPrototypeOf(Cat, Animal);

let cat = new Cat("jack");
cat.getName();
console.log(Cat.parentName);

其实早期 js 实现继承还有好几种方式,可以参考 从 js 看面向对象

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值