Javascript 调用本机原型方法时扩展或继承对象原型

Javascript 调用本机原型方法时扩展或继承对象原型,javascript,angularjs,prototype,Javascript,Angularjs,Prototype,我一直在读,它在某处写道: 错误做法:本地原型的扩展 一个经常使用的mis特性是扩展Object.prototype或 另一个内置原型 这种技术被称为猴子修补和破坏封装。 虽然Prototype.js等流行框架使用,但仍然存在 没有很好的理由将内置类型与其他 非标准功能 扩展内置原型的唯一好理由是向后移植 更新的JavaScript引擎的特性;例如Array.forEach, 等等 在一个真实的示例中,我尝试使用angular服务来处理http请求,该服务返回一个简单的对象实例,其中包含几个属性

我一直在读,它在某处写道:

错误做法:本地原型的扩展

一个经常使用的mis特性是扩展Object.prototype或 另一个内置原型

这种技术被称为猴子修补和破坏封装。 虽然Prototype.js等流行框架使用,但仍然存在 没有很好的理由将内置类型与其他 非标准功能

扩展内置原型的唯一好理由是向后移植 更新的JavaScript引擎的特性;例如Array.forEach, 等等

在一个真实的示例中,我尝试使用angular服务来处理http请求,该服务返回一个简单的对象实例,其中包含几个属性和两个方法
findAll()
findOne(id)
,我将在ui路由器的解析方法中使用其中一个(并且只使用一次):

解析:{
资源:'资源',
所有图像:功能(资源){
var images=新资源(“图像”);
返回images.findAll();
},
singleImage:函数(资源){
var image=新资源(“图像”);
返回图像。findOne(4);
}
},
根据我将调用的两个方法中的哪一个,我将尝试使用另一个预定义的
集合来扩展(甚至替换)整个实例
资源
,其中每个方法都有自己的结构和方法,因此在我的控制器中,我可以执行以下操作:

if(allImages.existNext())allImages.nextPage();
var currentPage=allImages.meta.currentPage,
收集=allImages.data;
singleImage.url='abc';
singleImage.save();
现在,我找到的唯一可行的解决方案(由一个与http请求无关的最小示例表示)是:

var myApp=angular.module('myApp',[]);
myApp.工厂(“动物”,动物);
功能动物(){
var Cat=函数(){
this.preferedfood='fish';
};
Cat.prototype.sayMiau=函数(){
console.log('Miau!')
};
var Dog=函数(名称){
this.dogName=名称;
};
Dog.prototype.sayGrr=函数(){
console.log('Grrr!')
};
功能动物(年龄){
这个。年龄=年龄;
}
动物原型={
makeItCat:function(){},
makeItDog:函数(名称){
狗。叫(这个,名字);
这个。uuuu proto_uuuu=Dog.prototype;
},
};
返回动物;
}
所以在控制器内部我可以做:

var-Dan=新动物(7);
Dan.makeItDog('Dan');
Console.log(Dan.age);//产出“7”
Console.log(Dan.dogName);//输出“Dan”
Dan.sayGrr();//输出“Grrr!”
正如你在这张照片上看到的

问题是: 对吗?我并没有破坏Object.prototype应该如何工作,或者失去它应该提供的性能增益?有更好的方法吗?例如,可能使用
angular.extend
或根本不扩展(或替换)原型,而是使用类似以下内容:

var Dog=函数(名称){
this.dogName=名称;
this.sayGrr=函数(字符串){
console.log('Grrr!')
}
};
...
动物原型={
makeItCat:function(){},
makeItDog:函数(名称){
狗。叫(这个,名字);
},
};

我认为你这样做可能会奏效。我不确定你的工厂实施情况。我曾经做过类似的事情,可能会有所帮助:

查看工作界面

这是您的代码,只需稍加编辑:

var myApp = angular.module('myApp', []);

myApp.factory('AnimalFactory', AnimalFactory);

function AnimalFactory() {

  // This is the main class
  var Animal = function(age, fullName) {

    this.age = age;
    this.fullName = fullName;

    this.eat = function() {
      console.log('I am eating');
    };

  };

  // Dog should inherit from Animal 
  var Dog = function(age, fullName) {

    // Calling the animal constructor
    Animal.call(this, age, fullName);

    // Augmenting object adding a new method
    this.bark = function() {
      console.log('I am ' + this.fullName + ' and I bark Woof woof');
    };
  };

  // Setting the Dog prototype to Animal
  Dog.prototype = Object.create(Animal);

  var Cat = function(age, fullName) {

    // Calling the animal constructor
    Animal.call(this, age, fullName);

    // Augmenting object adding a new method
    this.meow = function() {
      console.log('I am ' + this.fullName + ' and I meow');
    };
  };

  // Setting the Cat prototype to Animal
  Cat.prototype = Object.create(Animal);

  function createDog(age, fullName) {
    return new Dog(age, fullName);
  }

  function createCat(age, fullName) {
    return new Cat(age, fullName);
  }

  // Interface returned to use factory
  return {
    createDog: createDog,
    createCat: createCat
  };
}

function MyCtrl($scope, AnimalFactory) {

  var dan = AnimalFactory.createDog(7, 'Dan');
  dan.bark();

  console.log(dan);

  $scope.dan = dan;
}

我认为上面的代码在类之间有一个更清晰的原型继承实现。让我知道你的想法,这样我们可以改进它。

回答得好。我还没有在我的真实示例中尝试过,但在阅读之后,我非常确定直接设置
\uuuuuu proto\uuuu
不是一个好主意。在最初调用服务时设计继承布局和链接原型,然后在需要时使用
new
关键字返回实例,这应该是一个比我更干净的解决方案。谢谢分享!确切地我认为您的示例可能有效,但此解决方案提供了一种更干净的方法。我非常高兴能帮助你@Salemourdani。问候语!