[英]Understanding Private Variables (Closure?) in Javascript with specific example
[英]Why these closure based private variables in JavaScript not working
我正在尝试模仿JS中的OOP行为。 我试图在功能Person
拥有(私有)变量: id
和name
。 我要向该函数传递用于初始化(私有)变量的参数。 然后,我返回的对象的name
具有getter和setter,而id
仅有一个getter,从而有效地使id
只读。
因此,只能通过构造函数设置id,而可以随时设置和获取名称。
这是代码:
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
变量:
怎么了
原因是因为您正在使用Person.prototype
public
成员。 您无需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.getName();
和p.getId();
。 阅读有关闭包如何工作的信息。 这个想法是因为您使用的是var name
,所以将创建一个闭包来记住它的值。
您的getName
和setName
使用该闭包来访问name
属性。 没有this.name
,通过高阶闭包可以记住一个值。
您对_id
和_nm
和“公共”实例属性( this.id
和this.nm
)使用局部范围内的(“私有”)变量进行了this.nm
。
在这种情况下,您需要前者,但是您创建了两者并且仅初始化了后者。
请注意,由于id
是只读的,因此您根本不需要一个单独的局部变量,您可以对构造函数使用按词法定义的第一个参数:
var Person = function (id, _nm) {
var name = _nm;
...
};
this.id
和var id
不相同。 this.id
是对象的属性。 var id
属于本地范围。
使用new
或返回一个值。 不是都。
问题在于您正在使用new
关键字创建Person
的新实例,但是构造函数却返回了另一个对象。
当您从构造函数返回某些内容时,它将返回该值,而不是该函数的实例。
您会看到执行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);
};
}
我没有this
设置id
和name
属性,因为将它们包括在内没有任何意义。
让我尝试使用以下内容进行解释:
// 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
但是无法返回刚刚创建的对象。 相反,您返回一个字典,该字典引用您从未设置的Scope 2
中创建的name
和id
变量,因此在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
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.