时间:2021-07-01 10:21:17 帮助过:13人阅读
var felix = {
name: 'Felix',
greet: function(){
console.log('Hello, I am ' + this.name + '.');
}
};
接下来,假设我们想要将greet函数一般化,将其提取出来,放到一个一般的位置,这样一来,我们就可以创建多个对象来共享同一个greet方法。该怎么实现呢?
我们有好几种选择,先以mixin开始吧。
1、混入(对象扩张)Mixin(Augmentation)
在JavaScript语言中,混入属性非常简单。你只需要将混入对象的属性复制到要混入的对象中去即可。我们将使用一个“augment”函数来实现它,看代码就明白了:
代码如下:
var Dude = {
greet: function(){
console.log('Hello, I am ' + this.name + '.')
}
};
var felix = { name: 'Felix' };
augment(felix, Dude);//将Dude中的属性复制一份到felix中,即混入(mixin)
在上面的代码中,augment函数将Dude对象的属性混入到了felix当中。在很多的JS库中,augment函数被叫做extend。我不喜欢用extend,因为一些语言用extend表示继承,以至于是我很困惑。我更喜欢用“augment”表示,因为实际上这种做法并不是继承,并且语法augment(felix, Dude)已经很清楚的表明你是用Dude中的属性对felix进行了扩充,而不是继承。
也许你早就猜到了augment的代码实现了,没错,非常简单。如下所示:
代码如下:
function augment(obj, properties){
for (var key in properties){
obj[key] = properties[key];
}
}
2、对象克隆(Cloning)
mixin的一个替代的办法就是先克隆Dude对象,然后再给克隆的对象设置name属性。如下所示:
代码如下:
var Dude = {
greet: function(){
console.log('Hello, I am ' + this.name + '.');
}
}
var felix = clone(Dude);//克隆Dude对象
felix.name = 'Felix';
这两种方法之间的唯一不同就是添加属性的顺序。如果你想覆写克隆的对象中的某些方法,你可以考虑使用这种手法。
代码如下:
var felix = clone(Dude);
felix.name = 'Felix';
felix.greet = function(){
console.log('Yo dawg!');
};//覆写greet方法
如果想要调用父类的方法也很简单——使用apply函数即可,如下所示
代码如下:
felix.greet = function(){
Dude.greet.apply(this);
this.greetingCount++;
}
这比原型风格的代码要好很多,因为你不必去使用构造函数的.prototype属性——我们不会使用任何构造函数。
以下是clone函数的实现:
代码如下:
function clone(obj){
var retval = {};//创建一个空对象
augment(retval, obj);//复制属性
return retval;
}
3、继承(Inheritance)
最后,就是继承了。在我看来,继承被高估了,但是继承在“实例对象”之间共享属性方面确实要比对象扩张有一些优势。让我们编写一个inherit函数,这个函数接收一个对象作为参数,并且返回一个继承自该对象的新对象。
代码如下:
var felix = inherit(Dude);
felix.name = 'Felix';
使用继承,你可以创建多个继承自同一个对象的子对象,这些子对象可以实时的继承父对象的属性。如下面的代码所示,
代码如下:
var garfield = inherit(Dude);//garfield继承自Dude
Dude.walk = function(){//给Dude添加新的方法walk
console.log('Step, step');
};
garfield.walk(); // prints "Step, step"
felix.walk(); // also prints "Step, step"
在inherit函数中使用了基于原型对象的继承
代码如下:
function inherit(proto){
if (Object.create){
// 使用ES5中的Object.create方法
return Object.create(proto);
}else if({}.__proto__){
//使用非标准属性__proto__
var ret = {};
ret.__proto__ = proto;
return ret;
}else{
//如果两种都不支持,使用构造函数继承
var f = function(){};
f.prototype = proto;
return new f();
}
}
上面的代码看起来不怎么好,那是因为我们使用了特性监测来判断到底使用3种方式中的哪一种。
但是,怎么使用构造方法呢(也就是,初始化方法)?你该怎么在实例对象之间共享初始化代码呢?在一些情况下,如果你只需要为对象设置一些属性,这时候,初始化函数不是必须的,就像我们上面的例子中那样。但是如果你有更多的初始化代码呢,你也许会制定一个约定,例如:使用一个叫initialize的初始化方法。我们假设在Dude中定义了一个叫initialize的方法,如下
代码如下:
var Dude = {
initialize: function(){
this.greetingCount = 0;
},
greet: function(){
console.log('Hello, I am ' + this.name + '.');
this.greetingCount++;
}
}
然后,你可以这样来初始化对象
代码如下:
var felix = clone(Dude);
felix.name = 'Felix';
felix.initialize();或者也可以
var felix = { name: 'Felix' };
felix.name = 'Felix';
augment(felix, Dude);
felix.initialize();还可以
var felix = inherit(Dude);
felix.name = 'Felix';
felix.initialize();结语
我表示通过上面定义的三个函数——augment,clone和inherit,你可以对JavaScript中的对象做任何你想做的事,而不必使用构造函数和new关键字。我认为这三个函数所体现的语义更简单并且更接近于JavaScript底层的对象系统。(完)^_^