【发布时间】:2016-03-03 08:29:26
【问题描述】:
我一直在阅读 Inheritance and the prototype chain 和某处它说:
不良做法:扩展原生原型
一个经常使用的错误特性是扩展 Object.prototype 或 其他内置原型之一。
这种技术称为猴子补丁并破坏封装。 虽然被 Prototype.js 等流行框架使用,但仍有 没有充分的理由将内置类型与额外的 非标准功能。
扩展内置原型的唯一充分理由是向后移植 较新的 JavaScript 引擎的特性;例如 Array.forEach, 等等
在一个真实的例子中,我试图做的是一个角度服务来处理 http 请求,它返回一个带有少量属性的简单对象实例和两个方法 findAll() 和 findOne(id),我将使用其中一个(并且只有一次)在我的 ui-router 的解析方法中:
resolve: {
Resource: 'Resource',
allImages: function(Resource) {
var images = new Resource('images');
return images.findAll();
},
singleImage: function(Resource) {
var image = new Resource('images');
return image.findOne(4);
}
},
根据我将调用的两种方法中的哪一种,我尝试将整个实例 Resource 扩展(甚至替换)为另一个预定义实例 Item 或 Collection,其中每个实例都有自己的结构和方法,所以在我的控制器中我可以做类似的事情:
if (allImages.existNext()) allImages.nextPage();
var currentPage = allImages.meta.currentPage,
collection = allImages.data;
singleImage.url = 'abc';
singleImage.save();
现在,到目前为止,我发现的唯一可行的解决方案(由一个与 http 请求无关的最小示例表示)是这样的:
var myApp = angular.module('myApp',[]);
myApp.factory('Animal', Animal);
function Animal() {
var Cat = function() {
this.prefferedFood = 'fish';
};
Cat.prototype.sayMiau = function() {
console.log('Miau!')
};
var Dog = function(name) {
this.dogName = name;
};
Dog.prototype.sayGrr = function() {
console.log('Grrr!')
};
function Animal(age) {
this.age = age;
}
Animal.prototype = {
makeItCat: function() {},
makeItDog: function(name) {
Dog.call(this, name);
this.__proto__ = Dog.prototype;
},
};
return Animal;
}
所以在 Controller 里面我可以做:
var Dan = new Animal(7);
Dan.makeItDog('Dan');
Console.log(Dan.age); // outputs "7"
Console.log(Dan.dogName); // outputs "Dan"
Dan.sayGrr(); // outputs "Grrr!"
正如您在jsfiddle 中看到的那样,它的工作原理。
问题是:
正确吗?我没有破坏 Object.prototype 应该如何工作或失去它应该提供的性能增益?有更好的方法吗?比如可能使用 angular.extend 或者可能根本不扩展(或替换)原型,而是使用类似的东西:
var Dog = function(name) {
this.dogName = name;
this.sayGrr = function(string) {
console.log('Grrr!')
}
};
...
Animal.prototype = {
makeItCat: function() {},
makeItDog: function(name) {
Dog.call(this, name);
},
};
【问题讨论】:
标签: javascript angularjs prototype