如果函数是对象,函数体的位置在哪里?

时间:2014-09-12 18:40:58

标签: javascript

如果函数是对象,函数体的位置在哪里?

让我澄清一下我对此感到困惑。功能是对象,好的。我可以将对象视为由字符串键和任意类型值组成的哈希映射。我可以这样做:

function Square(size) {
    Rectangle.call(this, size, size);
}
Square.prototype = new Rectangle();

我刚刚将Square视为常规对象,并通过为其分配新值来使其与prototype属性混淆。但是,如果函数只是对象(或者那个问题的哈希映射),那么函数体(在这个例子中是Rectangle.call(this, size, size);)存储在哪里?

我认为它必须存储为某个属性的值,如下所示:

console.log(Square.executableBody); // "Rectangle.call(this, size, size);"

显然,事实并非如此。有趣的是,在阅读"面向对象JavaScript的原理"通过Nicholas C. Zakas,我偶然发现了这个:

  

[...]函数实际上是JavaScript中的对象。函数的定义特征 - 它与任何其他对象的区别 - 是存在名为[[Call]]的内部属性。无法通过代码访问内部属性[...] [[Call]]属性对于函数是唯一的,并指示可以执行该对象。

这可能是我上面寻找的财产。但是,它没有详细说明。函数体是否实际存储在[[Call]]属性中?如果是这样,执行如何运作?很遗憾,我无法找到有关[[Call]]的更多信息,Google主要提供有关函数call方法的信息...

非常感谢一些澄清! :)

2 个答案:

答案 0 :(得分:4)

它成为另一个内部属性的值,称为[[Code]]

  

13.2 Creating Function Objects
  给定由 FormalParameterList 指定的可选参数列表,由FunctionBody指定的主体,由 Scope 指定的词法环境,以及布尔标志 Strict ,一个Function对象构造如下:

     

[...]

     
      
  1. F [[Code]]内部属性设置为 FunctionBody
  2.   

  

如果是,执行如何运作?

调用函数基本上调用内部[[Call]]方法,http://es5.github.io/#x13.2.1中对此进行了描述。我想重要的一步是:

  
      
  1. 结果成为评估 F [[Code]]内部属性 FunctionBody 的结果。< / LI>   

答案 1 :(得分:1)

基本上,出于所有实际目的,您可以将该函数全部视为 该对象。您可以学习JS规范或JS引擎源代码,以了解函数体如何实际存储在对象的内部属性中,但这不能帮助您理解它如何作为JS程序员工作。您可以通过评估fn.toString将主体视为字符串。除了执行它或绑定它或调用Function.prototype上的其他方法之外,您不能以其他方式访问正文。但是,因为它是一个对象,所以它也可以像任何其他对象一样附加属性。

为什么我要将属性附加到函数?这是一个记忆功能的例子(故意简化):

function memoize(fn) {
    var cache = {};
    function memoized(x) {
        return x in cache ? cache[x] : cache[x] = fn(x);
    };
    memoized.clear = function() { cache = {}; };
    return memoized;
 }

因此我们将函数clear作为返回函数的属性。我们可以将其用作:

memofied = memoize(really_long_calculation);
result = memofied(1);  // calls really_long_calculation
result = memofied(1);  // uses cached value
memofied.clear();      // clear cache        
result = memofied(1);  // calls really_long_calculation again

该函数足以在其上调用Object.defineProperty的对象,允许我们按如下方式编写上面的memoization函数,如果我们真的想:

function memoize(fn) {
    var cache = {};
    return Object.defineProperty(function (x) {
        return x in cache ? cache[x] : cache[x] = fn(x);
    }, 'clear', {value: function() { cache = {}; } });
 }

(因为Object.defineProperty返回对象。)这样做的好处是clear采用默认的非可枚举和不可写属性,这似乎很有用。

我甚至可以使用函数作为Object.create的第一个(原型)参数:

someobj = Object.create(function() { }, { prop: { value: 1 } });

但是没有办法调用函数作为原型。但是,它的属性将在创建的对象的原型链中可用。