摘要:擁有了和方法的三個變種屬性這三個屬性會做特殊處理繼承的方法,只支持單繼承建立原型鏈來實現(xiàn)繼承強制改變構(gòu)造函數(shù)提供語法糖,來調(diào)用父類屬性混入屬性,可以混入多個類的屬性將參數(shù)變成數(shù)組無論參數(shù)是類,還是對象,都混入。
更新:讀 arale 源碼之 attribute 篇
arale 是阿里、開源社區(qū)明星人物--玉伯,開發(fā)的一套組件,代碼相當優(yōu)美,大贊玉伯的開源精神,我是您的粉絲。
這里分享下我對這段源代碼的感悟,若有錯誤的地方,煩請指正。= ̄ω ̄=
先談談基于原型的繼承。先看看 segementfault 上討論的一道題。
function F() {} Object.prototype.a = function() {} Function.prototype.b = function() {} var f = new F() // F.a F.b f.a
F 可以調(diào)用 a 和 b,因為 F 的原型鏈是這樣的。(直觀解釋:F 是 Function 實例,F(xiàn) 繼承自 Object)
F ----> Function.prototype ----> Object.prototype ----> null //既 F.__proto__ === Function.prototype // Function.prototype.__proto__ === Object.prototype // Object.prototype.__proto__ === null
而 f 只能調(diào)用 a , f 的原型鏈是這樣的。(直觀解釋:f 是 F 的實例,一切皆對象,f 繼承自 Object)
f ----> F.prototype ----> Object.prototype ----> null //既 f.__proto__ === F.prototype // F.prototype.__proto__ === Object.prototype // Object.prototype.__proto__ === null
在 f 的原型鏈上并沒有 Function.prototype . 因此訪問不到 b 。
注意,訪問原型對象 __proto__ 是非標準方法,ES5 標準方法是 Object.getPrototypeOf();
到這里,基于原型鏈的繼承已經(jīng)很明顯了,只需要
function Animal() {} function Dog() {} Dog.prototype.__proto__ = Animal.prototype; var dog = new Dog(); // dog.__proto__ --> Dog.prototype; // dog.__proto__.__proto__ --> Animal.prototype
基于 ES5 標準寫法是
Dog.prototype = Object.create(Animal.prototype);來看看 arale 的封裝
// 創(chuàng)建原型鏈 function Ctor() {}; var createProto = Object.__proto__ ? function(proto) { return { __proto__: proto } } : function(proto) { Ctor.prototype = proto; return new Ctor(); }
有三種寫法可以實現(xiàn)原型鏈繼承,但是我測試 new Ctor 是最慢的啊,Object.creaete 其次,__proto__ 是最快的。
function Ctor() {} function getProto1(proto, c) { Ctor.prototype = proto; var o = new Ctor(); o.constructor = c; return o; } function getProto2(proto, c) { return Object.create(proto, { constructor: { value: c } }) } function getProto3(proto, c) { return { __proto__: proto, constructor: c } }
接著往下看。。。
function Class(o) { if (!(this instanceof Class) && isFunction(o)) { return classify(o); } } function classify(cls) { cls.extend = Class.extend; cls.implement = implement; return cls; }
這種寫法是,當不使用 new 關鍵字調(diào)用時,將參數(shù) 類化,如:
修改:是不支持 new 的方式調(diào)用。
function Animal() {} Animal.prototype.talk = function() {} //Class(Animal); Animal 擁有了 extend 和 implement 方法 var Dog = Class(Animal).extend({ swim: function() {} })
Class 的三個變種屬性 Extends Implements Statics
這三個屬性會做特殊處理
Class.Mutators = { // 繼承的方法,只支持單繼承 Extends: function(parent) { var existed = this.prototype; // 建立原型鏈來實現(xiàn)繼承 var proto = createProto(parent.prototype); mix(proto, existed); // 強制改變構(gòu)造函數(shù) proto.constructor = this; this.prototype = proto; // 提供 superclass 語法糖,來調(diào)用父類屬性 this.superclass = parent.prototype; }, // 混入屬性,可以混入多個類的屬性 Implements: function(items) { // 將參數(shù)變成數(shù)組 isArray(items) || (items = [ items ]); var proto = this.prototype, item; while (item = items.shift()) { // 無論參數(shù)是 類(Function),還是 對象(Object),都混入。 mix(proto, item.prototype || item); } }, Statics: function(staticProperties) { // 直接混入靜態(tài)屬性。 mix(this, staticProperties); } }
再來看看 implement 方法, 它是用來混入屬性的。
三個變種屬性將被執(zhí)行
function implement(properties) { var key, value; for (key in properties) { value = properties[key]; if (Class.Mutators.hasOwnProperty(key)) { Class.Mutators[key].call(this, value); } else { this.prototype[key] = value; } } }
好了,最關鍵的方法 Class.create 來了,它是用來創(chuàng)建類的,可以指定父類。
Class.create = function(parent, properties) { // 如果沒有指定父類,父類就是 Class if (!isFunction(parent)) { properties = parent; parent = null; } properties || (properties = {}); // 如果指定了 Extends 屬性, 父類就是它了 parent || (parent = properties.Extends || Class); properties.Extends = parent; // 創(chuàng)建子類的構(gòu)造函數(shù) function SubClass() { // 調(diào)用父類的構(gòu)造函數(shù) parent.apply(this, arguments); // 僅調(diào)用自身的初始化方法,initialize if (this.constructor === SubClass && this.initialize) { this.initialize.apply(this, arguments); } } // 指定父類的情況下,繼承父類的屬性 if (parent !== Class) { Mix(SubClass, parent, parent.StaticsWhiteList); } // 為子類添加實例屬性,三個特殊屬性,在這里被執(zhí)行 implement.call(SubClass, properties); // 返回可繼續(xù) 繼承 的子類 return classify(SubClass); }
最后來看看繼承的方法 Class.extend ,被 classify 的類,都可以繼續(xù)創(chuàng)建子類。
Class.extend = function(properties) { properties || (properties = {}); // 指定父類為調(diào)用者 properties.Extends = this; return Class.create(properties); }
最后的最后,簡單介紹它的工具類,Helpers
// 屬性混合,增加白名單限制 function mix(r, s, wl) { for (var p in s) { // 最佳實踐:任何 for in 循環(huán)都要帶上 hasOwnProperty。除非你想遍歷原型 if (s.hasOwnProperty(p)) { if (wl && indexOf(wl, p) === -1) continue; if (p !== "prototype") { r[p] = s[p]; } } } } // [].indexOf 是 ES5 加入的,并非所有瀏覽器都支持。 // 這里沒有也不需要使用 polyfill 的方式。 var indexOf = Array.prototype.indexOf ? function(arr, item) { return arr.indexOf(item); } : function(arr, item) { for (var i = 0, len = arr.length; i < len; i++) { if (arr[i] === item) { return i; } } return -1; } // 這個很簡單,只有 Object.prototype.toString 才能知道它的 [[class]] var toString = Object.prototype.toString; var isArray = Array.isArray || function(val) { return toString.call(val) === "[object Array]"; } var isFunction = function(val) { return toString.call(val) === "[object Function]"; }
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/85987.html
摘要:系列文章讀源碼之篇提供基本的屬性添加獲取移除等功能。判斷是否為等對象特性檢查閉包實現(xiàn)塊作用域,不污染全局變量。找這個屬性,若沒有則返回空對象執(zhí)行函數(shù),返回被修改的值。 系列文章:讀 arale 源碼之 class 篇 attributes 提供基本的屬性添加、獲取、移除等功能。它是與實例相關的狀態(tài)信息,可讀可寫,發(fā)生變化時,會自動觸發(fā)相關事件 先來了解一下 Attribute 模塊要實...
摘要:本文同步自我的博客前言這個模塊實際上才是模塊系統(tǒng)中對外的模塊,它包含了之前介紹的類和類,以及自己內(nèi)部的模塊和模塊,因此模塊是真正的基礎類。這兩個方法的作用就是針對類上的某個方法,給這個方法綁定先于其執(zhí)行和后于其執(zhí)行的回調(diào)函數(shù)。 本文同步自我的GitHub博客 前言 Base這個模塊實際上才是Arale模塊系統(tǒng)中對外的模塊,它包含了之前介紹的Class類和Events類,以及自己內(nèi)部...
摘要:先來看源碼中,首先是做的是參數(shù)的處理工作,針對某些參數(shù)未傳的情況作了調(diào)整,最后達到的效果是的值為傳入的父類構(gòu)造函數(shù),如果沒有,設為。下一個語句其作用是處理父類構(gòu)造函數(shù)沒有修改的屬性值并且有方法的時候,在上調(diào)用方法。 本文同步自我的GitHub 概述 Arale是支付寶開發(fā)的一套基礎類庫,提供了一整套前端模塊架構(gòu),基于CMD規(guī)范,所有模塊均是以sea.js的標準進行開發(fā)。其開發(fā)過程借...
摘要:在方法執(zhí)行后,再執(zhí)行函數(shù)函數(shù)在執(zhí)行時,接收的參數(shù)第一個是的返回值,之后的參數(shù)和傳給相同。的返回值源碼定義兩個出口定義一個可柯里化的函數(shù),柯里化成函數(shù)指向基于生成的類的實例,如上例的如果該函數(shù)是第一次切面化綁定,則包裝該函數(shù)。 系列文章:讀 arale 源碼之 class 篇 使用 Aspect,可以允許你在指定方法執(zhí)行的前后插入特定函數(shù) before object.before(me...
摘要:今天我偷偷的去上喵了幾眼,發(fā)現(xiàn)我捉出來的,還沒被消滅掉,看來有必要發(fā)個郵件給高陽了。還得到了高陽的飯約,因為我們捉了好幾個的,高陽你別忘啊下面就上幾張我們的的靚照吧的獲獎自之后,我們還是很有自信能得個獎的。 BugLife的誕生記 先自我介紹下我們團隊,Wellming、Bell orchid、Retamia,三枚程序員,主要技能點PHP,目前在一家棒棒的做開源網(wǎng)校系統(tǒng)(EduSoho...
閱讀 2117·2023-04-26 00:41
閱讀 1153·2021-09-24 10:34
閱讀 3578·2021-09-23 11:21
閱讀 4070·2021-09-22 15:06
閱讀 1562·2019-08-30 15:55
閱讀 904·2019-08-30 15:54
閱讀 1833·2019-08-30 15:48
閱讀 555·2019-08-29 13:58