国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > JavaScript > 正文

ES6中的class是如何實現(xiàn)的(附Babel編譯的ES5代碼詳解)

2019-11-19 11:32:13
字體:
供稿:網(wǎng)友

序言

這篇文章主要講解面試中的一個問題 - ES6中的class語法的實現(xiàn)?

ECMAScript 6 實現(xiàn)了class,class是一個語法糖,使得js的編碼更清晰、更人性化、風(fēng)格更接近面向?qū)ο蟮母杏X;也使 IDE 、編譯期類型檢查器、代碼風(fēng)格檢查器等工具更方便地檢測代碼語法,做靜態(tài)分析。同樣的,這給沒有類就缺點什么的軟件開發(fā)工程師一個更低的門檻去接觸js。

ES6 class 的 ES5 代碼實現(xiàn)

JavaScript語言的傳統(tǒng)方法是通過構(gòu)造函數(shù)定義并生成新對象,這種寫法和傳統(tǒng)的面向?qū)ο笳Z言差異較大。所以,ES6引入了Class這個概念作為對象的模板。

constructor

效果:ES6創(chuàng)建一個class會默認(rèn)添加constructor方法,并在new調(diào)用時自動調(diào)用該方法。

ES5:

function Person(name, age) { this.name = name; this.age = age;}Person.prototype.toString = function () { return '(' + this.name + ',' + this.age + ')';}var p = new Person('Mia', 18);console.log(p);// Person { name: 'Mia', age: 18 }

ES6:

class Person { constructor(name, age) {  this.name = name;  this.age = age; } toString() {  return '(' + this.name + ',' + this.age + ')'; }}var p = new Person('Mia', 18);console.log(p);// Person { name: 'Mia', age: 18 }

ES6的class中constructor是構(gòu)造方法,對應(yīng)的是ES5中的構(gòu)造函數(shù)Person,this關(guān)鍵字則代表實例對象。

里面的class類可以看做是構(gòu)造函數(shù)的另一種寫法,由typeof Person === 'function'為true;Person === Person.prototype.constructor為true可以得出,類的數(shù)據(jù)類型就是函數(shù),類本身指向構(gòu)造函數(shù)。也可以說class的底層依然是function構(gòu)造函數(shù)。

類的公共方法都定義在類的prototype屬性上。可以使用Object.assign一次向類添加多個方法。

特別的:class的內(nèi)部定義的方法都是不可枚舉的(non-enumerable),這一點與ES5的行為不一致。

ES5:

Object.keys(Person.prototype); // ['toString']

ES6:

Object.keys(Person.prototype); // Person {}

不可枚舉的代碼實現(xiàn)會在后面將ES6代碼用Babel轉(zhuǎn)碼之后解析。

new調(diào)用

效果:class類必須使用new調(diào)用,否則會報錯。

ES5:

Person()// undefined

ES6:

Person() // TypeError: Class constructor Person cannot be invoked without 'new'

實例的屬性

效果:實例的屬性是顯式定義在this對象上,否則都是定義在原型上。類的所有實例共享一個原型對象,與ES5行為一致。

ES5:

function Person() { this.grade = {  count: 0 };}

ES6:

class Person { constructor() {  this.grade = {   count: 0  }; }}

此外還要關(guān)注新提案,Babel已經(jīng)支持實例屬性和靜態(tài)屬性新的寫法。

靜態(tài)方法

類相當(dāng)于實例的原型,所有在類中定義的方法,都會被實例繼承。如果在一個方法前,加上static關(guān)鍵字,就表示該方法不會被實例繼承,而是直接通過類來調(diào)用,這就稱為“靜態(tài)方法”。

注意:如果靜態(tài)方法包含this關(guān)鍵字,指的是類。

ES5:

function Person() { }Person.toSay = function () { return 'I love JavaScript.';};Person.toSay(); // I love JavaScript.

ES6:

class Person { static toSay() {  return 'I love JavaScript.'; }}Person.toSay(); // I love JavaScript.

getter 和 setter

ES6提供 get 和 set 關(guān)鍵字,對某個屬性設(shè)置存值函數(shù)和取值函數(shù),攔截該屬性的存取行為,和ES5行為一致。

ES5:

function Person(name) {}Person.prototype = { get name() {  return 'mia'; }, set name(newName) {  console.log('new name:' + newName); }}

ES6:

class Person { get name() {  return 'mia'; } set name(newName) {  console.log('new name:' + newName); }}

ES6 class 底層實現(xiàn)原理

下文主要用babel轉(zhuǎn)碼器分別對class中幾個主要的方法進(jìn)行轉(zhuǎn)碼,分析ES5的實現(xiàn)方式。

Babel是如何編譯class的

將下面的代碼使用babel轉(zhuǎn)碼器轉(zhuǎn)換成ES5代碼,按照代碼結(jié)構(gòu)和功能分塊進(jìn)行講解。

class Person { constructor(name, age) {  this.name = name;  this.age = age; } toString() {  return '(' + this.name + ',' + this.age + ')'; }}var p = new Person('Mia', 18);

運行模式

"use strict";//class默認(rèn)開啟嚴(yán)格模式

私有函數(shù):

JS開發(fā)者在變量名或函數(shù)名前綴加下劃線,一般表示私有。

前綴加下劃線表示私有僅僅是一個約定俗成的習(xí)慣,澄清意圖,并沒有做其他處理。由于ECMAScript草案中并沒有定義私有變量的方法,所以在此限定之下仍可以在函數(shù)外或作用域外訪問該函數(shù)或變量。

_instanceof和_classCallCheck的作用

檢查聲明的class類是否通過new的方式調(diào)用,否則會報錯。

function _instanceof(left, right) { if (right != null && typeof Symbol !== "undefined" && right[Symbol.hasInstance]) {  return right[Symbol.hasInstance](left); } else {  return left instanceof right; }}function _classCallCheck(instance, Constructor) { if (!_instanceof(instance, Constructor)) {  throw new TypeError("Cannot call a class as a function"); }}

_createClass和_defineProperties的作用

_createClass函數(shù)有三個參數(shù),Constructor是傳入構(gòu)造函數(shù)Person,protoProps 是要添加到原型上的函數(shù)數(shù)組,staticProps 是要添加到構(gòu)造函數(shù)本身的函數(shù),即靜態(tài)方法。這里的第二個和第三個參數(shù)是可以缺省的,會在_createClass 函數(shù)體內(nèi)判斷。

_createClass 函數(shù)的作用是收集公有函數(shù)和靜態(tài)方法,將方法添加到構(gòu)造函數(shù)或構(gòu)造函數(shù)的原型中,并返回構(gòu)造函數(shù)。

defineProperties 是將方法添加到構(gòu)造函數(shù)或構(gòu)造函數(shù)的原型中的主要邏輯,遍歷函數(shù)數(shù)組,分別聲明其描述符。若enumerable 沒有被定義為true,則默認(rèn)為fals,設(shè)置 configurable 為true。以上兩個布爾值是為了限制 Object.keys() 之類的方法被遍歷到。如果存在 value,就為 descriptor 添加 value 和 writable 屬性,如果不存在,就直接使用 get 和 set 屬性。

最后,使用 Object.defineProperty 方法為構(gòu)造函數(shù)添加屬性。

function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) {  var descriptor = props[i];  descriptor.enumerable = descriptor.enumerable || false;  descriptor.configurable = true;  if ("value" in descriptor) descriptor.writable = true;  Object.defineProperty(target, descriptor.key, descriptor); }}function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor;}

class類實現(xiàn)

var Person = /*#__PURE__*/ function () {  function Person(name, age) {   _classCallCheck(this, Person);   this.name = name;   this.age = age;  }  _createClass(Person, [{   key: "toString",   value: function toString() {    return '(' + this.name + ',' + this.age + ')';   }  }]);  return Person; }();var p = new Person('Mia', 18);

解析:

不使用new調(diào)用時,this指向window,所以instance instanceof Constructor為false,拋出異常。

通過調(diào)用_createClass函數(shù),遍歷函數(shù)數(shù)組。key為方法名,若有value說明是有具體的 function 聲明,若無 value 說明使用了get 或 set 方法。

結(jié)尾

讀到這相信大家對class的實現(xiàn)有了更深的理解。最近筆者一邊在忙畢業(yè)設(shè)計,一邊整理了這道阿里前端面試題的解析,評論區(qū)歡迎對class實現(xiàn)這一問題進(jìn)行討論。另外,class中的extend也是很有趣的實現(xiàn),在下一篇文章會對class實現(xiàn)繼承進(jìn)行解析。

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持武林網(wǎng)。

發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 绿春县| 永德县| 琼结县| 元谋县| SHOW| 河西区| 平远县| 台安县| 洛隆县| 竹山县| 临清市| 弥渡县| 万全县| 新余市| 紫金县| 仪陇县| 东乡| 永靖县| 土默特左旗| 睢宁县| 延寿县| 龙岩市| 全椒县| 武邑县| 无锡市| 青冈县| 开远市| 安平县| 隆化县| 尖扎县| 文水县| 定安县| 油尖旺区| 兴隆县| 陕西省| 华安县| 彰化市| 甘洛县| 兰西县| 来宾市| 万安县|