arale 是阿里、开源社区明星人物–玉伯,开辟的一套组件,代码相称幽美,大赞玉伯的开源精力,我是您的粉丝。
这里分享下我对这段源代码的感悟,如有毛病的处所,烦请斧正。= ̄ω ̄=
先谈谈基于原型的继承。
先看看 segementfault 上议论的一道题。
function F() {}
Object.prototype.a = function() {}
Function.prototype.b = function() {}
var f = new F()
// F.a F.b f.a
F 能够挪用 a 和 b,由于 F 的原型链是如许的。(直观诠释:F 是 Function 实例,F 继承自 Object)
F ----> Function.prototype ----> Object.prototype ----> null
//既 F.__proto__ === Function.prototype
// Function.prototype.__proto__ === Object.prototype
// Object.prototype.__proto__ === null
而 f 只能挪用 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();
到这里,基于原型链的继承已很明显了,只需要
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 的封装
// 竖立原型链
function Ctor() {};
var createProto = Object.__proto__ ? function(proto) {
return {
__proto__: proto
}
} : function(proto) {
Ctor.prototype = proto;
return new Ctor();
}
有三种写法能够完成原型链继承,然则我测试 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
症结字挪用时,将参数 类化
,如:
修正:是不支撑
new
的体式格局挪用。
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;
// 竖立原型链来完成继承
var proto = createProto(parent.prototype);
mix(proto, existed);
// 强迫转变组织函数
proto.constructor = this;
this.prototype = proto;
// 供应 superclass 语法糖,来挪用父类属性
this.superclass = parent.prototype;
},
// 混入属性,能够混入多个类的属性
Implements: function(items) {
// 将参数变成数组
isArray(items) || (items = [ items ]);
var proto = this.prototype, item;
while (item = items.shift()) {
// 不管参数是 类(Function),照样 对象(Object),都混入。
mix(proto, item.prototype || item);
}
},
Statics: function(staticProperties) {
// 直接混入静态属性。
mix(this, staticProperties);
}
}
再来看看 implement
要领, 它是用来混入属性的。
三个变种属性将被实行
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
来了,它是用来竖立类的,能够指定父类。
Class.create = function(parent, properties) {
// 假如没有指定父类,父类就是 Class
if (!isFunction(parent)) {
properties = parent;
parent = null;
}
properties || (properties = {});
// 假如指定了 Extends 属性, 父类就是它了
parent || (parent = properties.Extends || Class);
properties.Extends = parent;
// 竖立子类的组织函数
function SubClass() {
// 挪用父类的组织函数
parent.apply(this, arguments);
// 仅挪用本身的初始化要领,initialize
if (this.constructor === SubClass && this.initialize) {
this.initialize.apply(this, arguments);
}
}
// 指定父类的情况下,继承父类的属性
if (parent !== Class) {
Mix(SubClass, parent, parent.StaticsWhiteList);
}
// 为子类增添实例属性,三个特别属性,在这里被实行
implement.call(SubClass, properties);
// 返回可继承 继承 的子类
return classify(SubClass);
}
末了来看看继承的要领 Class.extend
,被 classify 的类,都能够继承竖立子类。
Class.extend = function(properties) {
properties || (properties = {});
// 指定父类为挪用者
properties.Extends = this;
return Class.create(properties);
}
末了的末了,简朴引见它的东西类,Helpers
// 属性夹杂,增添白名单限定
function mix(r, s, wl) {
for (var p in s) {
// 最好实践:任何 for in 轮回都要带上 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]";
}