function Ninja(){
this.swung = true;
}
var ninjaA = new Ninja();
var ninjaB = new Ninja();
Ninja.prototype.swing = function(){
this.swung = false;
return this;
};
console.log(ninjaA.swung,"checking Ninja's Swung member")//returning true WHY??
log( ninjaA.swing().swung, "Verify that the swing method exists and returns an instance." ); //false
log( !ninjaB.swing().swung, "and that it works on all Ninja instances." ); //true
如果我操纵原型中的属性,那么我只能通过原型访问它。 正如我正在做的那样ninja.swing()。swung - 使用ninja.prototype.swing改变了poperty值,但为什么我在做ninjaA.swung时会变为真实?
答案 0 :(得分:0)
不确定您预期会发生什么,但swung是您使用特殊此变量通过共享成员操作的特定于实例的成员。
即使你在Ninja.prototype上定义了swung,默认也是如此,但调用this.swung = false不会改变Ninja.prototype.swung,因为赋值会导致在实例上创建swung而不是查找原型链。
因此,如果您想通过实例更改共享成员并让它反映所有实例中的更改,您必须改变共享成员。你可以这样做:
function Ninja(){
// you want swung to be shared
// instance specific members are defined here
// this.swung = true;
}
Ninja.prototype.shared = {swung:true};
var ninjaA = new Ninja();
var ninjaB = new Ninja();
Ninja.prototype.swing = function(){
this.shared.swung = false;
return this;
};
console.log(ninjaB.shared.swung);//=true
ninjaA.swing();
console.log(ninjaB.shared.swung);//=false
以下答案更详细地解释了这一点:https://stackoverflow.com/a/16063711/1641941 该部分解释了从上面的链接原型变异共享成员: 构造函数功能介绍
您可以使用函数作为构造函数来创建对象,如果构造函数名为Person,则使用该构造函数创建的对象是Person的实例。
var Person = function(name){
this.name = name;
};
Person.prototype.walk=function(){
this.step().step().step();
};
var bob = new Person("Bob");
Person是构造函数。使用Person创建实例时,必须使用新关键字:
var bob = new Person("Bob");console.log(bob.name);//=Bob
var ben = new Person("Ben");console.log(ben.name);//=Ben
属性/成员name
是特定于实例的,对于bob和ben来说它是不同的
成员walk
是Person.prototype的一部分,并且对所有实例共享bob和ben是Person的实例,因此它们共享walk成员(bob.walk === ben.walk)。
bob.walk();ben.walk();
因为在bob上找不到walk(),JavaScript会在Person.prototype中查找它,因为这是bob的构造函数。如果在那里找不到它,它将会在Object.prototype上查找。这被称为原型链。继承的原型部分是通过延长这个链来完成的;例如bob => Employee.prototype => Person.prototype => Object.prototype(稍后继承更多关于继承)。
尽管bob,ben和所有其他创建的Person实例共享walk,但每个实例的函数行为都不同,因为在walk函数中它使用this
。 this
的值将是调用对象;现在让我们说它是bob.walk()
"这个"的当前实例。将是鲍勃。 (更多关于"这个"以及之后的调用对象。)
如果本正在等待红灯而且鲍勃处于绿灯状态;然后你会在ben和bob上调用walk(),显然ben和bob会发生不同的事情。
当我们执行类似ben.walk=22
之类的操作时会发生隐藏成员,即使bob和ben共享walk
22的赋值到ben.walk也不会影响bob.walk。这是因为该语句将直接在ben上创建一个名为walk
的成员,并为其赋值22.将有2个不同的walk成员:ben.walk和Person.prototype.walk。
当要求bob.walk时,您将获得Person.prototype.walk函数,因为在bob上找不到walk
。然后要求ben.walk将获得值22,因为成员行走已在ben上创建,因为JavaScript发现在Ben上行走它不会在Person.prototype中查找。
有关原型的更多信息
对象可以通过使用if原型从另一个对象继承。您可以使用Object.create
使用任何其他对象设置任何对象的原型。在构造函数的介绍中,我们已经看到,如果在对象上找不到成员,那么JavaScript将在prototpe链中查找它。
在上一部分中,我们已经看到重新分配来自实例原型(ben.walk)的成员将影响该成员(在ben上创建walk而不是更改Person.prototype.walk)。
如果我们不分配但改变会员怎么办?变异是(例如)改变Object的子属性或调用将改变对象值的函数。例如:
var a = [];
a.push(11);
a[1]=22;
以下代码通过变更成员来演示原型成员和实例成员之间的区别。
var person = {
name:"default",//immutable so can be used as default
sayName:function(){
console.log("Hello, I am "+this.name);
},
food:[]//not immutable, should be instance specific
// not suitable as prototype member
};
var ben = Object.create(person);
ben.name = "Ben";
var bob = Object.create(person);
console.log(bob.name);//=default, setting ben.name shadowed the member
// so bob.name is actually person.name
ben.food.push("Hamburger");
console.log(bob.food);//=["Hamburger"], mutating a shared member on the
// prototype affects all instances as it changes person.food
console.log(person.food);//=["Hamburger"]
上面的代码显示ben和bob分享来自个人的成员。只有一个人,它被设置为bob&和本的原型(人被用作原型链中的第一个对象,用于查找在实例上不存在的请求成员) 。上面代码的问题是bob和ben应该有自己的food
成员。这是构造函数的用武之地。它用于创建特定于实例的成员。您还可以向其传递参数以设置这些特定于实例的成员的值。
下一个代码显示了实现构造函数的另一种方法,语法不同但想法是一样的:
使用构造函数,您将在以下代码中的步骤2中设置原型,我们在步骤3中设置原型。
在这段代码中,我已经从原型和食物中删除了名称,因为无论如何,在创建实例时,您很可能会立即隐藏它。 Name现在是一个特定于实例的成员,在构造函数中设置了默认值。 Becaus食品成员也从原型成员转移到具体成员,在向Ben添加食物时不会影响bob.food。
var person = {
sayName:function(){
console.log("Hello, I am "+this.name);
},
//need to run the constructor function when creating
// an instance to make sure the instance has
// instance specific members
constructor:function(name){
this.name = name || "default";
this.food = [];
return this;
}
};
var ben = Object.create(person).constructor("Ben");
var bob = Object.create(person).constructor("Bob");
console.log(bob.name);//="Bob"
ben.food.push("Hamburger");
console.log(bob.food);//=[]
您可能会遇到类似的模式,这些模式更强大,可以帮助创建对象和定义对象。
答案 1 :(得分:0)
function Ninja(){ this.swung = true; } var ninjaA = new Ninja(); … console.log(ninjaA.swung,"checking Ninja's Swung member")
返回
true
为什么?
因为这是你在构造函数中初始化它的方式。
然后你拨打.swing()
,将swung
设置为false
(有点违反直觉,但没关系)。之后,您按预期记录false
。
它同样适用于您的ninjaB
,但您已将日志记录反转(.swung == false
,但您记录! ninjaB.swung
)。