考虑这段代码,
var getPerson = function() {
var _name = "";
var person = {};
person.getName = function() {
return _name;
}
person.setName = function(value) {
_name = value;
}
return person;
}
p1 = getPerson();
p1.setName("foo");
p2 = getPerson();
p2.setName("bar");
console.log(p1.getName()); // logs "foo"
console.log(p2.getName()); // logs "bar"
有人可以在这里解释_name的范围吗? p1._name和p2._name不存在。该变量真正存储在哪里?
答案 0 :(得分:1)
_name
的范围限定为getPerson
函数,因为它是使用var
关键字声明的。
嵌套在getPerson
中的任何函数都将继承getPerson
中声明的变量,并且它们可以覆盖它以声明它们自己的变量。 This concept is called closure
并且在进行任何认真的JavaScript开发之前都值得了解。
在JavaScript中,范围不是由块决定的(如在Java中),而是function scoped。
因此,_name
函数中的setName
与_name
中声明的getPerson
相同。
答案 1 :(得分:1)
_name
的范围限定为getPerson()
函数中的任何代码。
在Javascript中,函数中的局部变量的范围限定在函数的特定调用范围内,并且函数的每次调用都会创建一组新的局部变量。此外,这些局部变量就像其他变量一样被垃圾收集。它们不会严格存储在函数退出时被销毁的堆栈上。
由于垃圾收集,只要仍可访问的代码具有对该变量的引用,函数内的变量就会存在。因此,在getPerson()
函数中,_name
变量的范围是getPerson()
函数的特定调用,但变量的生命周期只要一些代码仍然可以达到变量,即使在getPerson()
的调用完成后很长时间。
这在Javascript中被称为闭包,是一个非常有价值和有用的工具。
因为person.getName()
和person.setName()
在_name
函数执行完毕后仍然有getPerson()
变量的引用,所以它将保持活动状态并且不会是垃圾由语言收集。
因此,scope
由变量的声明决定。 _name
的范围限定在它声明的函数和该函数中也存在的任何其他子范围内。 Javascript具有lexical
范围(这意味着范围由声明的位置/方式决定)。但是,范围内变量的生命周期由垃圾收集器单独确定,并且范围内的变量可以远远超出创建范围的函数的执行,只要其他一些可访问代码仍然具有对该变量的引用即可。
我喜欢将函数作用域本身视为Javascript中的垃圾收集实体。虽然Javascript的某些实现甚至可能比整个范围更精细(例如,垃圾收集范围内的各个变量尽可能),但是垃圾收集而不是基于堆栈的范围的概念为您提供了理解它们之间差异的框架。像Javascript这样的语言和像C ++这样的语言,它使用显式堆栈帧来确定局部变量的生命周期。
答案 2 :(得分:1)
我认为你可能是从Java背景来的JavaScript。
var _name = "";
定义匿名函数范围内的_name
变量(分配给getPerson
的函数)。该变量不附加到任何对象,它只是一个普通变量。
如果你真的想做p1._name和p2._name,你可以做一两个解决方法。
var getPerson = function() {
var person = {
_name: ''
};
person.getName = function() {
return this._name;
}
person.setName = function(value) {
this._name = value;
}
return person;
}
p1 = getPerson();
p1.setName("foo");
p2 = getPerson();
p2.setName("bar");
console.log(p1.getName()); // logs "foo"
console.log(p2.getName()); // logs "bar"
console.log(p1._name); // logs "foo"
console.log(p2._name); // logs "bar"
var getPerson = function() {
var _name = "";
var person = {
get _name () {
return _name;
}
};
person.getName = function() {
return _name;
}
person.setName = function(value) {
_name = value;
}
return person;
}
p1 = getPerson();
p1.setName("foo");
p2 = getPerson();
p2.setName("bar");
console.log(p1.getName()); // logs "foo"
console.log(p2.getName()); // logs "bar"
console.log(p1._name); // logs "foo"
console.log(p2._name); // logs "bar"
还有很多其他方法可以实现这一目标; JavaScript是一种动态语言。
你上面所说的是一个闭包。通过返回person
,您可以公开方法person.getName
和person.setName
。因为这些方法是在getPerson
中定义的,所以它们也可以访问_name
变量(因为_name
是在同一个函数中定义的。)
getPerson
以外的代码无法访问_name
,但他们可以通过getName和setName方法(以受控方式)访问。这为_name
变量创建了隐私。