鸭式辨型来自于James Whitecomb Riley的名言:"像鸭子一样走路并且嘎嘎叫的就叫鸭子。"通过制定规则来判定对象是否实现这个接口。例如:数组都有length属性且值为数字,而String、Arguments等也有同样的特征,即[].length或'abc'.length
1)Array的prototype受益于鸭式辨型,如下所示:
(function () {
var arr = Array.prototype.slice.call(arguments);
})(1, 2, 3)
2)使用鸭式辨型实现模拟接口,如下所示:
/**
* 模拟接口,并检测接口里的方法是否被实现类都实现
* 实现步骤
* 1)接口类,用来创建接口(接口类有两个属性和一个检测方法)
* 2)创建接口
* 3)子类
* 4)判断实例对象是否实现了接口中所有的方法
*/
// 接口类,存储实现类的类名和方法名
var Interface = function (name, methods) {
if (arguments.length !== 2) {
throw new Error("arguments.length must be 2")
}
this.name = name;
this.methods = [];
var that = this;
methods.forEach(function (item) {
if (typeof item !== "string") {
throw new Error("item type must be string");
}
that.methods.push(item);
})
}
// 如果检验通过,不做任何操作;不通过,浏览器抛出error
Interface.prototype.confirmImplement = function (objs) {
if (arguments.length < 1) {
throw new Error("At least one parameter must be 1")
}
var that = this;
// arguments伪数组,利用了鸭式辨型的思想,调用了数组中的forEach方法
Array.prototype.forEach.call(arguments, function (obj) {
that.methods.forEach(function (methodName) {
if (!obj[methodName] || typeof obj[methodName] !== "function") {
throw new Error(obj.constructor.name + "\'s method name '" + methodName + "' is not found !");
}
})
}, arguments)
}
// 创建接口
var Animal = new Interface("Animal", ["walk", "sleep", "play"]);
// 实现类
var Dog = function () {
this.name = 'dog';
this.implementInterface = 'Animal';
}
Dog.prototype.walk = function () {
console.log("walk")
}
Dog.prototype.sleep = function () {
console.log("sleep")
}
Dog.prototype.play = function () {
console.log("play")
}
var Duck = function () {
this.name = 'duck';
this.implementInterface = 'Animal';
}
Duck.prototype.walk = function () {
console.log("walk")
}
Duck.prototype.sleep = function () {
console.log("sleep")
}
Duck.prototype.play = function () {
console.log("play")
}
// 判断对象是否实现接口中的所有方法
Animal.confirmImplement(new Dog, new Duck);
// Animal.confirmImplement(Dog.prototype,Duck.prototype)