繁体   English   中英

函数内创建对象的Javascript变量范围

[英]Javascript variable scope for objects created within function

考虑一下这段代码,

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不存在。 该变量真正存储在哪里?

_name的作用域为getPerson函数,因为在此使用var关键字对其进行了声明。

被嵌套在任何功能getPerson将继承在声明的变量getPerson ,他们可以覆盖此声明自己的变量。 这个概念称为closure ,在进行JavaScript认真开发之前值得理解。

在JavaScript中,作用域不是由块决定的(与Java中一样),而是函数 scoped

所以, _namesetName功能是一样的_name是在宣布getPerson

_name的范围是getPerson()函数中的任何代码。

在Javascript中,函数中的局部变量的作用范围是该函数的特定调用,并且每次调用该函数都会创建一组新的局部变量。 同样,这些局部变量也像其他变量一样被垃圾回收。 它们并不严格存储在函数退出时会被破坏的堆栈中。

由于进行了垃圾回收,只要仍然可以访问的代码引用了该变量,函数中的变量将继续存在。 因此,在您的getPerson()函数中, _name变量的范围是对getPerson()函数的特定调用,但是该变量的生存期只要某些代码仍然可以到达该变量,即使在调用之后很长时间也是如此。 getPerson()已完成。

这在Javascript中称为闭包,是一种非常有价值和有用的工具。

因为person.getName()person.setName()甚至在getPerson()函数完成执行后很长时间仍具有对_name变量的引用,所以它将保持活动状态,并且不会被语言垃圾收集。

因此, scope由变量的声明确定。 _name的作用域范围是在其声明的函数中,并且该函数中还存在任何其他子作用域。 Javascript具有lexical范围(这意味着范围由声明它的位置/方式决定)。 但是,范围内的变量的生存期由垃圾收集器单独确定,并且范围内的变量的生存期可以远远超出创建范围的函数的执行范围,只要其他一些可访问的代码仍然引用了该变量。

我喜欢将功能范围本身视为Javascript中的垃圾收集实体。 尽管Javascript的某些实现甚至可能比整个作用域更为精细(例如,尽可能在范围内进行垃圾收集),但垃圾收集而不是基于堆栈的作用域概念为您提供了一个框架,使您可以理解像Javascript这样的语言和像C ++这样的语言,它们使用显式堆栈框架来确定局部变量的寿命。

我认为您可能是从Java背景开始使用JavaScript的。

var _name = ""; 在匿名函数(分配给getPerson的函数)的范围内定义_name变量。 该变量没有附加到任何对象,而只是一个普通变量。

如果您确实要执行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.getNameperson.setName 由于这些方法是在getPerson中定义的,因此它们也可以访问_name变量(因为_name是在同一函数中定义的)。

getPerson外部的代码无法访问_name ,但是可以(通过受控方式)通过getName和setName方法访问_name 这将为_name变量创建隐私。

暂无
暂无

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

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