如何在 Javascript 中动态设置函数/对象名称,因为它在 Chrome 中显示

IT技术 javascript oop google-chrome joose
2021-02-23 08:16:29

这是 Google Chrome 调试器一直困扰我的问题,我想知道是否有办法解决它。

我正在开发一个大型 Javascript 应用程序,使用了大量面向对象的 JS(使用Joose框架),当我调试代码时,我的所有类都被赋予了一个无意义的初始显示值。要了解我的意思,请在 Chrome 控制台中试试这个:

var F = function () {};
var myObj = new F();

console.log(myObj);

输出应该是一行,您可以展开该行以查看 的所有属性myObj,但您首先看到的只是▶ F.

我的问题是,由于我的 OO 框架,每个实例化的对象都获得相同的 'name'它看起来负责这个的代码是这样的:

getMutableCopy : function (object) {
    var f = function () {};
    f.prototype = object;
    return new f();
}

这意味着在调试器中,初始视图总是▶ f.

现在,我真的不想改变Joose如何实例化对象(getMutableCopy...?) 的任何内容,但是如果我可以添加一些内容以便我可以提供自己的名字,那就太好了。

我看过的一些东西,但无法获得:

> function foo {}
> foo.name
  "foo"
> foo.name = "bar"
  "bar"
> foo.name
  "foo"    // <-- looks like it is read only
6个回答
Object.defineProperty(fn, "name", { value: "New Name" });

会解决问题并且是最高效的解决方案。也没有评估。

@speg,我不是 100% 确定您要做什么。您可以发布具有预期输出的要点吗?
2021-04-24 08:16:29
@Piercey4 SOO 关闭!Object.defineProperty(fn.constructor, 'name', { value: 'New Name' });*请参阅此处的警告:developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/...
2021-05-07 08:16:29
这似乎对我不起作用:function caat() { this.legs = 4; } Object.defineProperty(caat, "name", {value: "cat"}) milo = new caat() caat {legs: 4} 我希望在最后一行控制名称的输出,但在打印到控制台时似乎没有使用 name 属性。
2021-05-08 08:16:29
@Piercey4 谢谢,但我还是很难过。我无法让开发工具打印不同的名称:gist.github.com/speg/30abc28a9d83cbf2c8dba897092fd596
2021-05-13 08:16:29
到目前为止最好的答案。它使用旨在定义名称等属性的 API,否则这些属性是只读的。
2021-05-15 08:16:29

在过去的 3 个小时里,我一直在玩这个,最后按照其他线程的建议使用 new Function 至少有点优雅:

/**
 * JavaScript Rename Function
 * @author Nate Ferrero
 * @license Public Domain
 * @date Apr 5th, 2014
 */
var renameFunction = function (name, fn) {
    return (new Function("return function (call) { return function " + name +
        " () { return call(this, arguments) }; };")())(Function.apply.bind(fn));
};   

/**
 * Test Code
 */
var cls = renameFunction('Book', function (title) {
    this.title = title;
});

new cls('One Flew to Kill a Mockingbird');

如果运行上面的代码,您应该会在控制台看到以下输出:

Book {title: "One Flew to Kill a Mockingbird"}
它是否可用于类型为 Function 的 class (es6) ?
2021-04-26 08:16:29

结合使用计算属性名称来动态命名属性,并使用推断函数命名为我们的匿名函数提供计算属性名称:

const name = "aDynamicName"
const tmp  = {
  [name]: function(){
     return 42
  }
}
const myFunction= tmp[name]
console.log(myFunction) //=> [Function: aDynamicName]
console.log(myFunction.name) //=> 'aDynamicName'

人们可以在这里使用他们想要的任何“名称”,以创建一个他们想要的任何名称的函数。

如果这还不清楚,让我们分别分解此技术的两个部分:

计算属性名称

const name = "myProperty"
const o = {
  [name]:  42
}
console.log(o) //=> { myProperty: 42 }

通过计算属性命名,我们可以看到分配给 的属性名称omyProperty[]这里's 导致 JS 查找括号内的值,并将其用于属性名称。

推断函数命名

const o = {
  myFunction: function(){ return 42 }
}
console.log(o.myFunction) //=> [Function: myFunction]
console.log(o.myFunction.name) //=> 'myFunction'

这里我们使用推断的函数命名。该语言查看函数被分配到的任何位置的名称,并给出推断名称的函数。

我们可以结合这两种技术,如开头所示。我们创建了一个匿名函数,它通过推断的函数命名从计算属性名称中获取它的名称,这是我们想要创建的动态名称。然后我们必须从它嵌入的对象中提取新创建的函数。


使用堆栈跟踪的示例

命名提供的匿名函数

// Check the error stack trace to see the given name

function runAnonFnWithName(newName, fn) {
  const hack = { [newName]: fn };
  hack[newName]();
}

runAnonFnWithName("MyNewFunctionName", () => {
  throw new Error("Fire!");
});

看看这个:<<<<<< function named42(name_of_42){ var obj = { [name_of_42] : function(){ return 42; } }; 返回对象 [name_of_42]; } test1 = named42('forty_two'); 控制台日志(test1.name);>>>>> 这符合您的答案,并记录“四十二”<<<<<<function named_fromArg(name_of, func){ var obj = { [name_of] : func }; 返回对象 [name_of]; } test2 = named_fromArg('hello', function(){ return 'world'; }); >>>>>> 这不像您的答案所预期的那样工作并记录空字符串。令人费解,不是吗?有人知道这是怎么回事吗??
2021-04-15 08:16:29
这应该是公认的答案。它工作得很好。
2021-04-16 08:16:29
我没有看到此代码如何为函数分配名称。它只是创建一个具有动态属性名称的对象,该对象包含一个匿名函数。函数本身没有名称。
2021-05-03 08:16:29

虽然它很丑,但你可以通过 eval() 作弊:

function copy(parent, name){
  name = typeof name==='undefined'?'Foobar':name;
  var f = eval('function '+name+'(){};'+name);
  f.prototype = parent;
  return new f();
}

var parent = {a:50};
var child = copy(parent, 'MyName');
console.log(child); // Shows 'MyName' in Chrome console.

注意:您只能使用作为函数名有效的名称!

附录:为避免eval在每个对象实例化上执行 ing,请使用缓存:

function Cache(fallback){
  var cache = {};

  this.get = function(id){
    if (!cache.hasOwnProperty(id)){
      cache[id] = fallback.apply(null, Array.prototype.slice.call(arguments, 1));
    }
    return cache[id];
  }
}

var copy = (function(){
  var cache = new Cache(createPrototypedFunction);

  function createPrototypedFunction(parent, name){
    var f = eval('function '+name+'(){};'+name);
    f.prototype = parent;
    return f;
  }

  return function(parent, name){
    return new (cache.get(name, parent, typeof name==='undefined'?'Foobar':name));
  };
})();
+1 - 好主意。不幸的是,我太害怕对每个单个对象实例化执行 eval 的性能成本。
2021-04-19 08:16:29
适用于传递的数组。但我需要将构造函数传递给命名函数。
2021-04-21 08:16:29
添加了带有缓存的版本。
2021-04-25 08:16:29

这不会完全解决您的问题,但我建议覆盖类原型上的 toString 方法。例如:

my_class = function () {}
my_class.prototype.toString = function () { return 'Name of Class'; }

如果您直接在控制台中输入 my_class 的实例,您仍然会看到原始类名(我认为不可能对此做任何事情),但是您会在错误消息中获得不错的名称,我发现很有帮助。例如:

a = new my_class()
a.does_not_exist()

会报错:“TypeError: Object Name of Class has no method 'does_not_exist'”