简体   繁体   English

Javascript闭包-变量的生存期

[英]Javascript closures - lifetime of variables

Being fairly new to Javascript and from ac# background I have been stumbling along adequately. 对Java语言还很陌生,并且从ac#背景开始,我就一直在绊脚石。 I knew that soon enough I would need to get my head round the fact that functions are objects in their own right and that JS closures are often the cause of confusion. 我知道,很快我就需要弄明白事实,即函数本身就是对象,而JS闭包通常是造成混乱的原因。

I am trying to understand this little snippet of code 我正在尝试理解这小段代码

// 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);

I get the following results when run in jsFiddle 在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

These show that the functions are using the variable value within their closure and this persists between invocation of the inner functions. 这些表明函数在其闭包内使用变量value ,并且在内部函数调用之间一直存在。 BUT, the value of value does not change in the returned object. 但是,value的value在返回的对象中不会更改。

I think I get the basic point that functions are executed using the scope chain that was in effect when they were defined. 我想我的基本要点是,函数是使用定义时有效的作用域链执行的。

Questions Can I make the value property of the returned object operate in the same way - or is the only way to return it via a function, since the latter retains the variable in its closure? 问题我可以使返回对象的value属性以相同的方式操作-还是通过函数返回它的唯一方法,因为后者将变量保留在其闭包中?

And , just for confirmation, for every invocation of myFunc() , I assume I will get an object whose function properties will have their own scope chain and therefore independent of each invocation. 并且 ,为确认myFunc() ,对于myFunc()每次调用,我都假定将得到一个对象,其功能属性将具有自己的作用域链,因此与每次调用无关。

First of all, do not forget the var keyword when declaring variables. 首先,声明变量时不要忘记var关键字。 When you declare value = 42 inside myFunc , you are actually creating a variable in the global namespace instead of the function scope. 当在myFunc内部声明value = 42 ,实际上是在全局名称空间而不是函数作用域中创建变量。 It should start like this: 它应该这样开始:

function myFunc() {
    var value = 42;

Now, myObject.result is returning 42 because myFunc returns your result object which contains a copy of the value variable declared inside the function. 现在, myObject.result返回42,因为myFunc返回了您的result对象,其中包含在函数内部声明的value变量的副本。

Your functions setValue , getValue and incrementValue are changing the value of value , not result.value . 你的函数setValuegetValueincrementValue正在改变的价值value ,而不是result.value When you call myObject.value , you are getting the value from the returned object, not the inner variable of your function. 调用myObject.value ,您将从返回的对象获取值,而不是从函数的内部变量获取值。

You could get it to work using something like this: 您可以使用以下方法使其工作:

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++;
    }
}

However, there are better design patterns than this. 但是,有比这更好的设计模式。 You could use the new keyword and prototype to define the methods available for the objects returned from your function. 您可以使用new关键字和prototype来定义可用于从函数返回的对象的方法。 Take this example: 举个例子:

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

Can I make the value property of the returned object operate in the same way 我可以使返回对象的value属性以相同的方式运行吗

If you mean that it shows the updated value, yes, you can do that. 如果您的意思是显示更新后的值,那么可以。 You just have to change the code to update the value property as well: 您只需要更改代码即可更新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;
    }
}

The reason why I choose to use both value and result.value is to prevent the modification of the value through result.value . 我选择同时使用valueresult.value是为了防止通过result.value修改值。 If you notice, I don't internally read from result.value , I only write to it. 如果您注意到,我不会从内部读取 result.value ,而只会写它。 That means that assignments to result.value from external code doesn't have an effect. 这意味着从外部代码对result.value赋值无效。 This conforms to how your existing code works. 这符合您现有代码的工作方式。

And, just for confirmation, for every invocation of myFunc() , I assume I will get an object whose function properties will have their own scope chain and therefore independent of each invocation. 并且,为确认myFunc() ,对于myFunc()每次调用,我都假定将得到一个对象,其功能属性将具有自己的作用域链,因此与每次调用无关。

Yes, every invocation of myFunc creates a new object and new functions and they are completely independent from objects/functions created by previous invocations. 是的, myFunc每次调用都会创建一个新的对象和新函数,它们完全独立于先前调用创建的对象/函数。

Yes, you can: 是的你可以:

var result = {
    get value() {
        return value;
    },
    getValue: getValue,
    incrementValue: incrementValue,
    setValue: setValue,
};

Hooray for ECMAScript 5. Of course, this won't work on IE < 8. Hooray for ECMAScript5。当然,这在IE <8上不起作用。

<aside> value = 42; <aside> value = 42; should be var value = 42; 应该是var value = 42; .</aside> </ aside>。

This doesn't have a lot to do with the lifetime of variables, by the way – it's just how assignment works. 顺便说一下,这与变量的生存期没有多大关系–分配的工作方式就是如此。 There are references in JavaScript, but no “reference variables” or “reference properties”. JavaScript中有引用,但没有“引用变量”或“引用属性”。 The object contains a copy of whatever value was at the time; 该对象包含当时的任何value的副本; creating a getter like this is just like creating a function that's called implicitly. 创建这样的getter就像创建一个隐式调用的函数一样。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM