js继承 Base类的源码解析


Posted in Javascript onDecember 30, 2008

// timestamp: Tue, 01 May 2007 19:13:00
/*
base2.js - copyright 2007, Dean Edwards
http://www.opensource.org/licenses/mit-license
*/
// You know, writing a javascript library is awfully time consuming.
//////////////////// BEGIN: CLOSURE ////////////////////
// =========================================================================
// base2/Base.js
// =========================================================================
// version 1.1
var Base = function(){
// call this method from any other method to invoke that method's ancestor
};
Base.prototype = {
extend: function(source){
//参数大于一个时
if (arguments.length > 1) { // extending with a name/value pair
//获得proto的祖先
var ancestor = this[source];
var value = arguments[1];
//如果value(第二个参数)是function,并且祖先对象存在,在重载函数中调用base时
if (typeof value == "function" && ancestor && /\bbase\b/.test(value)) {
// get the underlying method
var method = value;
// override
value = function(){
var previous = this.base;
this.base = ancestor;
//上溯到父类对象
var returnValue = method.apply(this, arguments);
this.base = previous;
return returnValue;
};
value.method = method;
value.ancestor = ancestor;
}
this[source] = value;
}
else
if (source) { // extending with an object literal 用一个对象列表来扩展
var extend = Base.prototype.extend;
/**
* 1.扩展原型方法和属性 2.
*/
//如果是扩展属于原型的方法或属性,先遍历其重载Object的3个方法
if (Base._prototyping) {
var key, i = 0, members = ["constructor", "toString", "valueOf"];
while (key = members[i++]) {
//如果是重载了这些方法
if (source[key] != Object.prototype[key]) {
/**
* 逐个扩展,用call的原因是要将extend的上下文改为要扩展的源this,
* 既是新建对象的父类对象
*/
extend.call(this, key, source[key]);
}
}
}
else
if (typeof this != "function") {
// if the object has a customised extend() method then use it
extend = this.extend || extend;
}
// copy each of the source object's properties to this object
for (key in source)
if (!Object.prototype[key]) {
extend.call(this, key, source[key]);
}
}
return this;
},
base: Base
};
Base.extend = function(_instance, _static){ // subclass
/**
* Base类原型的扩展别名,将这个当成一个方法调用
*/
var extend = Base.prototype.extend;
/**
* build the prototype,创建原型
* 设置原型标志
*/
Base._prototyping = true;
/**
* 创建一个Base的实例,初始化继承部分
* 继承方式大致还是以下方式
* function A(){}
* function B(){
* this.b=[];
* }
* A.prototype=new B();//A继承B的所有属性和方法
* 这种继承方式会有一个问题,B中声明的对象(如b)以prototype的形式
* 被A继承之后,prototype只是生成一个指向B中对象的引用,即
* A所有实例会共同享有B中对象(b)
* var a1=new A();
* var a2=new A();
* a1.b.push("a11");
* a2.b.push("a21");
* 此时,a1.b=a2.b=["a11","a21"],
*
* Dean Edwards在实现继承的时候,以父类为基础,创建实例,
* 利用extend扩展该实例,最后用A.prototype=new B();实现继承
* 但是属性是对象的时候没有做处理,
* 还是没有避开上述的继承缺陷
*/
var proto=new this;
/**
* 在这里,不可以用 proto.extend(_instance)代替
*/
extend.call(proto, _instance);
/**
* 类实例属性和方法的原型部分构造完毕,删除标志位
*/
delete Base._prototyping;
/**
* 这里作者运用了适配器的模式,用自定义的构造器生成一个新的类对象
* wrapper/adapter:通过一定的方法,一个对象封装或授权另一个
* 对象来改变它的接口或者行为
*/
// create the wrapper for the constructor function
/**
* 获得构造器的引用
*/
var constructor = proto.constructor;
/**
* 建立klass的Function对象,调用自定义的构造器, klass就是衍生的子类
* 两种情况下,调用此方法:
* 1.创建类实例的时候,这时候不是原型构造阶段,执行由extend方法
* 继承的时候设定的构造方法
* 2.当用extend方法衍生子类的时候---new this
* 因为下文中klass的属性已经全部获得,
* 所以当new完之后,获得所有父类的方法和属性都包含在了
* proto里面了,这时候,在proto的基础上运用prototype的extend方法
* 将此子类的属性和方法添加到proto里面
*/
var klass = proto.constructor = function(){
/**
* var proto=new this; 调用父类的构造函数,创建一个父类的实例
* new this用完后,函数重定向到子类对象构造方法
*/
if (!Base._prototyping) {
/**
* 当在构造函数中(constructor)调用base方法时,
* base方法会调用父类对象的构造函数,这时候会嵌套
* 调用这个代码段,方法得以执行的条件就是this._constructing==true
*/
if (this._constructing || this.constructor == klass) { // instantiation
this._constructing = true;
constructor.apply(this, arguments);
delete this._constructing;
}
/**
*
* 不再向下执行
*/
else { // casting
var object = arguments[0];
if (object != null) {
(object.extend || extend).call(object, proto);
}
return object;
}
}
};
// build the class interface
/**
*
*/
for (var i in Base){
klass[i] = this[i];
}
/**
* 创建继承链
*/
klass.ancestor = this;
klass.base = Base.base;
klass.prototype = proto;
klass.toString = this.toString;
/**
* 扩展类方法,属性,类似java的static
*/
extend.call(klass, _static);
// class initialisation 如果存在init函数 调用
if (typeof klass.init == "function")
klass.init();
return klass;
};
// initialise
Base = Base.extend({
constructor: function(){
this.extend(arguments[0]);
}
}, {
ancestor: Object,
base: Base,
implement: function(_interface){
if (typeof _interface == "function") {
// if it's a function, call it
_interface(this.prototype);
}
else {
// add the interface using the extend() method
this.prototype.extend(_interface);
}
return this;
}
});

Javascript 相关文章推荐
javascript网页关闭时提醒效果脚本
Oct 22 Javascript
js写一个字符串转成驼峰的实例
Jun 21 Javascript
jquery实现图片渐变切换兼容ie6/Chrome/Firefox
Aug 02 Javascript
javascript中全局对象的isNaN()方法使用介绍
Dec 19 Javascript
JS实现div居中示例
Apr 17 Javascript
JS判断浏览器是否支持某一个CSS3属性的方法
Oct 17 Javascript
javascript获得当前的信息的一些常用命令
Feb 25 Javascript
JS 对象属性相关(检查属性、枚举属性等)
Apr 05 Javascript
Javascript中return的使用与闭包详解
Jan 11 Javascript
AngularJS表单提交实例详解
Feb 18 Javascript
vue实现输入框自动跳转功能
May 20 Javascript
Vue操作Storage本地化存储
Apr 29 Vue.js
动态创建的表格单元格中的事件实现代码
Dec 30 #Javascript
javascript FormatNumber函数实现方法
Dec 30 #Javascript
js 图片轮播(5张图片)
Dec 30 #Javascript
走出JavaScript初学困境—js初学
Dec 29 #Javascript
ExtJS 简介 让你知道extjs是什么
Dec 29 #Javascript
不用写JS也能使用EXTJS视频演示
Dec 29 #Javascript
My Desktop :) 桌面式代码
Dec 29 #Javascript
You might like
PHP将整个网站生成HTML纯静态网页的方法总结
2012/02/05 PHP
PHP set_error_handler()函数使用详解(示例)
2013/11/12 PHP
PHP_NETWORK_GETADDRESSES: GETADDRINFO FAILED问题解决办法
2014/05/04 PHP
微信第三方登录(原生)demo【必看篇】
2017/05/26 PHP
缓动函数requestAnimationFrame 更好的实现浏览器经动画
2012/12/07 Javascript
jQuery层次选择器选择元素使用介绍
2013/04/18 Javascript
BOM系列第一篇之定时器setTimeout和setInterval
2016/08/17 Javascript
详解JavaScript跨域总结与解决办法
2016/10/31 Javascript
原生JavaScript实现Ajax异步请求
2017/11/19 Javascript
浅析从vue源码看观察者模式
2018/01/29 Javascript
vue实现通讯录功能
2018/07/14 Javascript
使用elementUI实现将图片上传到本地的示例
2018/09/04 Javascript
微信小程序实现留言板功能
2018/11/02 Javascript
jQuery判断自定义属性data-val用法示例
2019/01/07 jQuery
react组件从搭建脚手架到在npm发布的步骤实现
2019/01/09 Javascript
微信小程序时间标签和时间范围的联动效果
2019/02/15 Javascript
浅谈vue中document.getElementById()拿到的是原值的问题
2020/07/26 Javascript
python打开文件并获取文件相关属性的方法
2015/04/23 Python
在Python的Django框架中调用方法和处理无效变量
2015/07/15 Python
python如何去除字符串中不想要的字符
2020/07/05 Python
python3中pip3安装出错,找不到SSL的解决方式
2019/12/12 Python
使用Keras预训练好的模型进行目标类别预测详解
2020/06/27 Python
python tkinter实现下载进度条及抖音视频去水印原理
2021/02/07 Python
美国花布包包品牌:Vera Bradley
2017/08/11 全球购物
Coccinelle官网:意大利的著名皮具品牌
2019/05/15 全球购物
意大利在线大学图书馆:Libreria universitaria
2019/07/16 全球购物
vue项目实现分页效果
2021/03/24 Vue.js
汽车运用工程专业毕业生推荐信
2013/12/25 职场文书
师范生的个人求职信范文
2014/01/04 职场文书
暑期社会实践方案
2014/02/05 职场文书
超市促销活动方案
2014/03/05 职场文书
环保公益策划方案
2014/08/15 职场文书
领导干部保密承诺书
2014/08/30 职场文书
党员干部批评与自我批评反四风思想汇报
2014/09/21 职场文书
浅谈redis的过期时间设置和过期删除机制
2022/03/18 MySQL
vue 把二维或多维数组转一维数组
2022/04/24 Vue.js