Simple JavaScript Inheritance 源码分析


John Resig 写了一篇关于 JavaScript 里 类似其它语言的 "继承", 灵感来自于  base2 and PrototypeJS 他为文章起名为"Simple JavaScript Inheritance" . 他使用的一些很巧妙的技术来实现 类似于java 的 extend方法.


其实  Simple JavaScript Inheritance 的源码就那么20多行,咱们结合 http://ejohn.org/blog/simple-javascript-inheritance/  上的demo给大家讲解一下

(function() {
	var initializing = false,
		fnTest = /xyz/.test(function() {
			xyz;
		}) ? /\b_super\b/ : /.*/;
	this.Class = function() {}; //this---->window
	Class.extend = function(prop) {
		var _super = this.prototype; //  this---->Person构造函数      this.prototype---->Person.prototype  
		initializing = true;
		var prototype = new this(); //Person {}
		initializing = false;
		for(var name in prop) { //可以遍历到init  dance   swingSword

			prototype[name] =   //init方法里面调用了 _super
				typeof prop[name] == "function" && typeof _super[name] == "function" && fnTest.test(prop[name]) ?
				(function(name, fn) {
					return function() {
						var tmp = this._super;
						this._super = _super[name];   //闭包的原理
						var ret = fn.apply(this, arguments);
						this._super = tmp;
						return ret;
					};
				})(name, prop[name]) :

				prop[name];      
		}

		function Class() {
			if(!initializing && this.init)
				this.init.apply(this, arguments);
		}
		Class.prototype = prototype;
		Class.constructor = Class;
		Class.extend = arguments.callee;
		return Class;
	};

})();

var Person = Class.extend({
	init: function(isDancing) {
		this.dancing = isDancing;
	},
	dance: function() {
		return this.dancing;
	}
});

var Ninja = Person.extend({
	init: function() {
		this._super(false);
	},
	dance: function() {
		// Call the inherited version of dance()
		return this._super();
	},
	swingSword: function() {
		return true;
	}
});

var p = new Person(true);
p.dance(); // => true

var n = new Ninja();
n.dance(); // => false
n.swingSword(); // => true



首先分析这父类的构造方法是怎么生成的

var Person = Class.extend({
	init: function(isDancing) {
		this.dancing = isDancing;
	},
	dance: function() {
		return this.dancing;
	}
});


我们就对执行上面面这段代码时进行debug分析

(function() {
	var initializing = false,
		fnTest = /xyz/.test(function() {
			xyz;
		}) ? /\b_super\b/ : /.*/;
	this.Class = function() {}; //this---->window
	Class.extend = function(prop) {
		var _super = this.prototype; //  this---->function(){}  即this===window.Class
		initializing = true;
		var prototype = new this(); //Class {}
		initializing = false;
		for(var name in prop) { //可以遍历到init  dance

			prototype[name] =
				typeof prop[name] == "function" && typeof _super[name] == "function" && fnTest.test(prop[name]) ?
				(function(name, fn) {
					return function() {
						var tmp = this._super;
						this._super = _super[name];
						var ret = fn.apply(this, arguments);
						this._super = tmp;
						return ret;
					};
				})(name, prop[name]) :

				prop[name];      //执行Person时,执行的都是  prototype[name]=prop[name],上面那个并没有执行到上面那个判断
		}

		function Class() {
			if(!initializing && this.init)
				this.init.apply(this, argum ents);
		}
		Class.prototype = prototype;
		Class.constructor = Class;
		Class.extend = arguments.callee;
		return Class;
	};

})();

执行完var Person = Class.extend ,会产生如下的继承原型链




分析子类的构造方法是怎么生成的


var Ninja = Person.extend({
	init: function() {
		this._super(false);
	},
	dance: function() {
		// Call the inherited version of dance()
		return this._super();
	},
	swingSword: function() {
		return true;
	}
});



对上述代码进行debug分析

(function() {
	var initializing = false,
		fnTest = /xyz/.test(function() {
			xyz;
		}) ? /\b_super\b/ : /.*/;
	this.Class = function() {}; //this---->window
	Class.extend = function(prop) {
		var _super = this.prototype; //  this---->Person构造函数      this.prototype---->Person.prototype  
		initializing = true;
		var prototype = new this(); //Person {}
		initializing = false;
		for(var name in prop) { //可以遍历到init  dance   swingSword

			prototype[name] =   //init方法里面调用了 _super
				typeof prop[name] == "function" && typeof _super[name] == "function" && fnTest.test(prop[name]) ?
				(function(name, fn) {
					return function() {
						var tmp = this._super;
						this._super = _super[name];   //闭包的原理
						var ret = fn.apply(this, arguments);
						this._super = tmp;
						return ret;
					};
				})(name, prop[name]) :

				prop[name];      
		}

		function Class() {
			if(!initializing && this.init)
				this.init.apply(this, arguments);
		}
		Class.prototype = prototype;
		Class.constructor = Class;
		Class.extend = arguments.callee;
		return Class;
	};

})();


要分析上面这个继承语句究竟进行了那些操作关键是搞明白

 Typeofprop[name]=="function"&&typeof_super[name]=="function"&&fnTest.test(prop[name])

这行语句究竟判断了些什么

Typeofprop[name]=="function"    prop里面的[name]属性要是方法

 

typeof_super[name]=="function"   父对象里面要要一个name也是[name]的属性

 

 

fnTest.test(prop[name])    prop里面的[name]方法有没有调用 _super

   

 

fnTest=/xyz/.test(function() {

         xyz;

      })?/\b_super\b/ : /.*/;

 

这个fnTest的目的就是为了验证 [name]method中是否使用了 "_super()"调用,

/xyz/.test(function() {xyz; })是为了测试浏览器是否支持" function decompilation(函数反编译)", Function serialisation 是在一个函数被转换成字符串时发生的. 现在很多浏览器都支持 toString 方法。如果一个浏览器支持Function serialization,那么在进行/xyz/.test(function() {xyz; })  的时候会把function() {xyz; }  toString成字符串“function() {xyz; }”,这时候/xyz/.test(function() {xyz; })自然就会返回true。


如果浏览器支持函数反编译就用/\b_super\b/ 匹配,否则就用/.*/ 匹配,这会始终返回 true, 那么会始终对_super 进行额外的操作, 导致这些新的方法不能在 _super 中使用.这会有一些小的性能消耗.但能保证在所有浏览器中 正常执行.


最终  执行完var Ninja = Person.extend ,会产生如下的继承原型链



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值