Javascript闭包 - 变量的生命周期

jca*_*ddy 0 javascript closures

作为一个相当新的Javascript和ac#背景我一直在磕磕绊绊.我很快就知道,我需要了解函数本身就是对象这一事实,而且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);
Run Code Online (Sandbox Code Playgroud)

在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
Run Code Online (Sandbox Code Playgroud)

这些表明函数value在它们的闭包中使用变量,并且这在内部函数的调用之间持续存在.但是,value返回的对象中的值不会改变.

我想我得到的函数是使用在定义时生效的作用域链来执行的基本点.

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

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

Gui*_*ehn 5

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

function myFunc() {
    var value = 42;
Run Code Online (Sandbox Code Playgroud)

现在,myObject.result返回42是因为myFunc返回result包含value函数内声明的变量副本的对象.

你的功能setValue,getValueincrementValue正在改变的价值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++;
    }
}
Run Code Online (Sandbox Code Playgroud)

但是,有比这更好的设计模式.您可以使用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
Run Code Online (Sandbox Code Playgroud)

  • @Walter:这实际上可能是一个实现细节.由于原始值是*不可变的*你不能告诉(仅通过执行代码)原语是否也不仅仅是引用. (3认同)