为什么说ES6的class是语法糖?

51 篇文章 1 订阅
49 篇文章 1 订阅

一、前言

  • 为什么说ES6的class是语法糖?
  • class是原型的语法糖吗?
  • 那又是如何使用原型来实现class这一语法糖的呢?

二、基于Prototype的OOP(面向对象)

先来看个例子:

function Person (name, sex) {
	this.name = name
	this.sex = sex
}
 
function Man (name) {
	this.name = name
}
 
Man.prototype = new Person('', 'male')
 
let Jy = new Man('Jy')
 
console.log(Jy.name, Jy.sex) // Jy, male

这是我们使用原型的一个很简单的例子,Person具有名字和性别,Man是一个性别为男的Person,Jy是一个Man。我们先记住这一个例子,下面将使用class重写这个例子。

二、ES6 Class的OOP(面向对象)

class Person {
	constructor (name, sex) {
		this.name = name
		this.sex = sex
	}
}
 
class Man extends Person {
	constructor (name) {
		super('', 'male')
		this.name = name
	}
}
 
let Jy = new Man('Jy')
 
console.log(Jy.name, Jy.sex) // Jy, 'male'

我们通过重写这个例子,采用了class、constructor、extends、super 这些单词,接下来就具体来说说ES6规范中对它们做了什么。

四、使用Prototype实现的Class OOP(ES6规范)

在ES6之前,JS对象其实就是属性的集合,而属性则是一组键值对(key, value),key可以是String or Symbol, value包括数据属性特征值和访问器特征值。

你说普通的属性还好,不还有对象下面的方法吗?怎么就变成了属性的集合呢?

其实在ES5规范中出现的method的定义是“function that is the value of a property”,是对象的函数属性而已,不能称之为方法,直到ES6出现,规范中才有Method Definitions。
我们能想到的在ES3有关OOP的东西: prototype、new、 this、 constructor、 instanceof, 甚至不是规范的 __proto__属性。

所幸的是在ES5中我们增加了很多方法来补全它,使之完备:

  • Object.defineProperty:直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。
  • Object.freeze:冻结一个对象。一个被冻结的对象再也不能被修改;冻结了一个对象则不能向这个对象添加新的属性,不能删除已有属性,不能修改该对象已有属性的可枚举性、可配置性、可写性,以及不能修改已有属性的值。此外,冻结一个对象后该对象的原型也不能被修改。freeze() 返回和传入的参数相同的对象。
  • Object.create:创建一个新对象,使用现有的对象来提供新创建的对象的__proto__
  • Object.getPrototypeOf:返回指定对象的原型
  • Object.setPrototypeOf:设置一个指定的对象的原型 ( 即, 内部[[Prototype]]属性)到另一个对象或 null。
  • isPrototypeOf:用于测试一个对象是否存在于另一个对象的原型链上。

再来看一段代码:

let obj = {
	name: 'Jy',
	speak () { // Note: it's not speak: function () {}
		console.log(this.name, super.name)
	}
}
 
obj.speak() // Jy, undefined
 
Object.setPrototypeOf(obj,  { name: 'super' })
 
obj.speak() // Jy, super
 
let speak = obj.speak
speak() // undefined, super

obj.speak在ES6中定义已经是Method了,它具有属性[[homeObject]],homeObject指向方法被调用的对象(代码中指的是obj), 它是绑定在对象中的Internal Slots,也就是你不能去修改,就相当于写死了。

那么homeObject有什么用呢?它跟super密切相关,当解析到super这一关键字的时候就会找homeObject的prototype。

简单来说,super做的总结为下面两条公式:

  • let homeObj = Method[[HomeObject]] = obj
  • super = Object.getPrototypeOf(homeObj)

讲完super,我们来讲讲extends和constructor:

class A extends B { }
 
class A extends B {
	constructor (...args) {
		super(args)
	}
}
 
class C extends null { }

extends主要做了以下两件事:

  • 主要用到了Object.setPrototypeOf()
  • Object.setPrototypeOf(A, B)
  • Object.setPrototypeOf(A.prototype, B.prototype)
  • 如果父类是null, 则执行Object.setPrototypeOf(C.prototype, null)

上述代码的第一和第二部分区别在于有没有显示声明constructor, 那么这两段代码是否等价呢?答案是等价的。

代码的第三部分是继承了null, 它不会报语法错误,但是我们无法new一个C出来,原因是new的时候会调用null的constructor,而null没有constructor

五、babel编译后的class

编译前:


class A extends B {}
 
console.log(new A)

编译后:

function _getPrototypeOf(o) {
  _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) {
    return o.__proto__ || Object.getPrototypeOf(o);
  };
  return _getPrototypeOf(o);
}
 
function _inherits(subClass, superClass) {
  if (typeof superClass !== "function" && superClass !== null) {
    throw new TypeError("Super expression must either be null or a function");
  }
  subClass.prototype = Object.create(superClass && superClass.prototype, {
    constructor: {
      value: subClass,
      writable: true,
      configurable: true
    }
  });
  if (superClass) _setPrototypeOf(subClass, superClass);
}
 
function _setPrototypeOf(o, p) {
  _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) {
    o.__proto__ = p;
    return o;
  };
  return _setPrototypeOf(o, p);
}
 
var A =
  /*#__PURE__*/
  function (_B) {
    _inherits(A, _B);
 
    function A() {
 
      return _getPrototypeOf(A).apply(this, arguments);
    }
 
    return A;
  }(B);
 
console.log(new A());

我们重点看_inherits 方法,跟我们上述说的extends做的两件事是一样的:

  • Object.setPrototypeOf(subClass, superClass)
  • Object.setPrototypeOf(subClass.prototype, superClass.prototype)

只不过它采用的是Object.create方法

参考:https://juejin.im/post/5c820d0e6fb9a04a0c2f3e12

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值