对于Javascript和c#背景相当新,我一直在磕磕绊绊。我很快就知道,我需要了解函数本身就是对象这一事实,而且JS闭包通常是导致混淆的原因。
我想了解这段代码
// Function which returns object with function properties
function myFunc() {
value = 42;
var result = {
value: value,
getValue: getValue,
incrementValue: incrementValue,
setValue: setValue,
};
return result;
function setValue(y) {
value = y;
};
function getValue() {
return value;
};
function incrementValue() {
value++;
};
};
// Helper function to print out results
function printResults(m,x){
$('#output').append(m + ': ' + x).append('<br/>');
};
var myObject = myFunc(); // returns the object
printResults('Inital call to getValue',myObject.getValue());
myObject.setValue(59);
printResults('Called changeValue',myObject.getValue());
printResults('Value property of object',myObject.value);
printResults('Called getValue again',myObject.getValue());
myObject.incrementValue();
printResults('Call increment value',myObject.getValue());
printResults('Value property of object',myObject.value);
在jsFiddle
中运行时,我得到以下结果Inital call to getValue: 42
Called changeValue: 59
Value property of object: 42
Called getValue again: 59
Call increment value: 60
Value property of object: 42
这些表明函数在它们的闭包中使用变量value
,这在内部函数的调用之间持续存在。但是,value
的值在返回的对象中不会改变。
我认为我得到的基本观点是使用在定义时生效的范围链来执行函数。
问题
我可以使返回对象的value
属性以相同的方式运行 - 或者是通过函数返回它的唯一方法,因为后者在其闭包中保留变量吗?
和,仅用于确认,对于myFunc()
的每次调用,我假设我将获得一个对象,其函数属性将具有自己的作用域链,因此独立于每次调用。< / p>
答案 0 :(得分:5)
首先,在声明变量时不要忘记var
关键字。在value = 42
内声明myFunc
时,实际上是在全局命名空间而不是函数范围中创建变量。它应该像这样开始:
function myFunc() {
var value = 42;
现在,myObject.result
返回42,因为myFunc
返回您的result
对象,其中包含函数内声明的value
变量的副本。
您的功能setValue
,getValue
和incrementValue
正在更改value
的值,而不是result.value
。当您调用myObject.value
时,您将从返回的对象中获取值,而不是函数的内部变量。
你可以使用这样的东西让它工作:
function myFunc() {
var value = 42;
var result = {
value: value,
getValue: getValue,
incrementValue: incrementValue,
setValue: setValue
};
return result;
function setValue(y) {
result.value = y;
}
function getValue() {
return result.value;
}
function incrementValue() {
result.value++;
}
}
然而,有比这更好的设计模式。您可以使用new
关键字和prototype
来定义可用于从函数返回的对象的方法。举个例子:
function myFunc() {
this.value = 42;
}
myFunc.prototype.setValue = function(y) {
this.value = y;
}
myFunc.prototype.getValue = function(y) {
return this.value;
}
myFunc.prototype.incrementValue = function(y) {
this.value++;
}
var myObject = new myFunc();
console.log(myObject.getValue()); // 42
myObject.setValue(30);
myObject.incrementValue();
console.log(myObject.getValue()); // 31
答案 1 :(得分:1)
我可以使返回对象的value属性以相同的方式运行
如果您的意思是它显示更新的值,是的,您可以这样做。您只需更改代码以更新value
属性:
function myFunc() {
var value = 42; // don't forget var!
var result = {
value: value,
getValue: getValue,
incrementValue: incrementValue,
setValue: setValue,
};
return result;
function setValue(y) {
result.value = value = y;
}
function getValue() {
return value;
}
function incrementValue() {
value++;
result.value = value;
}
}
我选择同时使用value
和result.value
的原因是为了防止通过result.value
修改值。如果您注意到,我不会在result.value
内部读取,我只会写信给它。这意味着从外部代码分配给result.value
没有效果。这符合您现有代码的工作方式。
而且,为了确认,对于
myFunc()
的每次调用,我假设我将得到一个对象,其函数属性将具有自己的作用域链,因此独立于每次调用。
是的,myFunc
的每次调用都会创建一个新对象和新函数,它们完全独立于先前调用创建的对象/函数。
答案 2 :(得分:1)
是的,你可以:
var result = {
get value() {
return value;
},
getValue: getValue,
incrementValue: incrementValue,
setValue: setValue,
};
对于ECMAScript 5的万岁。当然,这不适用于IE&lt; 8。
&lt;旁边&gt; value = 42;
应为var value = 42;
。&lt; / aside&gt;
顺便说一句,这与变量的生命周期没有多大关系 - 它只是赋值的工作原理。 JavaScript中有引用,但没有“引用变量”或“引用属性”。该对象包含当时value
所有内容的副本;像这样创建一个getter就像创建一个隐式调用的函数。