在运行时用JavaScript设置函数的名称

Set the name of a function at runtime in JavaScript

本文关键字:函数 设置 运行时 JavaScript      更新时间:2023-09-26

是否可以在运行时用JavaScript设置函数的名称?

var ctor = function() {}; // Anonymous function because I don't know the name ahead of runtime.
ctor.name = 'foo'; // Pseudocode  - this is effectively what I want to do

我希望以上等同于:

var ctor = function foo() {};

编辑

下面是一个示例用例:

function mix(fn1, fn2, name) {    
    var ctor = function() {};
    ctor.name = name; // Vain attempt to set the name of the function.
    ctor.prototype = Object.create(fn1.prototype);
    Object.keys(fn2.prototype).map(function(k) {
        ctor.prototype[k] = fn2.prototype[k];
    });
    // Return a constructor function with the prototype configured.
    return ctor;
}
function Foo() {}
Foo.prototype.foo = function(){};
function Bar(){}
Bar.prototype.bar = function() {};
var Foobar = mix(Foo, Bar, 'Foobar');
console.log(new Foobar()); // ctor {bar: function, foo: function} (in Chrome) - I wanted Foobar { bar: function, foo: function }

name是一个非标准的,只有一些浏览器支持。

现在,它已经在ECMAScript6:中进行了标准化

19.2.4.2名称

name属性的值是一个字符串,用于描述作用该名称没有语义意义,但通常是用于引用函数的变量或属性名ECMAScript代码中的定义点。此属性具有属性{[[Writable]]:false,[[Enumerable]]:false,[[可配置]]:true}。

没有上下文名称的匿名函数对象根据本规范与它们相关联的name没有自己的属性,但继承%FunctionPrototype%的name属性。

因此,您的代码将在不支持name的浏览器上工作,但新属性将是可写和可枚举的。在支持它的浏览器上,您的代码将无法工作,因为name是不可写的。

因此,更好的等效代码是

Object.defineProperty(ctor, 'name', {
    value: 'foo',
    configurable: true
});

免责声明:这可能会让一些喜欢代码安全和可预测的人感到不安

当然,你不会真的这么做,因为你很明智,对吧

function rename(fn, name) {
  var fnStr = fn.toString().replace(/function/, 'function ' + name);
  eval.call(window, fnStr);
  return window[name];
}
var tmp = function(a, b) { return a + b; };
rename(tmp, 'add');
add(3, 4); // 7

当然,根据你需要的良好表现(如果你使用eval,那就不太好了),你可以(但你不会)

Function.prototype.rename = function(name) {
  return rename(this, name);
};

在实际代码中这样做,人们会讨厌你,,但没关系,因为你不会

函数的定义范围存在一些问题(可能还有一些边缘断裂的情况)。Eval使用this的上下文来决定在哪个范围内操作,因此传递窗口对象意味着重命名的函数将始终在窗口对象内定义。

这是一个相当做作的例子,但它应该让你对陷阱有一些了解。

function init() {
  function go() {
    return 'go';
  };
  var ctor = function() {
    return 'ctor';
  };
  rename(ctor, 'go');
  go(); // 'go'
  next();  
}
function next() {
  go(); // 'ctor'
}