我正在尝试在JS中模仿OOP行为。我想在函数id
中拥有(私有)变量:name
和Person
。对于这个函数,我传递的参数用于初始化(私有)变量。然后我返回具有name
的getter和setter的对象,并且只返回id
的getter,从而有效地使id
成为只读。
所以id只能通过构造函数设置,而name可以随时设置并获取。
这是代码:
var Person = function (_id,_nm) {
var id, name;
this.id = _id;
this.name = _nm;
return {
setName: function (nm) {
name = nm;
},
getName: function () {
return name;
},
getId: function () {
return id;
},
print: function () {
document.writeln("Id: "+id+"<br />Name: "+name);
}
}
}
var person = new Person(123, "Mahesh");
person.print();
但是当new Person(123,"Mahesh")
执行时,我不明白它实际上是否设置了id
和name
,因为在调试时我可以看到值悬停在它们上方时设置的值,但是Locals面板确实没有显示它们已初始化:
或者在print()中没有引用所需的id
和name
变量:
这里有什么问题?
答案 0 :(得分:2)
<强> Working fiddle 强>
原因是您使用的public
成员Person.prototype
。您不需要为这两个添加this
引用。所以删除:
this.id = _id;
this.name = _nm;
并简单地使用:
var id = _id,
name = _nm;
现在一切都会好起来的。整个想法是使用var
,而不是this
,否则将不会创建闭包。现在,您将无法直接访问name
和id
,而是必须使用setName(), getName(), setId(), getId()
等。
这两个成员id
和name
现在将成为您想要的闭包。
<强>更新强>
如果您使用this.id
,那么它就不会private
而您可以var p = new Person(1, "Mahesha");
直接访问p.name
或p.id
。它们应该是private
所以这不是你想要的。
使用闭包模式,p.name和p.id是未定义的,只能通过p.getName();
和p.getId();
访问。了解闭包的工作原理。这个想法是因为你使用的是var name
,所以会创建一个闭包来记住它的价值。
您的getName
和setName
正在使用该关闭来访问name
媒体资源。没有this.name
,通过更高阶的闭包记住了一个值。
答案 1 :(得分:1)
您使用_id
和_nm
以及“公共”实例属性(this.id
和this.nm
)的本地作用域(“私有”)变量进行了混合。
在这种情况下,您需要前者,但是您创建了两者并且仅初始化了后者。
请注意,由于id
是只读的,根本不需要单独的局部变量,您只需将词法范围的第一个参数用于构造函数:
var Person = function (id, _nm) {
var name = _nm;
...
};
答案 2 :(得分:1)
this.id
和var id
不一样。 this.id
是对象的属性。 var id
属于本地范围。
答案 3 :(得分:1)
使用new
或返回值。不是两个。
问题是您使用Person
关键字创建了new
的新实例,但您的构造函数正在返回另一个对象。
当你从构造函数返回一些东西时,它返回那个值,而不是函数的实例。
您看到执行new Person(123, "Mahesh")
时创建了Person
的新实例。这可以在构造函数中作为this
访问。
如果您没有从构造函数返回任何内容,则JavaScript会自动返回this
。但是你明确地返回了另一个对象。
难怪var person
没有id
和name
属性(您只在this
上定义)。
此外,print
不会显示id
和name
,因为虽然您声明了它们(var id, name
),但您没有给它们任何值。因此它们是undefined
。
这就是我重写Person
构造函数的方法:
function Person(id, name) {
this.getId = function () {
return id;
};
this.getName = function () {
return name;
};
this.setName = function (new_name) {
name = new_name;
};
this.print = function () {
document.writeln("Id: " + id + "<br/>Name: " + name);
};
}
我没有在id
上设置name
和this
属性,因为包含它们没有任何意义。
答案 4 :(得分:0)
让我尝试使用以下内容进行解释:
// Scope 1
var Person = function (_id,_nm) {
// Scope 2
var id, name;
this.id = _id;
this.name = _nm;
return {
// Scope 3
setName: function (nm) {
name = nm;
},
getName: function () {
return name;
},
getId: function () {
return id;
},
print: function () {
$("#output").append("<p>Id: "+id+"; Name: "+name + "<p/>");
}
}
}
print
方法将返回undefined
,因为您指的是代码中从未设置的var id, name;
。您将_id
和_name
设置为属性id
和name
,但无法返回刚刚创建的对象。相反,您将返回一个字典,该字典引用您在name
中创建的id
和Scope 2
变量,该变量是您从未设置的,因此print()
调用中的未定义输出。
这是你应该做的:
var NewPerson = function (_id,_nm) {
var self = this;
this.id = _id;
this.name = _nm;
this.print = function () {
$("#output").append("<p>New Person Id: "+this.id+"; Name: "+ this.name + "<p/>");
};
return this;
};
var nperson = new NewPerson(456, "Marcos");
nperson.print();
这将输出:
New Person Id: 456; Name: Marcos
实质上,new
正在创建一个由this
表示的新对象,您必须返回this
才能引用所创建的对象。实际上,如果在创建对象之前未使用new
,则最终会引用this
的全局实例。请尝试以下方法:
var nperson = new NewPerson(456, "Marcos");
this.name = "Hello";
nperson.print();
var nperson1 = NewPerson(456, "Marcos");
this.name = "Hello";
nperson1.print();
您将看到第一个输出符合预期:
New Person Id: 456; Name: Marcos
但第二个会接受对this.name
所做的更改:
New Person Id: 456; Name: Hello