【问题标题】:Function versus Object constructor函数与对象构造函数
【发布时间】:2023-06-27 19:43:01
【问题描述】:

我不太确定如何问这个问题,所以我会举个例子。假设我有这个设置:

var x = function() {
  console.log('YAY!');
};
x.test0 = 0;
x.test1 = 1;
x.test2 = "hello world";

按预期工作:

x(); // YAY!
x.test0 // 0
x.test2 // "hello world"

现在,我想知道如何首先从一个对象开始设置它。我尝试使用构造函数添加函数,但这不起作用。

var x = {
  test0 : 0,
  test1 : 1, 
  test2 : 'hello world',
  constructor: function() {
    console.log('YAY!');
  }
}

x(); // object is not a function
x.test0 // 0
x.test2 // "hello world";

我尝试了其他疯狂的事情,但似乎没有任何效果。

有什么想法吗?还是我坚持第一种方式?

【问题讨论】:

  • 您要解决的问题是什么?
  • 我只是想知道如何从一个对象开始并为其附加一个函数,以便x() 运行该函数。
  • 函数是唯一可调用的原生 EMCAScript 类型。您不能使非函数可调用,因为 ECMAScript 没有公开任何方式来操作对象的 [[Call]] 内部属性。如果你想把一个对象变成一个函数,为什么不先把它变成一个函数呢?
  • 在 JS 函数中是一个对象,但反之亦然是不正确的
  • 更简洁的代码。但实际上,我只是想知道这是否可能。

标签: javascript function object constructor


【解决方案1】:

如您的第一个示例所示,JavaScript 中的函数是对象并且可以具有属性。

ECMAScript 为对象定义了“internal properties”(和内部方法)。这些内部属性有助于定义对象的状态,但并非所有对象的内部属性都可以直接从代码中设置。我们用双方括号表示内部属性名称,例如[[Foo]]

当您调用像foo() 这样的函数时,您会运行对象的[[Call]] 内部方法。但是,只有函数对象具有[[Call]] 内部方法。无法设置或更改非宿主对象的[[Call]] 方法;它是在定义对象时设置的,ECMAScript 没有定义任何机制来更改它。 (“Host”对象是浏览器或其他执行环境提供的对象,可以按不同的规则播放。除非您正在编写浏览器,否则您可能不需要考虑此异常。)

因此,如果你定义一个函数

foo = function() { doStuff(); return 5; };

该函数(分配给变量foo)有一个永久的[[Call]] 方法(根据section 13.2 中的函数创建规则),它运行doStuff 并返回5

如果你有一个非函数对象

foo = { };

该对象缺少[[Call]] 属性。没有办法给它一个[[Call]] 属性,因为非宿主对象只能在定义时设置[[Call]]。逻辑内部属性[[Call]] 与实际代码中可访问的任何对象属性均不对应。

总之,使非函数对象可调用是不可能的。如果您希望一个对象是可调用的,请先将其定义为一个函数,就像您在第一个示例中所做的那样。

【讨论】:

  • 谢谢你,这完全回答了我的问题:)
【解决方案2】:

简单地说,你不能。为什么?因为两个对象的类型不同,首先是Function Object,其次返回一个标准对象。所以两者都继承自不同的祖先。这里唯一的可能性是,如果您可以将对象转换为函数,并且 JavaScript 本身没有这样的东西可用。但是,您可以使用自己的强制转换方法。

function toFunction (obj, fnProp) {
    var fn = function () {};
    if (typeof obj[fnProp] !== 'function') return fn;
    else {
        fn = obj[fnProp];
        for (prop in obj) {
            fn[prop] = obj[prop];
        }
    }
    return fn;  
}


var z = toFunction(y, 'prototype');    // with your example

【讨论】:

    【解决方案3】:

    你不能只是创建一个对象,然后像函数一样运行它。

    你可以反过来做,就像在 JavaScript 中一个函数就是一个对象:

    x.prop=1;
    console.log(x.prop);
    
    function x() {
        return true;
    }
    

    【讨论】:

      【解决方案4】:

      没有得到你想要的东西,你想要面向对象的东西吗?这可能会有所帮助

      function x(){
          this.test0 = 0;
          this.test1 = 1;
          this.test2 = 'hello word';
          console.log('Wow!');
      }
      
      var y = new x(); // new object of x PRINTS WOW and set's default values
      console.log(y.test0) // 0
      console.log(y.test2) // "hello world";
      

      【讨论】: