我正试图了解这种名为JavaScript的黑色艺术 - 而且,我必须承认,对它非常兴奋。我一直在寻找代码示例,主要来自“easeljs”,因为这是我将主要使用的。而且我有点困惑..
我(我想)我理解使用prototype
作为class
变量的函数或属性,并使用this.someProp
作为'实例'变量之间的区别(是的,我明白那里) JavaScript中没有类。)
我看过的代码,我用作我自己的代码declare
prototype
变量的模板,然后用它来引用它们。
在构造函数中:
this.name = name;
然后声明:
Object.prototype.name;
后来,
this.name = "Freddy";
这是在'new'调用的函数中,所以在这种情况下,据我所知,this
引用了当前对象。令我困惑的是原型声明正在做什么,为什么我们将它用作实例变量?
澄清:在下面的代码中,我看不到radius的原型声明实现了什么:
(function(){
// constructor
function MyCircle(radius){
this.radius = radius;
}
MyCircle.prototype.radius;
this.area = function(){
return 3.14*this.radius*this.radius;
};
window.MyCircle = MyCircle;
}());
答案 0 :(得分:55)
原型上的值具有与直接在实例上设置的属性不同的键行为。试试这个:
// Create a constructor
function A() {}
// Add a prototype property
A.prototype.name = "Freddy";
// Create two object instances from
// the constructor
var a = new A();
var b = new A();
// Both instances have the property
// that we created on the prototype
console.log(a.name); // Freddy
console.log(b.name); // Freddy
// Now change the property on the
// prototype
A.prototype.name = "George";
// Both instances inherit the change.
// Really they are just reading the
// same property from the prototype
// rather than their own property
console.log(a.name); // George
console.log(b.name); // George
如果没有原型继承,这是不可能的。
您可以使用hasOwnProperty
方法测试属性是instance属性还是prototype属性。
console.log(a.hasOwnProperty("name")); // false
实例可以覆盖prototype
值。
b.name = "Chris";
console.log(b.hasOwnProperty("name")); // true
console.log(a.name); // George
console.log(b.name); // Chris
并返回prototype
值。
delete b.name;
console.log(b.hasOwnProperty("name")); // false
console.log(b.name); // George
这是原型继承的一个重要部分。
在另一种模式中:
function A() {
this.name = "George";
}
每个新实例都会再次声明this.name
变量。
将方法作为在原型上声明的函数是有道理的。所有实例都可以共享一个函数,而不是在每个实例上重新声明函数定义。
就变量而非函数而言,在实例未设置自己的值的情况下,原型可能用于默认值。
答案 1 :(得分:11)
原型上存储的值为该属性提供默认值。
如果您随后将值写入该属性,实例将获取该新值,隐藏原型上的值,该值将保持不变。
在代码的上下文中,您现在已添加到问题中:
MyCircle.prototype.radius;
绝对没有。这是一个无操作 - 它试图读取该属性,然后丢弃结果。
答案 2 :(得分:0)
是的,我同意原型可用于属性(变量)的默认值。构造函数不需要声明属性;它可以有条件地完成。
function Person( name, age ) {
this.name = name;
if ( age ) {
this.age = age;
}
}
Person.prototype.sayHello = function() {
console.log( 'My name is ' + this.name + '.' );
};
Person.prototype.sayAge = function() {
if ( this.age ) {
console.log( 'I am ' + this.age + ' yrs old!' );
} else {
console.log( 'I do not know my age!' );
}
};
Person.prototype.age = 0.7;
//-----------
var person = new Person( 'Lucy' );
console.log( 'person.name', person.name ); // Lucy
console.log( 'person.age', person.age ); // 0.7
person.sayAge(); // I am 0.7 yrs old!
了解露西的age
是如何有条件地宣布和初始化的。
答案 3 :(得分:0)
其他答案已经解释了原型与实例属性之间的区别。
但只是为了添加答案,让我们分解你的代码片段:
(function(){ // <------- 1
// constructor
function MyCircle(radius){ // <------- 2
this.radius = radius; // <------- 2.1
}
MyCircle.prototype.radius; // <------- 3
this.area = function(){ // <------- 4
return 3.14*this.radius*this.radius;
};
window.MyCircle = MyCircle; // <------- 5
}());
IIFE
作为内部代码的范围容器MyCircle
的函数(但请注意它永远不会被“构造”所以应该除掉大写字母,因为它会误导)
radius
实例属性radius
函数MyCircle
上的prototype
属性,因此评估为undefined
area
实例属性并为其指定函数表达式MyCircle
对象上创建window
实例属性并为其分配MyCircle
函数 摘要:似乎它正在全局area
对象上创建MyCircle
和window
属性,并且在调用MyCircle
时创建一个额外的radius
属性。
用法:应该在区域之前调用MyCircle,因为区域依赖于MyCircle初始化半径:
window.MyCircle(10);
window.area(); // evaluates to 314