【类和模块】类的扩充

类的扩充

JavaScript中基于原型的继承机制是动态的:对象从其原型继承属性,如果创建对象之后原型的属性发生改变,也会影响到继承这个原型的所有实例对象。这意味着我们可以通过给原型对象添加新方法来扩充JavaScript类。这里我们给上例中的Complex类添加方法来计算复数的共貌复数(两个实部相等,虚部互为相反教的复数互为共辄复教)。

// 返回当前复数的共辄复数
Complex.prototype.conj = function() { return new Complex(this.r, -this.i); };

JavaScript内置类的原型对象也是一样如此“开放”,也就是说可以给数字、字符串、数组、函数等数据类型添加方法。在下例中我们曾给ECMAScript 3中的函数类添加了bind( )方法,这个方法原来是没有的:

if (!Function.prototype.bind) {
 Function.prototype.bind = function(o /*, args */) {
     // bind()方法的代码...
 };
}

这里有一些其他的例子:

// 多次调用这个函数传入一个迭代数
// 比如,要输出"hello”三次:
// var n = 3;
// n.times(function(n) { console.log(n + " hello"); });
Number.prototype.times = function(f, context) {
    var n = Number(this);
    for(var i = 0; i < n; i++) f.call(context, i);
};

// 如果不存在ES5的String.trim()方法的话,就定义它
// 这个方法用以去除字符串开头和结尾的空格
String.prototype.trim = String.prototype.trim || function() {
    if (!this) return this;	                   // 空字符串不做处理
    return this.replace(/^\s+|\s+$/g, "");     //使用正则表达式进行空格替换
};

// 返回函数的名字,如果它有(非标准的)name属性,则直接使用name属性
// 否则,将函数转换为字符串然后从中提取名字
// 如果是没有名字的函数,则返回一个空字符串
Function.prototype.getName = function() {
    return this.name || this.toString().match(/function\s*([^()*]\(/)[1];
};

可以给Object.prototype添加方法,从而使所有的对象都可以调用这些方法。但这种做法并不推荐,因为在ECMAScript 5之前,无法将这些新增的方法设置为不可枚举的,如果给Object.prototype添加属性,这些属性是可以被for/in循环遍历到的。

然而并不是所有的宿主环境(比如Web浏览器)都可以使用Object.defineProperty(),这跟ECMAScript具体实现有关。比如,在很多Web浏览器中,可以给HTMLElement.prototype添加方法,这样当前文档中表示HTML标记的所有对象就可以继承这些方法。但当前版本的IE则不支持这样做。这对客户端编程实用技术有着严重的限制。

上一篇:15个手写JS,巩固你的JS基础(面试高频)


下一篇:js 构造函数和原型、原型链