使用此代码:
function baz() {
var x = "foo";
function bar() {
debugger;
};
bar();
}
baz();
Run Code Online (Sandbox Code Playgroud)
我得到了这个意外的结果:

当我更改代码时:
function baz() {
var x = "foo";
function bar() {
x;
debugger;
};
bar();
}
Run Code Online (Sandbox Code Playgroud)
我得到了预期的结果:

此外,如果eval在内部函数中有任何调用,我可以按照我想要的方式访问我的变量(无论我传递给什么都没关系eval).
同时,Firefox开发工具在两种情况下都给出了预期的行为.
与Chrome有什么关系,调试器的行为不如Firefox?我已经观察了这种行为一段时间,包括版本41.0.2272.43 beta(64位).
是不是Chrome的javascript引擎可以"平坦化"这些功能呢?
有趣的是,如果我添加在内部函数中引用的第二个变量,则该x变量仍未定义.
我知道在使用交互式调试器时经常有范围和变量定义的怪癖,但在我看来,基于语言规范,应该是这些怪癖的"最佳"解决方案.所以我很好奇这是因为Chrome比Firefox更优化.以及在开发期间是否可以轻松禁用这些优化(也许在开放工具打开时应该禁用它们?).
此外,我可以使用断点和debugger语句重现这一点.
这主要是一个好奇心问题.考虑以下功能
var closure ;
function f0() {
var x = new BigObject() ;
var y = 0 ;
closure = function(){ return 7; } ;
}
function f1() {
var x = BigObject() ;
closure = (function(y) { return function(){return y++;} ; })(0) ;
}
function f2() {
var x = BigObject() ;
var y = 0 ;
closure = function(){ return y++ ; } ;
}
Run Code Online (Sandbox Code Playgroud)
在每种情况下,在执行函数之后,(我认为)无法到达x,因此BigObject可以被垃圾收集,只要x是对它的最后一个引用.只要评估函数表达式,一个简单的解释器就会捕获整个范围链.(首先,你需要这样做来调用eval工作 - 下面的例子).更智能的实现可能会在f0和f1中避免这种情况.更智能的实现将允许保留y,但不保留 …
我试图理解何时this在ES6箭头函数中进行词法绑定的规则.我们先来看看这个:
function Foo(other) {
other.callback = () => { this.bar(); };
this.bar = function() {
console.log('bar called');
};
}
Run Code Online (Sandbox Code Playgroud)
当我构造a时new Foo(other),在另一个对象上设置回调.回调是一个箭头函数,并且this箭头函数在词法上绑定到Foo实例,因此Foo即使我没有保留对Foo周围的任何其他引用,也不会进行垃圾回收.
如果我这样做会怎么样?
function Foo(other) {
other.callback = () => { };
}
Run Code Online (Sandbox Code Playgroud)
现在我将回调设置为nop,我从不提及this它.我的问题是:箭头功能是否仍然是词法绑定this,Foo只要活着就保持other活着,或者Foo在这种情况下可能是垃圾收集?
作为ECMAScriptv5,每当控件输入代码时,enginge创建一个LexicalEnvironment(LE)和一个VariableEnvironment(VE),对于功能代码,这两个对象是完全相同的引用,它是调用NewDeclarativeEnvironment(ECMAScript v5 10.4)的结果. 3),在函数代码中声明的所有变量都存储在VariableEnvironment(ECMAScript v5 10.5)的环境记录组件中,这是闭包的基本概念.
令我困惑的是Garbage Collect如何使用这种闭包方法,假设我有以下代码:
function f1() {
var o = LargeObject.fromSize('10MB');
return function() {
// here never uses o
return 'Hello world';
}
}
var f2 = f1();
Run Code Online (Sandbox Code Playgroud)
在该行之后var f2 = f1(),我们的对象图将是:
global -> f2 -> f2's VariableEnvironment -> f1's VariableEnvironment -> o
Run Code Online (Sandbox Code Playgroud)
从我的小知识来看,如果javascript引擎使用引用计数方法进行垃圾收集,则该对象o至少有1次重新引用,并且永远不会被GCed.显然这会导致浪费内存,因为o永远不会被使用但总是存储在内存中.
有人可能会说引擎知道f2的VariableEnvironment …
在我的顶级函数中,我使用require.js导入一些依赖项.他们在那里,没问题.在这个函数中,我定义了一个回调函数,并尝试使用通过require.js导入的一些变量,即父闭包中的变量.
他们只是不在那里,正如一个断点和偷看Chrome检查员的Scope Variables面板所证实的那样.
我理解这一点fn.apply和朋友只是设置上下文this,而不是他们可以销毁对闭包的引用或改变范围链.
define([
'backbone',
'backbone.vent',
'app/utils/foo',
'app/services/intent'
], function(Backbone, Vent, Foo) {
'use strict';
// Backbone, Vent, and Foo are defined here
Vent.on('myevent', function(options) {
// Backbone is defined here, but not Vent or Foo.
});
});
Run Code Online (Sandbox Code Playgroud)
这怎么可能呢?
我该如何解决?
我从node.js的这个线程垃圾收集中学到了node.js使用的是分代GC.
我经常使用循环对象引用(我删除/确保最终超出范围)并且想知道node.js是否处理好它们.所以对于例如.如果它是使用ref完成的.计数,会有问题,所以我想知道节点有多好.
一些使用场景:
对于每个http请求,我创建一个带有lambda的setTimeout,该lambda可能引用了scope对象.scope对象还引用了timeout对象等...
对于每个用户会话,我有一个指针(仍在进行C编程)对http请求对象的引用,它也引用了会话对象等...请求对象经常被删除,但会话对象不被删除.
编辑:我问因为我在网上找到这个链接http://lifecs.likai.org/2010/02/how-generational-garbage-collector.html
假设我有一个简单的http服务器,例如:
var http = require('http');
http.createServer(function (req, res) {
req.on('data', function (data) {
console.log('Got some data: ' + data);
});
req.on('end', function () {
console.log('Request ended!');
});
res.end('Hello world!');
}).listen(3000);
Run Code Online (Sandbox Code Playgroud)
所以,基本上是默认的101样本,到目前为止没什么特别的 - 除了我订阅了可读流data的end事件req.现在我想知道当我不再需要这些事件时是否必须取消订阅这些事件?
或者当可读流结束时它们会自动清除吗?
像这样的代码会导致内存泄漏吗?
在《你不知道的 JS:作用域和闭包》一书中,Kyle simpson 指出块作用域变量有助于垃圾回收,具体示例如下:
function process(data) {
// do something interesting
}
{
let someReallyBigData = {};
process(someReallyBigData);
}
var btn = document.getElementById("my_button");
btn.addEventListener("click", function click(evt) {
console.log("Clicked!");
}, false);
Run Code Online (Sandbox Code Playgroud)
现在上面的示例应该有助于垃圾收集,因为someReallyBigData一旦块结束,变量就会从内存中删除,与此示例不同,它对垃圾收集没有帮助:
function process(data) {
// do something interesting
}
var someReallyBigData = {};
process(someReallyBigData);
var btn = document.getElementById("my_button");
btn.addEventListener("click", function click(evt) {
console.log("Clicked!");
}, false);
Run Code Online (Sandbox Code Playgroud)
现在我确信这个人对他提供的例子(第一个)是正确的;var但是,我想知道如果我们使用匿名 IIFE(立即调用函数表达式)以及普通的而不是{}花括号和变量,是否一切都会相同let。让我把它变成一个例子:
function process(data) {
// do something interesting
}
(function(){
var someReallyBigData = {};
process(someReallyBigData);
}()); …Run Code Online (Sandbox Code Playgroud) 我知道闭包中的代码可以访问范围链中的变量和方法及参数,但是如果它不使用任何一个会发生什么?那些变量仍然保留?
考虑这种情况:
function f(){
var a=[];
for(var i=0;i<1000000;i++) a.push({});
return function(){
alert('Hi');
};
}
var x = f();
Run Code Online (Sandbox Code Playgroud)
变量是否a保留在内存中,即使闭包没有使用它?
谢谢
更新:似乎没有关于'琐碎'关闭的答案.因此,假设每个闭包(即使它什么都不做)可以在内存中保留范围链中的所有方法,包括它们的参数,变量和内部函数(直到闭包被垃圾收集),这是公平的吗?
此外,关于node.js的"可能重复"的问题 - 据我所知node.js仅在基于谷歌的v8 JS引擎的专用环境上运行.在这里,我谈论的是将在任何现代浏览器中运行的Web应用程序(在大多数情况下)
javascript ×9
closures ×4
ecmascript-6 ×2
node.js ×2
v8 ×2
memory ×1
memory-leaks ×1
requirejs ×1
scope ×1
scope-chain ×1
spidermonkey ×1