行为委托
[[prototype]] 机制:对象中的一个内部链接引用另一个对象。如果在第一个对象上没有找到需要的属性或者方法引用,引擎就会继续在 [[prototype]] 关联的对象上进行查找,以此类推。这一系列对象链接被称为原型链。
一、委托理论
- 数据成员存储在委托者上,并不是委托目标上。
- 类:重写相同方法;避免在 [[prototype]] 链的不同级别使用相同的命运。
- 委托行为意味着某些对象在找不到属性或者方法引用时,会把这个请求委托给另一个对象;this 隐式绑定。
- 禁止互相委托(双向)。
- API 接口设计中,委托最好在内部,不直接暴露。
二、委托控件:类和对象
1、“类”实例:使用“类”函数,[[prototype]] 关联。
function foo (){};
foo.prototype.render = function() {};
function bar() {
foo.call(this);
};
bar.prototype = Object.create(foo.prototype);
bar.prototype.render = function() {
foo.prototype.render.call(this);
};
foo.call(this);foo.prototype.render.call(this);伪多态调用。
2、ES6 class 语法糖
class foo {
constructor() {}
render() {}
};
class bar {
constructor() { super() }
render() { super.render() }
}
3、对象关联:对象和对象关联
var foo = {
init: function() {}
};
var bar = Object.create(foo);
bar.insert = function() {
this.init();
};
建议使用不相同且更具描述性方法名,用相对委托 this.init() 替代伪多态调用。
三、委托模式优点
- 不需要基类来“共享”两个实体之间的行为(委托足以满足功能)。
- 不需要实例化类(都只是对象)。
- 不需要合成,两个对象之间通过委托进行合作。
- 避免了类设计模式的多态(不需要使用丑陋的显式伪多态)。
四、ES6语法:化繁为简
-
ES6中可以在任意对象的字面形式中使用简洁方法声明(不用 function)。
var foo = { render() {} } // render() {} 相当于 render: function() {}
-
ES6中,可以使用对象的字面形式来改写繁琐的赋值语法。
var foo = { errors: [], render() {} //ES6 } Object.setPrototypeOf(foo, bar); //ES6
注意:render: function() {} 是匿名函数表达式,不具备自我引用的词法标识符。最好使用传统具名函数表达式来定义。
render: function render() {}
五、内省
- instanceof:类实例的自省方法。
- isPrototypeOf(…):对象关联的自省方法。