摘要:同時,創建的子類有幾個固定字段,分別是初始化函數原型初始化函數對象通過這個函數,把基類和子類的函數合并執行,這樣解決了基類構造函數無法執行的問題。二是構造函數可能不止會操作,還可能會修改全局的某些狀態比如計數器。
綜述
在 ES6 之前,ES5 實現面向對象是大家經常討論的問題,趁著 ES6 還沒進入瀏覽器,借我自己的一段腳本,跟大家討論一下 js 面向對象的一些細節問題,歡迎留言指教。
例子代碼基本的概念比如“基類”,“子類”等就不解釋了。下面是我寫的一段實現類繼承的 js 腳本:
/** * @file Inheritable.js * @author Y3G * @fileoverview * 可繼承對象 */ var _ = require("lodash"); var assert = require("./assert"); var seq = require("./seq"); /** * 并聯函數 * @return 生成的函數 */ var parallel = function () { var fns = _.filter(arguments, _.isFunction); if (fns.length === 0) return; return function () { _.forEach(fns, function (fn) { fn.apply(this, _.slice(arguments)); }); }; } /** * 創建類 * @param base 基類函數或原型對象 * @param ex 實例擴展 * @return 生成的類函數 * 默認方法: * __init__: 構造函數 * __initProto__: 原型構造函數 * 默認類方法: * makeClass: 創建類 * makeSubClass: 創建子類 */ function makeClass(base, ex) { base = base || {}; ex = ex || {}; var proto = _.isFunction(base) ? new base(true) : base; ex.__init__ = parallel(proto.__init__, ex.__init__); // 實例初始化函數 ex.__initProto__ = parallel(proto.__initProto__, ex.__initProto__); // 原型初始化函數 proto = _.mixin(proto, ex); // 合并原型和實例擴展 function SubClass(isProto) { var initFunc = isProto ? this.__initProto__ : this.__init__; if (_.isFunction(initFunc)) { initFunc.apply(this, _.slice(arguments)); } this.$id = seq(); } if (_.isFunction(base)) { // 復制靜態函數等屬性到子類 _.forOwn(base, function (val, key) { SubClass[key] = val; }); } SubClass.prototype = proto; SubClass.prototype.constructor = SubClass; SubClass.makeSubClass = _.curry(makeClass, SubClass); SubClass.makeClass = makeClass; return SubClass; } /** * 根基類 * @class Root */ var Root = makeClass(); module.exports = Root;
這段代碼導出了一個根基類 Root,它有一個靜態方法叫做 makeSubClass,調用可生成一個 Root 的子類,創建出的子類同樣帶有 makeSubClass 這個靜態方法。同時,創建的子類有幾個固定字段,分別是:
__init__ 初始化函數
__initProto__ 原型初始化函數
$id 對象 id
通過 parallel 這個函數,makeClass 把基類和子類的 __init__ 函數合并執行,這樣解決了基類構造函數無法執行的問題。
下面說說我對幾個細節問題的思考。
幾個問題和我的看法問:構造函數 __init__ 的執行順序是基類 -> 子類比較好還是子類 -> 基類比較好?
答:
按照我貼的代碼,是基類的構造函數先執行,當時我是想模仿 C++。但是我現在認為應該子類構造函數先執行。
原因很簡單,就是 ES6 使用的是類 java 方式, constructor 函數是子類先執行的,并且基類 constructor 是靠
super() 手工調用的。基于一點 java 的使用經驗,我也認為這樣的構造順序,比基類 -> 子類靈活不少。另外,采用和 ES6 一樣的構造順序,更有利于移植。
問:__initProto__ 是什么鬼?
答:
這是我一直以來堅持的看法——用 js 模擬類,如果一個類的實例有可能作為 prototype 存在,就必須把實例構造和 prototype
構造分開,而 __initProto__ 就是專門用來初始化 prototype 的。原因有兩方面:
一是對象可能會很昂貴,占很多資源。
二是構造函數 __init__ 可能不止會操作 this,還可能會修改全局的某些狀態(比如計數器)。這種時候多創建一個和少創建一個實例,顯然是不同的。
問:為什么要把基類函數上的靜態內容都拷貝到子類函數上?
答:
因為原型鏈查找對靜態內容無效。
比如這樣:
var Foo = Root.makeSubClass({}); Foo.SOME_STATIC_THING = 0; var Bar = Foo.makeSubClass({}); alert(Bar.SOME_STATIC_THING);這時候假設不拷貝 SOME_STATIC_THING 到子類上去,就不能通過 Bar.SOME_STATIC_THING 訪問到該屬性。這是非常違反常識的,沒有語言是這樣子的。同時,現在又有了另一個這么做的理由,就是 ES6 有 static
關鍵字,如果你使用其他方式實現靜態屬性,將不利于以后移植到 ES6。不過這里有個小坑,就如果靜態變量是基本類型(比如字符串),那么顯然在子類上修改對基類無效。于是基本類型的靜態變量只能是常量,如果需要非常量的靜態變量,必須使用對象。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/79802.html
摘要:眾多面向對象的編程思想雖不盡一致,但是無論哪種面向對象編程語言都具有以下的共通功能。原型編程以類為中心的傳統面向對象編程,是以類為基礎生成新對象。而原型模式的面向對象編程語言沒有類這樣一個概念。 什么是面向對象?這個問題往往會問到剛畢業的新手or實習生上,也是往往作為一個技術面試的開頭題。在這里我們不去談如何答(fu)好(yan)問(guo)題(qu),僅談談我所理解的面向對象。 從歷...
摘要:很多情況下,通常一個人類,即創建了一個具體的對象。對象就是數據,對象本身不包含方法。類是相似對象的描述,稱為類的定義,是該類對象的藍圖或原型。在中,對象通過對類的實體化形成的對象。一類的對象抽取出來。注意中,對象一定是通過類的實例化來的。 showImg(https://segmentfault.com/img/bVTJ3H?w=900&h=385); 馬上就要到七夕了,離年底老媽老爸...
摘要:很多情況下,通常一個人類,即創建了一個具體的對象。對象就是數據,對象本身不包含方法。類是相似對象的描述,稱為類的定義,是該類對象的藍圖或原型。在中,對象通過對類的實體化形成的對象。一類的對象抽取出來。注意中,對象一定是通過類的實例化來的。 showImg(https://segmentfault.com/img/bVTJ3H?w=900&h=385); 馬上就要到七夕了,離年底老媽老爸...
摘要:很多情況下,通常一個人類,即創建了一個具體的對象。對象就是數據,對象本身不包含方法。類是相似對象的描述,稱為類的定義,是該類對象的藍圖或原型。在中,對象通過對類的實體化形成的對象。一類的對象抽取出來。注意中,對象一定是通過類的實例化來的。 showImg(https://segmentfault.com/img/bVTJ3H?w=900&h=385); 馬上就要到七夕了,離年底老媽老爸...
摘要:當你真正到公司里面從事了幾年開發之后,你就會同意我的說法利用找工作,需要的就是項目經驗,項目經驗就是理解項目開發的基本過程,理解項目的分析方法,理解項目的設計思 Java就是用來做項目的!Java的主要應用領域就是企業級的項目開發!要想從事企業級的項目開發,你必須掌握如下要點: 1、掌握項目開發的基本步驟 2、具備極強的面向對象的分析與設計技巧 3、掌握用例驅動、以架構為核心的主流開發...
閱讀 1650·2021-11-16 11:44
閱讀 2393·2021-10-11 11:07
閱讀 4036·2021-10-09 09:41
閱讀 663·2021-09-22 15:52
閱讀 3187·2021-09-09 09:33
閱讀 2702·2019-08-30 15:55
閱讀 2284·2019-08-30 15:55
閱讀 837·2019-08-30 15:55