当前位置: 首页 > 工具软件 > Arale > 使用案例 >

Arale Class基类源码解析

欧阳山
2023-12-01

JS中OO的模拟有很多的实现与尝试(相关文章),Arale则在以下原则的指导下进行构建:

1.如无必要,勿增实体 —— Simple
2. 一目了然,容易学习 —— Stupid

Class源码的学习可以通过了解如何调用Class来实现类的继承与扩展的例子进行学习。下面是对Class类的源码的注释(简单的辅助方法不再进行注释),有问题可指出,欢迎交流。

// The base Class implementation.
// 基本的Class类的构造函数
// --直接调用该构造函数,传入的类o将被包裹,拥有extend和implement方法。
function Class(o) {
// Convert existed function to Class.
	if (!(this instanceof Class) && isFunction(o)) {
		return classify(o)
	}
}
// commonJS规范
module.exports = Class
// Create a new Class.
//
// var SuperPig = Class.create({
// Extends: Animal,
// Implements: Flyable,
// initialize: function() {
// SuperPig.superclass.initialize.apply(this, arguments)
// },
// Statics: {
// COLOR: 'red'
// }
// })
// 核心方法,返回一个新创建的子类
// --如果传入了父类parent以及传递给子类原型的properties对象,则分别继承父类的实例方法以及静态属性
// --如果只传入了properties对象,则默认将parent置为该对象的Extends属性值,没有该属性则默认置为Class
Class.create = function(parent, properties) {
	// 强制parent为函数类型,properties(最好)为对象
	if (!isFunction(parent)) {
		properties = parent
		parent = null
	}
	properties || (properties = {}) // 防报错,默认置为空对象
	parent || (parent = properties.Extends || Class)// Subclass需要继承的父类
	properties.Extends = parent //将父类置为properties的Extends属性值(可参考上面调用Class.create的例子)
	// The created class constructor
	// 创建类的构造函数
	function SubClass() {
		// 调用父类的构造函数,继承其中的实例方法
		parent.apply(this, arguments)
		// 在构造函数为Subclass自身且具有initialize实例方法的时候执行初始化方法
		if (this.constructor === SubClass && this.initialize) {
			this.initialize.apply(this, arguments)
		}
	}
	// Inherit class (static) properties from parent.
	// 将父类的静态方法mix给Subclass(可在父类StaticsWhiteList属性中指定要继承的属性)
	if (parent !== Class) {
		mix(SubClass, parent, parent.StaticsWhiteList)
	}
	// Add instance properties to the subclass.
	// 该方法特别重要。遍历properties的所有属性,如果该属性名存在于Class.Mutators中(Extends,Implements,Statics),
	// 则执行Class.Mutators对应的方法,否则将该属性对应的值赋给Subclass的原型链作为其实例属性
	// 因此,Class.Mutators的所有方法中的this指向Subclass,这一点需要注意
	implement.call(SubClass, properties)
	// Make subclass extendable.类化Subclass,使其可扩展可继承其他类
	return classify(SubClass)
}
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
		}
	}
}
// Create a sub Class based on `Class`.
// 基于Class创建子类
Class.extend = function(properties) {
	properties || (properties = {})
	properties.Extends = this
	return Class.create(properties)
}
// 类化构造函数cls,使其具有extend以及implement方法,从而使其能够轻松进行扩展
function classify(cls) {
	cls.extend = Class.extend 
	cls.implement = implement
	return cls
}
// Mutators define special properties.
// Class.Mutators定义了三个特定的属性,从而在调用Class.create的时候如果用户传入了对应的属性则进行对应方法的调用
// 注意:三个函数中的this都指向新创建的Subclass
Class.Mutators = {
	'Extends': function(parent) {
		// 新创建类的原型
		var existed = this.prototype
		// 创建以父类原型为原型对象的对象(该对象继承自parent.prototype)
		var proto = createProto(parent.prototype)
		// Keep existed properties.将Subclass的静态属性mix给proto
		mix(proto, existed)
		// Enforce the constructor to be what we expect.
		// 将proto的构造函数指向Subclass
		proto.constructor = this
		// Set the prototype chain to inherit from `parent`.
		// Subclass的原型指向proto,proto的原型指向parent.prototype,从而形成原型链继承
		this.prototype = proto
		// Set a convenience property in case the parent's prototype is needed later.
		// 方便对父类的原型的方法和属性进行调用
		this.superclass = parent.prototype
	},
	// implements为JS保留关键字,故开头大写
	'Implements': function(items) {
		// 保证参数为数组,方便后面调用
		isArray(items) || (items = [items])
		var proto = this.prototype, item
		while (item = items.shift()) {
			// 直接将被继承对象的原型(不是类的则将其本身)的属性赋值给Subclass原型
			mix(proto, item.prototype || item)
		}
	},
	// 静态属性
	'Statics': function(staticProperties) {
		mix(this, staticProperties)
	}
}
// Shared empty constructor function to aid in prototype-chain creation.
function Ctor() {}
// See: http://jsperf.com/object-create-vs-new-ctor
var createProto = Object.__proto__ ?
	function(proto) {
		return { __proto__: proto }
	} :
	function(proto) {
		Ctor.prototype = proto
		return new Ctor()
	}
// Helpers
// ------------
function mix(r, s, wl) {
	// Copy "all" properties including inherited ones.
	for (var p in s) {
		if (s.hasOwnProperty(p)) {
			if (wl && indexOf(wl, p) === -1) continue
			// 在 iPhone 1 代等设备的 Safari 中,prototype 也会被枚举出来,需排除
			if (p !== 'prototype') {
				r[p] = s[p]
			}
		}
	}
}
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]'
}
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
	}


 类似资料: