JavaScript 中并没有真正的类,但JavaScript 中有 构造函数 和 new 运算符。
- 任何JavaScript 函数都可以用做构造函数,
- 构造函数必须使用 new 运算符来创建新的实例。
一、模拟构造函数
大部分语言定义为:construct , 为了区别我们将其命名为:init
// 首先,我们需要一个可以生产类的工厂
var Class = function(){ var klass = function(){ // 执行构造函数,这里的 this 实际上指向了“类”的实例化对象,也就是下文的_person this.init.apply(this, arguments); }; klass.prototype.init = function(){}; return klass; }; // 第一步:生产类 var Person = new Class(); // 第二步:定义类的构造函数init Person.prototype.init = function(){ // 基于Person 的实例做初始化 alert("我是构造函数,我被自动执行了"); }; // 第三步:实例化对象 var _person = new Person();
二、给“类”库添加方法
在JavaScript 中,在构造函数中给类添加函数和给对象添加属性是一模一样的,区别是 静态属性(方法) 和 实例属性 (方法)
静态属性(方法):
// 直接给类添加静态方法 Person.find = function(id){ /* ... */ }; // 这样我们可以直接调用它们 var person = Person.find(1);
实例属性(方法):
var Person = new Class; // 在原型中定义函数 Person.prototype.save = function(){ /* ... */ }; // 这样就可以在实例中调用它们 var person = new Person; person.save();
可以看到,要想给构造函数添加实例函数,则需要用到构造函数的prototype,一种常用的模式是给类的prototype 起一个别名fn,写起来也更简单:
Person.fn = Person.prototype; Person.fn.run = function(){ /*...*/ };
实际上这种模式在jQuery 的插件开发中是很常见的,将函数添加至jQuery.fn 中也就相当于添加至jQuery 的原型中。
但在我看来这种语法有些绕,不切实际且不够简洁,很难一眼就分辨出类的静态属性和实例的属性。因此我们采用另外一种不同的方法来给类添加属性,这里用到了两个函数
extend() 和include() :
var Class = function () { var klass = function () { this.init.apply(this, arguments); }; klass.prototype.init = function () {}; // 定义 prototype 的别名 klass.fn = klass.prototype; // 给类添加静态属性(方法) klass.extend = function (obj,cb) {for (var o in obj) { klass[o] = obj[o]; } cb && cb(); }; // 给类添加实例属性(方法) klass.include = function (obj,cb) {for (var o in obj) { klass.fn[o] = obj[o]; } cb && cb(); }; return klass; };
这段代码是“类”库的增强版,我们使用extend() 函数来生成一个类,这个函数的参数是一个对象。通过迭代将对象的属性直接复制到类上:
var Person = new Class(); Person.extend({ find: function(id) { alert("我是用户" + id) }, exists: function(id) { alert("用户" + id + "存在") } });
这种写法之美在于它已经可以支持模块了。模块是可重用的代码段,用这种方法可以实现各种继承,用来在类之间共享通用的属性。比如ORM模块
// 共享的函数 var ORMModule = { inster:function(){/* 增 */}, del:function(){/* 删 */}, save:function(){/* 改 */}, select:function(){/* 查 */} }; var Person = new Class; var Asset = new Class; Person.include(ORMModule); Asset.include(ORMModule);
基于原型的类继承
创建一个父类
var Animal = function(){}; Animal.prototype.breath = function(){ console.log('breath'); };
创建一个子类
var Dog = function(){}; // 子类自己的个性方法,和本例无关,只是为了演示 Dog.prototype.wag = function(){ console.log('wag tail'); };
将父类的实例赋值给子类的原型
Dog.prototype = new Animal;
至此,我们就轻松实现了继承,我们来检查一下继承是否生效了
var dog = new Dog(); dog.breath(); // breath