溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

es6 class是不是語法糖

發(fā)布時(shí)間:2022-10-18 09:42:52 來源:億速云 閱讀:117 作者:iii 欄目:web開發(fā)

這篇文章主要介紹了es6 class是不是語法糖的相關(guān)知識,內(nèi)容詳細(xì)易懂,操作簡單快捷,具有一定借鑒價(jià)值,相信大家閱讀完這篇es6 class是不是語法糖文章都會有所收獲,下面我們一起來看看吧。

class是語法糖。原因:class是基于原型繼承的實(shí)現(xiàn),對語言的功能并沒有什么影響,只是方便了語法的書寫及閱讀;class的本質(zhì)是function,能夠讓對象原型的寫法更加清晰,更像面向?qū)ο缶幊痰恼Z法。

本教程操作環(huán)境:windows7系統(tǒng)、ECMAScript 6版、Dell G3電腦。

ES6 class類——語法糖

class (類)作為對象的模板被引入,可以通過 class 關(guān)鍵字定義類。它的本質(zhì)是函數(shù)(function),可以看作一個(gè)語法糖,讓對象原型的寫法更加清晰、更像面向?qū)ο缶幊痰恼Z法。

它的class和別的語言不一樣,它依舊是基于原型繼承的實(shí)現(xiàn),對語言的功能并沒有影響,只是方便了你的書寫及閱讀

為什么說ES6的class是語法糖

我們帶著問題去閱讀下文:

  • 為什么說ES6的class是語法糖?

  • class是原型的語法糖嗎?

  • 那又是如何使用原型來實(shí)現(xiàn)class這一語法糖的呢?

1. 基于Prototype的OOP

先來看一個(gè)prototype的例子:

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

這是我們使用原型的一個(gè)很簡單的例子,Person具有名字和性別,Man是一個(gè)性別為男的Person,Jy是一個(gè)Man。我們先記住這一個(gè)例子,下面將使用class重寫這個(gè)例子。

Tips: new, this等是Brendan Eich使之更像Java的OOP而加上的,有興趣的讀者可以自行查閱相關(guān)信息。

2. 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'

我們通過重寫這個(gè)例子,采用了class、constructor、extends、super 這些單詞,接下來就具體來說說ES6規(guī)范中對它們做了什么。

3. 使用Prototype實(shí)現(xiàn)的Class OOP(ES6規(guī)范)

在ES6之前,JS對象其實(shí)就是屬性的集合,而屬性則是一組鍵值對(key, value),key可以是String or Symbol, value包括數(shù)據(jù)屬性特征值和訪問器特征值。

你說普通的屬性還好,不還有對象下面的方法嗎?怎么就變成了屬性的集合呢?

其實(shí)在ES5規(guī)范中出現(xiàn)的method的定義是“function that is the value of a property”,是對象的函數(shù)屬性而已,不能稱之為方法,直到ES6出現(xiàn),規(guī)范中才有Method Definitions。

我們能想到的在ES3有關(guān)OOP的東西: prototype、new、 this、 constructor、 instanceof, 甚至不是規(guī)范的 __proto__ 屬性。

所幸的是在ES5中我們增加了很多方法來補(bǔ)全它,使之完備:

  • Object.defineProperty

  • Object.freeze

  • Object.create

  • Object.getPrototypeOf

  • Object.setPrototypeOf

  • 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中定義已經(jīng)是Method了,它具有屬性[[homeObject]],homeObject指向方法被調(diào)用的對象(代碼中指的是obj), 它是綁定在對象中的Internal Slots,也就是你不能去修改,就相當(dāng)于寫死了。

那么homeObject有什么用呢?它跟super密切相關(guān),當(dāng)解析到super這一關(guān)鍵字的時(shí)候就會找homeObject的prototype。

簡單來說,總結(jié)為下面兩條公式:

  • let homeObj = Method[[HomeObject]] = obj

  • super = Object.getPrototypeOf(homeObj)

Note: homeObject是靜態(tài)綁定在internal slots中的,而super是動態(tài)查找的。

講完super,我們來講講extends和constructor

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

extends主要做了以下兩件事:

  • Object.setPrototypeOf(A, B)

  • Object.setPrototypeOf(A.prototype, B.prototype)

如果父類是null, 則執(zhí)行Object.setPrototypeOf(C.prototype, null)

上述代碼的第一和第二部分區(qū)別在于有沒有顯示聲明constructor, 那么這兩段代碼是否等價(jià)呢?答案是等價(jià)的。

規(guī)范中就是這么定義的:

代碼的第三部分是繼承了null, 它不會報(bào)語法錯(cuò)誤,但是我們無法new一個(gè)C出來,原因是new的時(shí)候會調(diào)用null的constructor,而null沒有constructor。

看到這里,ES6的class oop, 規(guī)范聲明都是使用原型來操作,所以我們是不是可以說class是原型的語法糖了?

4. babel編譯后的class

我們實(shí)際項(xiàng)目中多采用babel來編譯ES6、7的代碼,所以這節(jié)我們就來分析以下babel編譯后的代碼,其中會省略一些報(bào)錯(cuò)、類型檢測的一些相關(guān)代碼來更好地呈現(xiàn)使用原型來實(shí)現(xiàn)OOP的主題。

編譯前:

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

編譯后:

"use strict";
 
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());

我們重點(diǎn)看_inherits 方法,跟我們上述說的extends做的兩件事是一樣的:

  • Object.setPrototypeOf(subClass, superClass)

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

只不過它采用的是Object.create方法,這兩個(gè)方法的區(qū)別可以去MDN上查看。

再看function A內(nèi)部,其實(shí)就是執(zhí)行了B的構(gòu)造器函數(shù)來達(dá)到super(arguments)的效果, 這個(gè)與規(guī)范:如果沒有顯示聲明constructor會自動加上constructor是一致的。

關(guān)于“es6 class是不是語法糖”這篇文章的內(nèi)容就介紹到這里,感謝各位的閱讀!相信大家對“es6 class是不是語法糖”知識都有一定的了解,大家如果還想學(xué)習(xí)更多知識,歡迎關(guān)注億速云行業(yè)資訊頻道。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI