Javascript闭包-变量的生存期

Javascript闭包-变量的生存期,javascript,closures,Javascript,Closures,由于对Javascript相当陌生,并且是c语言背景,我一直步履蹒跚。我知道,很快我就会明白,函数本身就是对象,JS闭包常常是造成混淆的原因 我正在努力理解这段代码 // Function which returns object with function properties function myFunc() { value = 42; var result = { value: value, getValue: getValue,

由于对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);
这表明函数正在其闭包中使用变量值,这在调用内部函数之间持续存在。但是,value的值在返回的对象中不会更改

我想我得到了一个基本点,即函数是使用定义时有效的范围链执行的

问题 我可以让返回对象的value属性以相同的方式运行吗?或者是通过函数返回它的唯一方法,因为后者在其闭包中保留了变量

并且,为了确认,对于myFunc的每次调用,我假设我将得到一个对象,其函数属性将有自己的作用域链,因此独立于每次调用

我可以让返回对象的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都会创建一个新对象和新函数,它们完全独立于以前调用创建的对象/函数。

是的,您可以:

var result = {
    get value() {
        return value;
    },
    getValue: getValue,
    incrementValue: incrementValue,
    setValue: setValue,
};
ECMAScript 5万岁。当然,这在IE<8上不起作用

数值=42;应为var value=42


顺便说一句,这与变量的生存期没有多大关系——这只是赋值的工作方式。JavaScript中有引用,但没有“引用变量”或“引用属性”。对象包含当时的任何值的副本;创建这样的getter就像创建隐式调用的函数一样。

首先,在声明变量时不要忘记var关键字。在myFunc中声明value=42时,实际上是在全局名称空间而不是函数范围中创建变量。应该是这样开始的:

function myFunc() {
    var value = 42;
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++;
    }
}
现在,myObject.result返回42,因为myFunc返回的结果对象包含函数内声明的值变量的副本

函数setValue、getValue和incrementValue正在更改value的值,而不是result.value。调用myObject.value时,您是从返回的对象获取值,而不是从函数的内部变量获取值

您可以使用以下方法使其工作:

function myFunc() {
    var value = 42;
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

提示:块后不能有分号,例如在函数声明中。@minitech并不重要,甚至不完全正确。var func=函数{};不需要分号,因为JavaScript通常不需要分号,但linters仍然会标记它。但这是唯一一个你的陈述不完全正确的情况。。。而且有点特别P@Derija93:在您的异常情况下,块仍然没有以分号结尾,但变量声明却以分号结尾。@Derija93:我不是说省略分号,而是说分号太多,这在客观上是错误的。参见myObject.增量值;;;;;;;;;打印结果@Guillhermesehn那么。。。可以把这个小争论降到最低。那么这是否意味着通过引用结果变量,它在调用之间保持在内部函数的闭包内?我不知道你的意思。myFunc中定义的函数可以访问myFunc中定义的所有其他变量。所以他们可以获得价值和结果。为我的天真道歉。我希望返回对象的value属性是对内部函数使用的同一变量的引用。因此,当changeValue更改value变量时,我希望返回对象的value属性会反映该变量。我错过了什么?为什么我们必须设置result.value而不是变量值-它们不是指同一个地方吗?非常感谢您帮助我们理解这一点。@jcaddy:他们是否
o或不引用同一个地方最初几乎是不相关的——在JavaScript中,实际上可以安全地假设所有内容都是“引用”。重要的是,通过执行.value=somethingNew,您正在覆盖该引用。如果它是一个参考,它不再指向同一个地方。偶数.value++是.value=.value+1的简写;“原地”没有发生任何事情。@Derija93:这实际上是不正确的。将复制所有值。对象的值实际上是对对象的引用,它是复制的引用。我是这样看的:变量是独立的值容器。为一个变量赋值不会改变另一个变量的值。但是两个变量可以引用相同的值,例如一个对象,然后该对象可以从任何一个变量中更改,当然这些更改也可以通过另一个变量看到,因为它们都引用相同的对象。我刚刚回复了上面的Felix King,我看到您的帖子可能会回答这个问题。因此,在JS中,变量不是对对象的引用——它们是对象?@jcaddy:你可以肯定地认为它们都是对对象的引用,但你正在覆盖引用;我对费利克斯·克林的回答添加了更详细的评论:如果您解释原语是复制的,那就太好了。这就是将值复制到返回对象的原因。另一方面,不会复制对象。对他们来说,赋值只是同一对象的别名。@Walter:这实际上可能是一个实现细节。由于原语值是不可变的,所以您不能仅通过执行代码来判断原语是否也不仅仅是引用。请注意,这两个示例都公开了与OP代码不同的行为。在这两种情况下,您也可以通过myObject更改值。value=newValue;除了myObject.setValue之外。这在原始代码中是不可能的。同意。我的评论只是想澄清为什么返回对象中的“值”与函数中声明的值不同。感谢您指出这一点。这肯定会澄清我的评论可能引起的任何疑问。