在javascript中,Function对象的本质是什么?


这个问题最近一直困扰着我,我感到自己无法理解Function对象的本质是什么。
如果说是一个普通的js变量。比如


 var a = 5;

我可以把它理解为开辟了某个内存给变量a,并把内容赋值为5。
那么如果我定义了一个函数:


 var fn = function() { console.log(this); };

它在内存中又是怎么存储的?

其实把我的问题再具体话一点,可以这样问:
1. Function对象中如何保存作用域链的上下文(context)
2. Function对象的函数体是以字符串的形式存储下来的吗?

再看看下面这个例子:


 var fn;
(function(){
    var a = 5;
    fn = function () {
        console.log(a++);
    };
})();
fn();

这是个常见的闭包例子,就拿这个例子来说,Function对象是如何把变量a保存在自己的上下文环境中的呢?

首先感谢大家热情的回答,我再补充说明一下:
我主要的问题是Function在解释器引擎(比如Google V8)里是以怎样的形式实现的?是把函数体以字符串的形式存储下来,并在执行时以类似eval方法来调用它,或者还是其他方式?所以我的实际问题可能比较底层一点。

function 作用域 JavaScript 本质 内存

xwh8888 10 years, 8 months ago

在JS中,Function对象就是Function对象。
在引擎中,随便它怎么实现都可以,只要遵照ECMAScript Spec就行了。
不过只要不是玩具引擎,就肯定不会把代码作为字符串存储,到执行到函数时再去解析的。

要理解这个问题,你需要定个目标,你要理解到什么样的深度呢?
我有个建议,就是不要把问题描述得多么底层。这样除了提高B格之外,其实无助于理解问题。这个问题是一个原理上的问题,不定非要你会C++、汇编才能理解。

你要知道Closure、This这些对象是如何传给函数的,即你说的闭包变量是如何传给函数的。你只需要参照ECMAScript Spec中「Creating Function Objects」、「Executable Code and Execution Contexts」这些章节就行了。
伪代码其实就是这样,对于下面的代码:


 var fn;
(function(){
    var a = 5;
    fn = function () {
        console.log(a++);
    };
})();
fn();

经过解析,会变成类似下面的对象:


 var fn;
var RANDOM_LAMBA_1={
  FormalParameterList:[],
  Scope:{fn:&fn},  //假设用&表示变量的地址
  Code:"\
   var a = 5;\
   fn ={\
      FormalParameterList:[],\
      Code:\"console.log(a++)\",\
      Scope:{a:&a}\
   };\
   return fn;\
  ",

};
RANDOM_LAMBA_1.Call(this,[]);
//Call方法大概如下:
function Call(thisObject,args) {
  var context={},fn=this; //this是Function对象
  fn.FormalParameterList.zip(args).forEach(function (a) {
    context[a[0]]=&a[1];
  });
  context.arguments=args;
  context.this=thisObject;//将this当成一个普通变量理解就行了
  with(context,fn.Scope) {
    eval(fn.Code);
  }
}

至于引擎中怎么实现的,想太多也没用,思而不学则殆。
理解这些至少需要理解 SouceCode => Tokens => AbstractSyntaxTree .....=> JIT Code 这个流程。将代码转换成抽象语法树的部分在最初JS加载解析时就已经执行了,不然怎么能不执行函数就能报告语法错误呢?虽然Spec用eval(stringSourceCode)这种方式抽述,但解释器实现显然最多只需要直接遍历已经Parse过后的Tree就行了,绝不会再去读取函数的FunctionBody的字符串解析执行的。如果还想更深入地理解,还不如直接去读编译原理呢。

嘛嘛嘛嘛嘛 answered 10 years, 8 months ago

Your Answer