Simple JavaScript Inheritance(John Resig)
I’ve been doing a lot of work, lately, with JavaScript inheritance – namely for my work-in-progress JavaScript book – and in doing so have examined a number of different JavaScript classical-inheritance-simulating techniques. Out of all the ones that I’ve looked at I think my favorites were the implementations employed by base2 andPrototype.
I wanted to go about extracting the soul of these techniques into a simple, re-usable, form that could be easily understood and didn’t have any dependencies. Additionally I wanted the result to be simple and highly usable. Here’s an example of what you can do with it:
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 // Should all be true
p instanceof Person && p instanceof Class &&
n instanceof Ninja && n instanceof Person && n instanceof Class
A couple things to note about this implementation:
- Creating a constructor had to be simple (in this case simply providing an init method does the trick).
- In order to create a new ‘class’ you must extend (sub-class) an existing class.
- All of the ‘classes’ inherit from a single ancestor: Class. Therefore if you want to create a brand new class it must be a sub-class of Class.
- And the most challenging one: Access to overridden methods had to be provided (with their context properly set). You can see this with the use of
this._super()
, above, calling the originalinit()
anddance()
methods of thePerson
super-class.
I’m pleased with the result: It helps to enforce the notion of ‘classes’ as a structure, maintains simple inheritance, and allows for the super method calling.
Simple Class Creation and Inheritance
And here’s the implementation (reasonably sized and commented well) – clocking in at around 25 lines. Feedback is welcome and appreciated.
/* 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/ : /.*/; // The base Class implementation (does nothing)
this.Class = function(){}; // Create a new Class that inherits from this class
Class.extend = function(prop) {
var _super = this.prototype; // Instantiate a base class (but only create the instance,
// don't run the init constructor)
initializing = true;
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
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
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
Class.extend = arguments.callee; return Class;
};
})();
In my opinion the two trickiest parts are the “initializing/don’t call init” and “create _super method” portions. I want to cover those briefly so that you will have a good understanding of what’s being achieved in this method.
Initialization
In order to simulate inheritance with a function prototype we use the traditional technique of creating an instance of the super-class function and assigning it to the prototype. Without using the above it would look something like this:
function Person(){}
function Ninja(){}
Ninja.prototype = new Person();
// Allows for instanceof to work:
(new Ninja()) instanceof Person
What’s challenging about this, though, is that all we really want is the benefits of ‘instanceof’, not the whole cost of instantiating a Person object and running its constructor. To counteract this we have a variable in our code, initializing
, that is set to true whenever we want to instantiate a class with the sole purpose of using it for a prototype.
Thus when it comes time to actually construct the function we make sure that we’re not in an initialization mode and run the init method accordingly:
if ( !initializing )
this.init.apply(this, arguments);
What’s especially important about this is that the init method could be running all sorts of costly startup code (connecting to a server, creating DOM elements, who knows) so circumventing this ends up working quite well.
Super Method
When you’re doing inheritance, creating a class that inherits functionality from a super-class, a frequent desire is the ability to access a method that you’ve overridden. The final result, in this particular implementation, is a new temporary method (._super
) which is only accessible from within a sub-classes’ method, referencing the super-classes’ associated method.
For example, if you wanted to call a super-classes’ constructor you could do that with this technique.
var Person = Class.extend({
init: function(isDancing){
this.dancing = isDancing;
}
}); var Ninja = Person.extend({
init: function(){
this._super( false );
}
}); var p = new Person(true);
p.dancing; // => true var n = new Ninja();
n.dancing; // => false
Implementing this functionality is a multi-step process. To start, note the object literal that we’re using to extend an existing class (such as the one being passed in toPerson.extend
) needs to be merged on to the base new Person
instance (the construction of which was described previously). During this merge we do a simple check: Is the property that we’re attempting merge a function and is what we’re replacing also a function? If that’s the case then we need to go about creating a way for our super method to work.
Note that we create an anonymous closure (which returns a function) that will encapsulate the new super-enhanced method. To start we need to be a good citizen and save a reference to the old this._super
(disregarding if it actually exists) and restore it after we’re done. This will help for the case where a variable with the same name already exists (don’t want to accidentally blow it away).
Next we create the new _super
method, which is just a reference to the method that exists on the super-class’ prototype. Thankfully we don’t have to make any additional changes, or re-scoping, here as the context of the function will be set automatically when it’s a property of our object (this
will refer to our instance as opposed to the super-class’).
Finally we call our original method, it does its work (possibly making use of _super
as well) after which we restore _super
to its original state and return from the function.
Now there’s a number of ways in which a similar result, to the above, could be achieved (I’ve seen implementations that have bound the super method to the method itself, accessible from arguments.callee
) but I feel that this technique provides the best mix of usability and simplicity.
I’ll be covering a lot more of the nitty-gritty behind the JavaScript prototype system in my completed work but I just wanted to get this Class implementation out there to get everyone trying it out and playing with it. I think there’s a lot to be said for simplistic code (easier to learn, easier to extend, less to download) so I think this implementation is a good place to start and learn the fundamentals of JavaScript class construction and inheritance.
This topic will be discussed, in depth, in my work-in-progress book: Secrets of the JavaScript Ninja. To be released Fall 2008.
Posted: March 20th, 2008
Simple JavaScript Inheritance(John Resig)的更多相关文章
- Join Resig's “Simple JavaScript Inheritance ”
======================Enein翻译========================= John Resig 写了一篇关于 JavaScript 里类似其它语 ...
- Simple JavaScript Inheritance
1. [代码]Simple JavaScript Inheritance (function(){ var initializing = false, fnTest = /xyz/.test ...
- [转] jquery作者John Resig编写的微模板引擎:JavaScript Micro-Templating
I've had a little utility that I've been kicking around for some time now that I've found to be quit ...
- Simple JavaScript Inheritance--一个极简JS面向对象-类库
面向对象 面向对象思想的几个重要特征(针对类的要求): 抽象-封装.信息隐藏(将内部实现的方法和数据隐藏, 定义开放的接口) 继承-子类可以使用父类的资源,并可以定制自己的资源, 资源包括方法和数据 ...
- JavaScript Inheritance All in One
JavaScript Inheritance All in One constructor inheritance prototype chain inheritance "use stri ...
- [翻译]jQuery十周年-John Resig
10th Anniversary of jQuery Today marks the 10th anniversary of the release of jQuery...[原文] 今天是jQuer ...
- 最简单的JavaScript模板引擎
在小公司待久了感觉自己的知识面很小,最近逛博客园和一些技术网站看大家在说JavaScript模版引擎的事儿,完全没有概念,网上一搜这是08年开始流行起来的...本来以为这是很高深的知识,后来在网上看到 ...
- 简单JavaScript模版引擎优化
在上篇博客最简单的JavaScript模板引擎 说了一下一个最简单的JavaScript模版引擎的原理与实现,作出了一个简陋的版本,今天优化一下,使之能够胜任日常拼接html工作,先把上次写的模版函数 ...
- Javascript模版引擎简介
回顾 Micro-Templating 出自John Resig 2008年的一片文章,以及其经典实现: // Simple JavaScript Templating // John Resig - ...
随机推荐
- expect基础及实例
expect基础及实例 http://blog.csdn.net/zhuying_linux/article/details/6900805
- 【uva11421】玩纸牌
数学期望. #include<bits/stdc++.h> ; using namespace std; double d[N][N],p; int main(){ ;double p;s ...
- POI导入导出小案例
一.HSSF 97-2003 需要jar:poi-3.9.jar 简单示例:生成EXCEL //93---2003 String [] titlie={"id","nam ...
- 记录一次WebService使用的经历
于业务需要,需要和第三方对接一些接口,但是问题是,他们的接口提供是webservice的,本人只精通restful接口(也就是说我比较年轻^-^).好在对面人特别奈斯,一顿指导我,感谢. 废话不多说了 ...
- QT_QMAKE_EXECUTABLE reported QT_INSTALL_LIBS as /usr/lib/i386-linux-gnu but ...
$sudo apt-get install libqt4-dev done!!!
- 洛谷 P3927 SAC E#1 - 一道中档题 Factorial【数论//】
题目描述 SOL君很喜欢阶乘.而SOL菌很喜欢研究进制. 这一天,SOL君跟SOL菌炫技,随口算出了n的阶乘. SOL菌表示不服,立刻就要算这个数在k进制表示下末尾0的个数. 但是SOL菌太菜了于是请 ...
- [haoi2009]巧克力
鉴于河南是oi弱省,所以想来这道题也没什么人会翻出来写吧,而且这还是haoi2009的一道简单题目,所以估计也没几个人会写博客的,那么看在我这么弱的份上,我觉得是应该写一篇出来的. 这道题我是按照贪心 ...
- Node 入门<1>
1. Node JavaScript web服务器框架,主要特点:事件驱动,异步 I/O,强制不共享任何资源的单线程,单进程系统. 每一个node进程都构成网络应用中的一个节点. ...
- Xamarin XAML语言教程控件模板的模板绑定
Xamarin XAML语言教程控件模板的模板绑定 控件模板的模板绑定 为了可以轻松更改控件模板中控件上的属性值,可以在控件模板中实现模板绑定功能.模板绑定允许控件模板中的控件将数据绑定到公共属性上. ...
- [APIO2015]巴厘岛的雕塑
题目描述 印尼巴厘岛的公路上有许多的雕塑,我们来关注它的一条主干道. 在这条主干道上一共有 NN 座雕塑,为方便起见,我们把这些雕塑从 11 到 NN 连续地进行标号,其中第 ii 座雕塑的年龄是 Y ...