JavaScript MVC 学习笔记(二)类的使用(上)


公开记录学习JS MVC,不知道能坚持多久= =。以《基于MVC的JavaScript web富应用开发》为主要学习资料。

JavaScript类的内容好多,我脑容量太小,分两次学习

JavaScript的类

JavaScript是基于原型的语言,没有包含内置的类,但是通过JavaScript可以轻易地模拟出经典的类。JavaScript中有构造函数和 new 运算符。构造函数用来给实例对象初始化属性和值。任何JavaScript函数都可以用做构造函数,构造函数必须使用new 运算符作为前缀来创建新的实例。

new 运算符改变了函数的执行上下文,同时改变了return 语句的行为。实际上,使用new和构造函数和传统的实现了类的语言中的使用方法是很类似的:

var Person = function(name) {
  this.name = name;
};

// 实例化一个Person
var alice = new Person('alice');

// 检查这个实例
assert( alice instanceof Person );

构造函数的命名通常使用驼峰命名法,首字母大写,以此和普通的函数区分开来,这是一种习惯用法。

不要省略new前缀的方式来调用构造函数:

// 不要这么做!
Person('bob'); //=> undefined

这个函数只会返回undefined,并且执行上下文是window(全局)对象,你无意间创建了一个全局变量name。调用构造函数时不要丢掉new关键字。

当使用new关键字来调用构造函数时,执行上下文从全局对象(window)变成一个空的上下文,这个上下文代表了新生成的实例。因此,this关键字指向当前创建的实例。尽管理解起来有些绕,实际上其他语言内置类机制的实现也是如此。默认情况下,如果构造函数中没有返回任何内容,就会返回this——当前的上下文。要不然就返回任意非原始类型的值。

创建自己的类模拟库

var Class = function(){

    var klass = function(){
      this.init.apply(this, arguments);
    };

    klass.prototype.init = function(){};

    return klass;
};

var Person = new Class;

Person.prototype.init = function(){
  // 基于Person 的实例做初始化
};

// 用法:
var person = new Person;

由于 JavaScript 2 规范从未被实现过,class 一直都是保留字。最常见的做法是将变量名 class 改为 _classklass

给类添加函数

在JavaScript 中,在构造函数中给类添加函数和给对象添加属性是一样的:

Person.find = function(id){ /*...*/ };
var person = Person.find(1);

要想给构造函数添加实例函数,则需要用到构造函数的prototype :

Person.prototype.breath = function(){ /*...*/ };
var person = new Person;
person.breath();

一种常用的模式是给类的 prototype 起一个别名fn,写起来也更简单:

Person.fn = Person.prototype;
Person.fn.run = function(){ /*...*/ };

这种模式在jQuery 的插件开发中是很常见的,将函数添加至jQuery.fn 中也就相当于添加至jQuery 的原型中。

给实现了类机制的类库添加方法

给类添加属性和给构造函数添加属性是一样的。

直接给类设置属性和设置其静态成员是等价的:

var Person = new Class;

// 直接给类添加静态方法
Person.find = function(id){ /* ... */ };

// 这样我们可以直接调用它们
var person = Person.find(1);

给类的原型设置的属性在类的实例中也是可用的:

var Person = new Class;

// 在原型中定义函数
Person.prototype.save = function(){ /* ... */ };

// 这样就可以在实例中调用它们
var person = new Person;
person.save();

这样很难一眼就分辨出类的静态属性和实例的属性。因此我们采用另外一种不同的方法来给类添加属性,这里用到了两个函数extend()include()

var Class = function () {
    var klass = function () {
        this.init.apply(this, arguments);
    };

    klass.prototype.init = function () {};

    // 定义 prototype 的别名
    klass.fn = klass.prototype;

    // 定义类的别名
    klass.fn.parent = klass;

    // 给类添加属性
    klass.extend = function (obj) {
        var extended = obj.extended;
        for (var i in obj) {
            klass[i] = obj[i];
        }
        if (extended) 
            extended(klass)
    };

    // 给实例添加属性
    klass.include = function (obj) {
        var included = obj.included;
        for (var i in obj) {
            klass.fn[i] = obj[i];
        }
        if (included) 
            included(klass)
    };
    return klass;
};

这段代码使用extend() 函数来生成一个类,这个函数的参数是一个对象。通过迭代将对象的属性直接复制到类上:

var Person = new Class;
Person.extend({
    find: function(id) { /* ... */ },
    exists: functions(id) { /* ... */ }
});
var person = Person.find(1);

include() 函数的工作原理也一样,只不过不是将属性复制至类中,而是复制至类的原型中。换句话说,这里的属性是类实例的属性,而不是类的静态属性。

var Person = new Class;
Person.include({
    save: function(id) { /* ... */ },
    destroy: functions(id) { /* ... */ }
});
var person = new Person;
person.save();

同样地,这里的实现支持extended 和included 回调。将属性传入对象后就会触发这两
个回调:

Person.extend({
    extended: function(klass) {
        console.log(klass, " was extended!");
    }
});

这种写法已经可以支持模块了。模块是可重用的代码段,用这种方法可以实现各种继承,用来在类之间
共享通用的属性。

var ORMModule = {
    save: function(){
        // 共享的函数
    }
};

var Person = new Class;
var Asset = new Class;
Person.include(ORMModule);
Asset.include(ORMModule);

One response on “JavaScript MVC 学习笔记(二)类的使用(上)

发表评论

电子邮件地址不会被公开。 必填项已用*标注

您可以使用这些HTML标签和属性: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>