js的本质是对象之间的关联关系
1.比较面向对象和对象关联的设计模式
面向对象
function Foo(who) {
this.me = who;
}
Foo.prototype.identify = function () {
return "I am " + this.me;
};
function Bar(who) {
Foo.call(this,who);
}
Bar.prototype = Object.create( Foo.prototype );
Bar.prototype.speak = function () {
alert("Hello, " + this.identify() + ".");
};
var b1 = new Bar("b1");
var b2 = new Bar("b2");
b1.speak();
b2.speak();
子类Bar继承了父类Foo,然后生成了b1和b2两个实例。b1委托了Bar.prototype,Bar。prototype委托了Foo.prototype。
关联模式:
Foo = {
init: function (who) {
this.me = who;
},
identify: function () {
return "I am " + this.me;
}
};
Bar = Object.create( Foo );
Bar.speak = function () {
alert( "Hello, " + this.identify() + "." );
};
var b1 = Object.create(Bar);
b1.init("b1");
var b2 = Object.create(Bar);
b2.init("b2");
b1.speak();
b2.speak();
结合一下前端的常用使用场景,下面用控件类举例
类风格代码:
function Widget(width,height) {
this.width = width || 50;
this.height = height || 50;
this.elem = null;
}
Widget.prototype.render = function (where) {
if (this.elem) {
this.elem.css({
width: this.width + 'px',
height: this.height + 'px'
}).appendTo(where);
}
};
//子类
function Button(width,height,label) {
//调用super构造函数
Widget.call(this, width, height);
this.lable = label || "Default";
this.elem = $("
可以看到代码中出现了显式伪多态,即通过Widget.call和Widget.prototype.render.call从子类方法中引用父类中的基础方法。
ES6的class语法糖
class Widget{
constructor(width,height) {
this.width = width || 50;
this.height = height || 50;
this.elem = null;
}
render(where) {
if (this.elem) {
this.elem.css({
width: this.width + 'px',
height: this.height + 'px'
}).append(where);
}
}
}
class Button extends Widget {
constructor(width,height,label){
super(width,height);
this.label = label || "Default";
this.elem = $( "
委托控件对象
var Widget = {
init:function (width,height) {
this.width = width || 50;
this.height = height || 50;
this.elem = null;
},
insert: function (where) {
if (this.elem) {
this.elem.css({
width: this.width + 'px',
height: this.height + 'px'
}).append(where);
}
}
};
var Button = Object.create(Widget);
Button.setup = function (width,height,label) {
//委托调用
this.init( width, height );
this.label = label || "Default";
this.elem = $("
使用对象关联风格来编写代码时,不需要把Widget和Button当作父类和子类。相反,Widget只是一个对象,包含一组通用的函数,任何类型的控件都可以委托,Button同样只是一个对象。(它通过委托关联到Widget)
从设计模式的角度看,我们并没有像类一样在两个对象中都定义相同的方法名render,而是两个更加具体描述性的方法名。
在委托设计模式中,除了使用不相同的方法名外,还要通过对象关联避免丑陋的显式伪多态调用(Widget.call....),代之以简单的相对委托调用this.init()和this.insert()
从语法角度来说,我们同样没有使用任何构造函数、.prototype或new
小结:
行为委托认为对象之间是兄弟关系,互相委托,而不是父类和子类的关系。js机制的本质上就是行为委托机制。
对象关联是一种编码风格,它倡导的是直接创建和关联对象,不拔它们抽象成类。对象关联可以用基于[[prototype]]的行为委托非常自然的实现