javascript中的对象

javascript中的对象,javascript,Javascript,基本值存储在javascript的堆栈中,而对象存储在堆中。我理解为什么要在堆栈中存储原语,但是为什么要在堆中存储对象呢?对象的大小可以动态增长。因此,您需要调整它们的内存需求。这就是它们存储在堆中的原因。实际上,在JavaScript中,甚至原语都存储在堆中,而不是堆栈中(不过请参见下面的分节注释)。当控件进入函数时,将为该函数调用创建一个执行上下文(对象),该上下文包含一个变量对象。函数的所有vars和参数(加上一些其他东西)都是该匿名变量对象的属性,与命名对象的其他属性完全相同。调用堆栈被

基本值存储在javascript的堆栈中,而对象存储在堆中。我理解为什么要在堆栈中存储原语,但是为什么要在堆中存储对象呢?

对象的大小可以动态增长。因此,您需要调整它们的内存需求。这就是它们存储在堆中的原因。

实际上,在JavaScript中,甚至原语都存储在堆中,而不是堆栈中(不过请参见下面的分节注释)。当控件进入函数时,将为该函数调用创建一个执行上下文(对象),该上下文包含一个变量对象。函数的所有
var
s和参数(加上一些其他东西)都是该匿名变量对象的属性,与命名对象的其他属性完全相同。调用堆栈被使用,但规范不要求堆栈用于“本地”变量存储,JavaScript的闭包将使用堆栈“ALAC,C++等”,这是不切实际的。详情请参阅

而是使用链(链表)。当引用非限定符号时,解释器将检查变量对象的当前执行上下文,以查看它是否具有该名称的属性。如果是这样,它就会被使用;如果没有,则检查作用域链中的下一个变量对象(注意,这是词法顺序,而不是调用堆栈那样的调用顺序),依此类推,直到到达全局执行上下文(全局执行上下文与任何其他执行上下文一样具有变量对象)。全局EC的变量对象是我们可以在代码中直接访问的唯一对象:
this
在全局范围代码中指向它(以及在没有显式设置this的情况下调用的任何函数中)。(在浏览器上,我们有另一种直接访问它的方式:全局变量对象有一个名为
window
的属性,它用来指向自身。)

您的问题是,为什么对象存储在堆中:因为它们可以彼此独立地创建和释放。C、C++和其他使用局部变量的堆栈的函数可以这样做,因为函数返回时变量可以(也应该)被销毁。堆栈是一种非常有效的方法。但物体并不是以那种简单的方式被创造出来的;同时创建的三个对象可能具有完全不同的生命周期,因此堆栈对它们没有意义。而且,由于JavaScript的局部变量存储在对象上,而这些对象的生命周期(可能)与函数返回无关……那么,您就明白了。:-)在JavaScript中,堆栈几乎只用于返回地址


然而值得注意的是,仅仅因为事情在概念上是如上所述的,这并不意味着发动机必须在发动机罩下这样做。只要它在规范中描述的外部工作,实现(引擎)就可以自由地做他们喜欢做的事情。我知道V8(谷歌的JavaScript引擎,在Chrome和其他地方使用)做了一些非常聪明的事情,比如使用堆栈作为局部变量(甚至函数中的局部对象分配),然后在必要时只将它们复制到堆中(例如,因为执行上下文或其上的单个对象在调用后仍然有效)。您可以看到,在大多数情况下,这将使堆碎片最小化,并比依赖GC更积极有效地回收临时内存,因为与大多数函数调用相关联的执行上下文不需要在调用后继续存在。让我们看一个示例:

function foo() {
    var n;

    n = someFunctionCall();
    return n * 2;
}

function bar() {
    var n;

    n = someFunction();
    setCallback(function() {
        if (n === 2) {
            doThis();
        }
        else {
            doThat();
        }
    });
}
在上面的例子中,像V8这样积极优化的引擎可以检测到当
foo
返回时,调用
foo
的概念执行上下文永远不需要存在。因此V8可以在堆栈上自由分配该上下文,并使用基于堆栈的机制进行清理

相反,为调用
bar
而创建的执行上下文必须在
bar
返回后保留,因为有一个闭包(我们传递给
setCallback
的匿名函数)依赖于它。因此,在编译
bar
时(因为V8会动态编译为机器代码),V8可能会使用不同的策略,实际上是在堆中分配上下文对象

(顺便说一句,如果上述任何一种方法都使用了
eval
,那么V8和其他发动机很可能都不会尝试任何形式的优化,因为
eval
引入了太多的优化失败模式。如果不必使用
eval
的话,这也是不使用
eval
的另一个原因,而且几乎不必使用。)


但这些都是实现细节。从概念上讲,事情如上所述。

原语值和对象总是存储在其他对象中,它们是某些对象的属性


没有一个基本值/对象不是另一个对象的属性。(这里唯一的例外是全局对象).

是的,但我无法想象这一点。你能举一个对象的例子并解释这个场景吗。简单地说,假设你有一个具有属性年龄和地址的对象。在JavaScript中,你可以通过编程方式添加另一个属性。堆结构就是这样的,很容易在任何位置分配释放内存。因为堆栈按顺序递增或递减,如果需要,不可能为堆栈中的对象分配额外的内存。我希望这能让您明白一点。是什么让您认为原始值存储在堆栈中?它们不是。@T.J.Crowder:我知道这已经过去了4年,但我想说声谢谢这是一个惊人的答案。在JavaScript中,内存和执行上下文是相同的吗?@Nips:执行上下文(至少在概念上)是一个对象,因此它占用内存;这并不意味着它“是”内存(很多其他东西也保存在内存中)