锁定老帖子 主题:简单实现JavaScript继承
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2012-09-01
看John Resig 的JavaScript实现继承的文章,对大神的实现代码拿来跟大家一起读下源码,因为英语太菜就不翻译了,直接根据源码来分析了。原文地址:http://ejohn.org/blog/simple-javascript-inheritance/
首先来看本继承所要达到的效果,知道效果来看源码更能容易理解。(先要知其然,然后知其所以然)。
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
继承需要做到以下几点: 1.定义一个简单的结构,有一个初始化方法(生成对象时调用的函数,类似Java的构造方法) 2.子类的生成,必须要继承一个父类。 3.所有类的原型都是派生自Class.(就像Java类最终都派生自Object一样) 4.在子类中提供一种方法能访问到父类中被覆盖的方法。通过this._super().(如:在类Ninja的init方法中调用this._super()就是调用父类Person的init方法)
下面来看看代码是怎么实现继承的:
/* Simple JavaScript Inheritance * By John Resig http://ejohn.org/ * MIT Licensed. */ // Inspired by base2 and Prototype (function(){ var initializing = false, fnTest = /xyz/.test(function(){xyz;}) ? /\b_super\b/ : /.*/; //fnTest是一正则表达式,匹配函数里是否有调_super方法。 // The base Class implementation (does nothing) this.Class = function(){}; // 定义一个全局变量Class类/函数。 // Create a new Class that inherits from this class Class.extend = function(prop) { /** 保存当前对象的原型(也就父类的原型), * Class.extend()调用时this是Class,Person.extend调用时this是Person * js里一切都是对象,Class函数也是对象,所以this这里是一个函数。 */ var _super = this.prototype; // Instantiate a base class (but only create the instance, // don't run the init constructor) initializing = true; /**父类的实例作为子类的原型(典型的原型继承) * 但是这里实例化跟普通的生成对象不一样,这里不调用父类的init方法。 * 类就是一模板,所以子类在以父类对象为原型的时候,不应调用初始化方法,仅仅是生成一个模板 * 这边就是用initializing变量来标识实例父类是否是赋值给子类的原型。 * 用闭包来隐藏了initializing 作为全局变量的污染 */ var prototype = new this(); initializing = false; // Copy the properties over onto the new prototype for (var name in prop) { // Check if we're overwriting an existing function /** 当子类新方法父类中有同名函数,而且子类中调用了父类方法(函数中有_super的调用) * 这里使用了代理模式,在调用函数前先将this._super用tmp保存起来(也可能没有_super方法) * 在将this._super 赋值为父类中同名函数。调用结束再将原来的this._super还原 */ prototype[name] = typeof prop[name] == "function" && typeof _super[name] == "function" && fnTest.test(prop[name]) ? (function(name, fn){ return function() { var tmp = this._super; // Add a new ._super() method that is the same method // but on the super-class this._super = _super[name]; // The method only need to be bound temporarily, so we // remove it when we're done executing var ret = fn.apply(this, arguments); this._super = tmp; return ret; }; })(name, prop[name]) : prop[name]; } // The dummy class constructor function Class() { // All construction is actually done in the init method /**如果定义了初始化方法init,则调用init初始化 * 注意:这里的this不是Class或者Person等类/函数对象 * 而是实例化后的对象var p = new Person() 这里的this 是p */ if ( !initializing && this.init ) this.init.apply(this, arguments); } // Populate our constructed prototype object Class.prototype = prototype; //子类原型复制 // Enforce the constructor to be what we expect Class.prototype.constructor = Class; //子类构造函数定义 // And make this class extendable //定义类的继承方法,保证每个新类也都有extend. //这里也可写成 Class.extend = this.extend; Class.extend = arguments.callee; return Class; }; })(); 看这些代码最重要的一点是时刻要清楚this是哪个对象。
好了,上面就是文章的全部了,希望对大家有帮助,有疑问请留言,有什么解释不对和不清楚的地方也望大家指正。
声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2012-09-04
YUI的继承体系也不错,核心代码:
extend:function(subClass,superClass){ var F = function(){}; F.prototype = superClass.prototype; subClass.prototype = new F(); subClass.prototype.constructor = subClass; subClass.superclass = superClass.prototype; if(superClass.prototype.constructor == Object.prototype.constructor) { superClass.prototype.constructor = superClass; } } |
|
返回顶楼 | |
发表时间:2012-09-04
thc1987 写道 YUI的继承体系也不错,核心代码:
extend:function(subClass,superClass){ var F = function(){}; F.prototype = superClass.prototype; subClass.prototype = new F(); subClass.prototype.constructor = subClass; subClass.superclass = superClass.prototype; if(superClass.prototype.constructor == Object.prototype.constructor) { superClass.prototype.constructor = superClass; } } yui的代码精炼啊 |
|
返回顶楼 | |
发表时间:2012-09-04
thc1987 写道
YUI的继承体系也不错,核心代码:
extend:function(subClass,superClass){ var F = function(){}; F.prototype = superClass.prototype; subClass.prototype = new F(); subClass.prototype.constructor = subClass; subClass.superclass = superClass.prototype; if(superClass.prototype.constructor == Object.prototype.constructor) { superClass.prototype.constructor = superClass; } } 其实2者还是有点不一样的地方: 1. 写法 YUI是 extend(subClass, superClass); 这边是任何按照这个定义的类都有 var B = A.extend({...子类新加的函数和变量...}); 2. 看你发的这块代码是 subClass继承了superClass,而仅仅是继承了prototype的东西,而subClass里没有继承非在prototype里的方法。 这边是子类的B.prototype = new A()的,继承了所有的属性。 3. 最后一点差异也是这边代码的亮点,在子类函数中可以引用父类被覆盖的同名函数,只要this._super()即可。
这里只是列举出来差异,当然代码没有好与差之分,只有适合不适合,YUI确实写得短小精炼,但功能可能相对John Resig的强大,而且除掉注释代码也非常精炼。(我没看过YUI,只看了你发的这块,可能YUI不止这么少的代码,说的不对的地方还请谅解,欢迎交流,只有交流才能进步,呵呵) 3. |
|
返回顶楼 | |
发表时间:2012-09-04
在子类中是可以调用父类的的方法的.下面有个列子,参考下吧:
<HTML> <HEAD> <TITLE> New Document </TITLE> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> <SCRIPT LANGUAGE="JavaScript"> <!-- // ----------------工具类-------------------- var Class = { extend:function(subClass,superClass){ var F = function(){}; F.prototype = superClass.prototype; subClass.prototype = new F(); subClass.prototype.constructor = subClass; subClass.superclass = superClass.prototype; if(superClass.prototype.constructor == Object.prototype.constructor){ superClass.prototype.constructor = superClass; } } } // ------------------------------------ // Demo // 声明父类 var Person = function(param){ this.name = param.name; this.age = param.age; } Person.prototype.sayName = function(){ alert("My name is " + this.name); } Person.prototype.sayAge = function(){ alert("My age is " + this.age); } Person.prototype.getAge = function(){ return this.age; } // 声明子类 var Man = function(param){ // 调用父类的构造函数 Man.superclass.constructor.call(this,param); } // 继承父类 Class.extend(Man,Person); // 覆盖父类的sayAge方法 Man.prototype.sayAge = function(){ alert(this.name + "'s age is " + this.age); } // 覆盖父类的方法,并且调用父类原来的方法 Man.prototype.getAge = function(){ // 先调用父类方法返回年龄 var age = Man.superclass.getAge.call(this); // 年龄+1 alert(this.name + "'s age is " + (age + 1)); } // 测试 var man = new Man({name:"Jim",age:22}); man.sayName(); // 这里调用父类的方法 man.sayAge(); // 这里调用自己的方法 man.getAge(); // 是否属于Person类型 alert(man instanceof Person) // //--> </SCRIPT> </HEAD> <BODY> </BODY> </HTML> |
|
返回顶楼 | |
发表时间:2012-09-04
其实javascript的继承都是根据自身的特性来模仿出来的.
方法可能有多种,自己选择一种喜欢的就好了 <javascript设计模式>这本书里面就提到过2种继承方法.其中一种就是YUI的 |
|
返回顶楼 | |
发表时间:2012-09-04
thc1987 写道
其实javascript的继承都是根据自身的特性来模仿出来的.
方法可能有多种,自己选择一种喜欢的就好了 <javascript设计模式>这本书里面就提到过2种继承方法.其中一种就是YUI的
var Person = function(param){ this.name = param.name; this.age = param.age; } Person.prototype.sayName = function(){ alert("My name is " + this.name); } Person.prototype.sayAge = function(){ alert("My age is " + this.age); } Person.prototype.getAge = function(){ return this.age; } 这些方法都是写在原型中的,如果方法不是定义在原型中这样就不能被继承了,刚说的是这个意思,可能之前说的不清楚,抱歉,呵呵。
var Person = function(param){ this.name = param.name; this.age = param.age; this.sayName = function(){ //sayName不是定义在Person.prototype 中 alert("My name is " + this.name); } } /* Person.prototype.sayName = function(){ alert("My name is " + this.name); } */
|
|
返回顶楼 | |
发表时间:2012-09-05
var Person = function(param){ this.name = param.name; this.age = param.age; this.sayName = function(){ alert("My name is " + this.name); } } /* Person.prototype.sayName = function(){ alert("My name is " + this.name); } */ Person.prototype.sayAge = function(){ alert("My age is " + this.age); } Person.prototype.getAge = function(){ return this.age; } 这样是可以的,试下就知道了.
|
|
返回顶楼 | |
浏览 3699 次