Javascript原型仅用于函数
Javascript prototype used only for functions?
我最近一直在研究Javascript,并认为我已经弄清楚了原型功能,直到我遇到了一个小问题。
我发现如果你创建一个对象的两个新实例,并且在这两个对象中的任何一个中,你改变了一个变量的值,它在另一个对象中也会改变,这不是我当时正在寻找的效果,不得不将属性放在构造函数中,而不是让它们在每个实例中保持独立。
什么时候需要让每个对象实例共享属性(字符串、布尔值等)?
原型真的只用于声明函数吗? 你在构造函数中声明了所有属性?
举个例子:
function Animal(name) {
this.name = name;
}
Animal.prototype = {
color: null,
walk: function() {}
};
var dog = new Animal('Sam');
var horse = new Animal('Bob');
dog.color = 'black';
horse.color = 'chestnut';
"dog"对象颜色现在是"栗子",因为该属性位于原型中并在两个实例之间共享。哪里需要这种效果?乍一看,我能从中看到的只是调试头痛,还是在 Javascript 中使用它有很好的用途?这让我想起了糟糕的全球变化。
如果大多数情况下您不想在一个实例中更改属性,并且在所有其他实例中它也更改,那么您是否只使用原型来声明函数?
你不应该在原型中分配变量(实际上你正在用自定义对象覆盖Animal.prototype
)。要定义实例属性,请在构造函数中定义它们,如下所示:
function Animal(name) {
this.name = name;
this.color = null;
}
// Instance method
Animal.prototype.walk = function() {};
// Static method
Animal.run = function() {};
// Inheritance example
function Dog(name) {
// Call parent constructor
Animal.apply(this, arguments);
}
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.walk = function() {
// Call parent method (if you need)
Animal.prototype.walk.apply(this, arguments);
...
};
恕我直言,您误解了原型的行为。
解释所有内容将是一个太长的故事,但是关于在原型上设置的属性,如果更改实例上的属性就是更改所有实例的此值,则确实是一个无限的错误来源。
看看,使用jsfiddle,jsbin,cssdeck或任何你喜欢的测试站点,在你的马/狗的例子上:当你改变马的颜色时,狗的颜色不会改变。它仍然是黑色的。
为什么会这样?
当 dog 的实例对属性进行 READ 访问时,它将在原型上搜索,然后在原型的原型上搜索,依此类推,直到我们到达原型链的末端。在找到的第一个值上,将返回该值,如果在没有原型上找不到属性,则返回 undefined。
因此,在创建实例后,所有动物颜色都将为空。
现在,如果您对实例的属性执行 WRITE 访问权限,则会在此实例上创建一个全新的属性,并为其分配提供的值。这样,原型将保留其引用函数,并且实例将获得其值。救济。
在原型上定义属性仍然很有用,因为:
1) 确保所有实例都将为这些属性提供有效值(默认值)。
2)您可以通过分配一次在所有实例(静态)之间共享的属性(更重要的是:一个大对象)来节省内存。Expl :狗的默认图像。
3) 在某些情况下,您可能希望一次更改所有实例的值。在这种情况下,更改原型上的值就可以做到这一点。
4)你允许JavaScript解释器通过将一个类(C++经典的含义)与你的JavaScript类相关联来优化你的代码:当你分配原型上存在的属性时,类不会被"破坏",JS解释器可以继续使用后台类来表示实例。如果性能很重要,那是非常重要的一点。如果没有,就算了:-)
所以只是一个小例子:如果你定义一个动物,那么每个实例都有它的颜色和名称:在构造函数中而不是在原型上设置它们是有意义的。但是对于腿计数,例如,它不会从一个实例更改为另一个实例,如果您创建子类,则始终可以更改子原型上的值,以使子类更改此计数:
function Animal(name, color) {
this.name = name;
this.color = null;
}
Animal.prototype.legCount = 4; // most animal have 4 legs (...)
// Dog Class, inheriting from Animal
function Dog(name) { Animal.apply(this, arguments); }
// Set Animal as Dog's prototype's prototype.
// so that we can safely change Dog's prototype.
Dog.prototype = Object.create(Animal.prototype);
// Duck class
function Duck(name) { Animal.apply(this, arguments); }
// same inheritance scheme
Duck.prototype = Object.create(Animal.prototype);
// ... but we change the legCount, for the ducks only
Duck.prototype.legCount = 2;
高级答案:
如果您希望原型属性保持不变,即使如果我们尝试在实例上为此属性赋值,请将它作为原型上的只读属性。
Object.defineProperty(Duck.prototype,'legCount', { get : function() { return 2 } } );
var duck = new Duck(...) ;
duck.legCount = 5;
console.log (duck.legCount) ; // --> output is still 2
如果您希望在实例上设置值,请将值更改为所有实例(不显式更改原型的属性值),然后 在原型属性定义的设置器中完成它。
// using a closure
var duckLegCount = 2;
Object.defineProperty(Duck.prototype,'legCount', {
get : function() { return duckLegCount } ,
set : function (x) { duckLegCount = x } } );
var duck1 = new Duck(...);
var duck2 = new Duck(...);
duck1.legCount = 12;
console.log ( duck2.legCount ) ; // output is 12
- Javascript函数用于检查数字并返回
- 为什么不是't此函数用于修改最终输出
- JQuery .find() 函数用于多个数组
- 在ko.applyBindings(..)中执行Knockout js订阅函数(用于可观察对象)
- Javascript函数用于选择/取消选中radgrid标头模板中的所有复选框
- 如何将一个函数用于多个项目 JEditable/JQuery
- 如何将一个函数用于多个元素
- 如何使用不带逗号的 join() 函数(用于数组)
- Setter 函数用于动态访问数组中的字段,该数组是一个属性
- JavaScript .some 函数用于对象属性
- 如何将一个函数用于具有不同 id 的输入类
- javascript changelink函数用于2选择
- 2jquery.click函数用于一个按钮.火一个接一个地发挥作用
- Javascript函数用于按Id检索不同的html元素
- 在流星中,是否有一个onRendered函数用于所有模板
- 使用jQuery's setTimout()函数用于锚点滚动
- 将jQuery.click()函数用于单个元素
- Javascript中的内置函数用于格式化日期
- 一个函数用于多个元素
- Init函数用于引导盒显示对话框后使用一些代码