摘要:防止類的構(gòu)造函數(shù)以普通函數(shù)的方式調(diào)用。這個(gè)函數(shù)的主要作用是通過給類添加方法,其中將靜態(tài)方法添加到構(gòu)造函數(shù)上,將非靜態(tài)的方法添加到構(gòu)造函數(shù)的原型對象上。
Class是ES6中新加入的繼承機(jī)制,實(shí)際是Javascript關(guān)于原型繼承機(jī)制的語法糖,本質(zhì)上是對原型繼承的封裝。本文將會討論:
1、ES6 class的實(shí)現(xiàn)細(xì)
2、相關(guān)Object API盤點(diǎn)
3、Javascript中的繼承實(shí)現(xiàn)方案盤點(diǎn)
class Person{ constructor(name, age){ this.name = name this.age = age } static type = "being" sayName (){ return this.name } static intro(){ console.log("") } } class Men extends Person{ constructor(name, age){ super() this.gender = "male" } }
const men = new Men()
以上代碼是ES6 class的基本使用方式,通過babel解析后,主要代碼結(jié)構(gòu)如下:
"use strict"; var _createClass = function () {...}();// 給類添加方法 function _possibleConstructorReturn(self, call) { ...}//實(shí)現(xiàn)super function _inherits(subClass, superClass) {...}// 實(shí)現(xiàn)繼承 function _classCallCheck(instance, Constructor) {...} // 防止以函數(shù)的方式調(diào)用class var Person = function () { function Person(name, age) { _classCallCheck(this, Person); this.name = name; this.age = age; } _createClass(Person, [{ key: "sayName", value: function sayName() { return this.name; } }], [{ key: "intro", value: function intro() { console.log(""); } }]); return Person; }(); Person.type = "being"; //靜態(tài)變量 var Men = function (_Person) { _inherits(Men, _Person); function Men(name, age) { _classCallCheck(this, Men); var _this = _possibleConstructorReturn(this, (Men.__proto__ || Object.getPrototypeOf(Men)).call(this)); _this.gender = "male"; return _this; } return Men; }(Person); var men = new Men();
為什么說es6的class 是基于原型繼承的封裝呢? 開始省略的四個(gè)函數(shù)又有什么作用呢?
下面,我們就從最開始的四個(gè)函數(shù)入手,詳細(xì)的解釋es6的class 是如何封裝的。
第一:_classCallCheck函數(shù), 檢驗(yàn)構(gòu)造函數(shù)的調(diào)用方式:
代碼
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
我們知道,在javascript中 person = new Person() ,通常完成以下幾件事:
1、創(chuàng)建一個(gè)新的對象 Object.create()
2、將 新對象的 this 指向 構(gòu)造函數(shù)的原型對象
3、新對象的__proto__ 指向 構(gòu)造函數(shù)
4、執(zhí)行構(gòu)造函數(shù)
而普通函數(shù)調(diào)用,this通常指向全局
因此,_classCallCheck函數(shù)是用來檢測類的調(diào)用方式。防止類的構(gòu)造函數(shù)以普通函數(shù)的方式調(diào)用。
第二: _createClass 給類添加方法
var _createClass = function () { 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); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); //非靜態(tài)函數(shù) -> 原型 if (staticProps) defineProperties(Constructor, staticProps); return Constructor; // 靜態(tài)函數(shù) -> 構(gòu)造函數(shù) }; }();
_createClass是一個(gè)閉包+立即執(zhí)行函數(shù),以這種方式模擬一個(gè)作用域,將defineProperties私有化。
這個(gè)函數(shù)的主要作用是通過Object.defineProperty給類添加方法,其中將靜態(tài)方法添加到構(gòu)造函數(shù)上,將非靜態(tài)的方法添加到構(gòu)造函數(shù)的原型對象上。
第三: _inherits 實(shí)現(xiàn)繼承
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, // 子類的原型的__proto__指向父類的原型 //給子類添加 constructor屬性 subclass.prototype.constructor === subclass { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } } ); if (superClass) //子類__proto__ 指向父類 Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
從這個(gè)函數(shù)就能夠很明顯的看出來,class實(shí)現(xiàn)繼承的機(jī)制了。
第四: _possibleConstructorReturn super()
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn"t been initialised - super() hasn"t been called"); //保證子類構(gòu)造函數(shù)中 顯式調(diào)用 super() } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
要想理解這個(gè)函數(shù)的作用,需要結(jié)合他的調(diào)用場景
var _this = _possibleConstructorReturn(this, (Men.__proto__ || Object.getPrototypeOf(Men)).call(this));// function Men(){}
此時(shí)已經(jīng)執(zhí)行完_inherits函數(shù),Men.__proto__ === Person
相當(dāng)于:
var _this = _possibleConstructorReturn(this, Person.call(this));
很明顯,就是將子類的this 指向父類。
API 總結(jié)根據(jù)以上的分析,es6 class 的實(shí)現(xiàn)機(jī)制也可以總結(jié)出來了:
毫無疑問的,class機(jī)制還是在prototype的基礎(chǔ)之上進(jìn)行封裝的
——contructor 執(zhí)行構(gòu)造函數(shù)相關(guān)賦值
——使用 Object.defineProperty()方法 將方法添加的構(gòu)造函數(shù)的原型上或構(gòu)造函數(shù)上
——使用 Object.create() 和 Object.setPrototypeOf 實(shí)現(xiàn)類之間的繼承 子類原型__proto__指向父類原型 子類構(gòu)造函數(shù)__proto__指向父類構(gòu)造函數(shù)
——通過變更子類的this 作用域?qū)崿F(xiàn)super()
1.原型鏈繼承
2.構(gòu)造函數(shù)繼承
3.組合繼承
4.ES6 extends 繼承
詳細(xì)內(nèi)容可以參考 聊一聊 JavaScript的繼承方式https://segmentfault.com/a/11...
后記終于寫完了,在沒有網(wǎng)絡(luò)輔助的情況下寫博客真是太難了!絕知此事要躬行呀!
原來覺得寫一篇關(guān)于class的博客還不簡單嗎,就是原型鏈繼承那一套唄,現(xiàn)在總結(jié)下來,還是有很多地方需要注意的;學(xué)習(xí)到了很多!嗯 不說了, 我還有好幾個(gè)坑要填呢~
如果這篇文章對你有幫助的話,歡迎點(diǎn)贊收藏!
如果你有疑問的話,希望積極留言,共同討論,共同進(jìn)步!
ES6—類的實(shí)現(xiàn)原理 https://segmentfault.com/a/11...
JavaScript 紅寶書
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/100918.html
摘要:組合繼承實(shí)現(xiàn)了屬性分離,方法共享下的完美繼承方案繼承我們的主角,,就是對組合繼承的改進(jìn)。這也是為什么在子類構(gòu)造函數(shù)中一定要顯示調(diào)用的原因。 談到繼承,或者更廣義上的:一個(gè)對象可以使用另外一個(gè)對象的屬性或方法。實(shí)現(xiàn)起來無外乎有兩種方式:apply or call 改變this的作用域原型繼承 改變__proto__指向,添加作用域鏈 而JavaScript所有的繼承實(shí)現(xiàn),都是圍繞以上兩點(diǎn)...
摘要:以上實(shí)現(xiàn)了最簡單的一個(gè)測試代碼當(dāng)然,這不能算是一個(gè),目前僅僅實(shí)現(xiàn)了根據(jù)狀態(tài)調(diào)用不同的回調(diào)函數(shù)。靜態(tài)函數(shù)接下來是的各種靜態(tài)函數(shù)每一個(gè)都執(zhí)行完畢后返回總結(jié)現(xiàn)在,一個(gè)完整的對象就完成了。 前言 說到 ES6,Promise 是繞不過的問題;如果說 ES6 的 Class 是基于 Javascript 原型繼承的封裝,那么 Promise 則是對 callback 回調(diào)機(jī)制的改進(jìn)。這篇文章,不...
摘要:前言與是目前圈子內(nèi)比較活躍的前端構(gòu)建工具。對于初學(xué)者來說,對這二者往往容易認(rèn)識不清,今天,就從事件的源頭,說清楚與。它可以將許多松散的模塊按照依賴和規(guī)則打包成符合生產(chǎn)環(huán)境部署的前端資源。打包后形成的文件出口。 前言:Webpack 與 gulp是目前圈子內(nèi)比較活躍的前端構(gòu)建工具。網(wǎng)上有很多二者比較的文章,面試中也會經(jīng)常遇到gulp,Webpack的區(qū)別這樣的問題。對于初學(xué)者來說,對這二...
摘要:前言無論是面試還是在討論瀏覽器優(yōu)化過程中,都會涉及到去抖動和節(jié)流的問題??偟膩碚f,這二者是一種限制事件觸發(fā)頻率的方式。不同的是,節(jié)流會指定事件觸發(fā)的時(shí)間間隔而去抖動會指定事件不觸發(fā)的時(shí)間間隔。 前言 無論是面試還是在討論瀏覽器優(yōu)化過程中,都會涉及到去抖動和節(jié)流的問題。總的來說,這二者是一種限制事件觸發(fā)頻率的方式。不同的是,節(jié)流會指定事件觸發(fā)的時(shí)間間隔;而去抖動會指定事件不觸發(fā)的時(shí)間間隔...
摘要:前言無論是面試還是在討論瀏覽器優(yōu)化過程中,都會涉及到去抖動和節(jié)流的問題??偟膩碚f,這二者是一種限制事件觸發(fā)頻率的方式。不同的是,節(jié)流會指定事件觸發(fā)的時(shí)間間隔而去抖動會指定事件不觸發(fā)的時(shí)間間隔。 前言 無論是面試還是在討論瀏覽器優(yōu)化過程中,都會涉及到去抖動和節(jié)流的問題??偟膩碚f,這二者是一種限制事件觸發(fā)頻率的方式。不同的是,節(jié)流會指定事件觸發(fā)的時(shí)間間隔;而去抖動會指定事件不觸發(fā)的時(shí)間間隔...
閱讀 3265·2023-04-26 01:31
閱讀 1904·2023-04-25 22:08
閱讀 3456·2021-09-01 11:42
閱讀 2833·2019-08-30 12:58
閱讀 2176·2019-08-29 18:31
閱讀 2440·2019-08-29 17:18
閱讀 3071·2019-08-29 13:01
閱讀 2559·2019-08-28 18:22