你能获得调用函数的属性名吗?

bgo*_*dst 1 javascript properties

我已经做了很多搜索和一些游戏,我很确定这个问题的答案是否定的,但我希望JavaScript专家可能有一个技巧可以做到这一点.

JavaScript函数可以由多个属性引用,即使在完全不同的对象上也是如此,因此不存在包含该函数对象或属性.但是,无论何时实际调用函数,都必须通过单个对象(至少window是全局函数调用的对象)和该对象的属性来完成.

(函数也可以通过函数局部变量调用,但是我们可以将函数局部变量视为作用域的激活对象的属性,因此该情况​​不是此规则的例外.)

我的问题是,有没有办法从函数体内部获取用于调用函数的属性名称?我不想将属性名称作为参数传递,或者在封闭范围内的变量周围传递,或者将名称存储为保存函数引用的对象的单独属性,并使函数访问该属性的属性的this对象.

这是我想要做的一个例子:

var callName1 = function() { var callName = /* some magic */; alert(callName); };
var obj1 = {'callName2':callName1, 'callName3':callName1 };
var obj2 = {'callName4':callName1, 'callName5':callName1 };

callName1(); // should alert 'callName1'
obj1.callName2(); // should alert 'callName2'
obj1.callName3(); // should alert 'callName3'
obj2.callName4(); // should alert 'callName4'
obj2.callName5(); // should alert 'callName5'
Run Code Online (Sandbox Code Playgroud)

从我的搜索,它看起来就像你可以得到的最接近的arguments.callee.name,但是这不起作用,因为它只返回在定义时固定到函数对象的名称,并且只有当它被定义为命名函数(我的例子中的函数不是).

我还考虑过,也许你可以遍历this对象的所有属性并测试相等性,arguments.callee以找到其值是对函数本身的引用的属性,但这也不起作用(在一般情况下),因为可能是对象自己(或继承)属性集中的函数的多个引用,如我的示例中所示.(而且,这似乎是一种效率低下的解决方案.)

可以这样做吗?

She*_*epy 7

简短回答:

  1. 不,你不能得到用于调用你的函数的"属性名称".
  2. 可能根本没有名称,或者不同范围内有多个名称,因此"属性名称"的定义非常糟糕.
  3. arguments.callee 已弃用,不应使用.
  4. 没有不使用参数或闭包的解决方案.

答案很长:

正如thefourtheye评论的那样,你应该重新思考你想要做的事情并在一个新问题中提出这个要求.但是有一些常见的误解,所以我会试着解释为什么你不能得到"简单的属性名称".

原因是因为它并不简单.

在我们继续之前,让我们澄清一些事情.激活对象根本不是对象.ECMAScript 5.1规范称它们为Environment Records (10.2.1),但更常见的术语是Scope chain.在浏览器中,全局范围(通常)是window对象,但所有其他范围不是对象.有可能是你用来调用函数的对象,当你调用一个函数,你必须在一定范围内.它们是不同的.

并且有很多名字.

  • 调用函数时,需要引用它,例如通过对象属性.该引用可能有一个名称.
  • 范围链具有声明,它始终具有名称.
  • A Function(真正的函数,不是引用)也可能有一个函数名称 - 你的arguments.callee.name- 在声明时固定.

它们不仅名称不同,而且(不总是)您正在寻找的"财产名称".

var obj = { prop : function f(){} }, func = obj.prop;
// "obj" and "func" are declarations.
// Function name is "f" - use this name instead of arguments.callee
// Property name is "prop"
func();     // Reference name is "func"
obj.prop(); // Reference names are "obj" and "prop"
// But they are the same function!
// P.S. "this" in f is undefined (strict mode) or window (non-strict)
Run Code Online (Sandbox Code Playgroud)

因此,函数引用可能来自binding(例如函数声明),Object(arguments.callee)或a variable.他们都是References (8.7).参考确实有一个名字(可以这么说).

问题是,函数引用并不总是来自对象或作用域链,并且其名称并不总是被定义. 例如,常见的闭包技术:

(function(i){ /* what is my name? */ })(i)
Run Code Online (Sandbox Code Playgroud)

即使引用确实有名称,函数调用(11.2.3)也不会以任何方式将引用或其名称传递给函数. 这使得JavaScript引擎保持理智.考虑这个例子:

eval("(new Function('return function a(){}'))()")() // Calls function 'a'.
Run Code Online (Sandbox Code Playgroud)

最后的函数调用是指eval函数,它引用一个新的全局作用域的结果(无论如何,在严格模式下),它引用一个函数调用语句,它引用一个组,它引用一个匿名的Function对象,并包含表达并返回一个名为'a'的函数.

如果你想从a中得到"属性名称",应该得到哪一个?"EVAL"?"功能"?"匿名"?"一个"?他们都是?在回答之前,考虑一些复杂问题,例如跨iframe的函数访问,它具有不同的全局变量以及交叉原点限制,或与本机函数的交互(Function.prototype.bind例如),您将看到它如何迅速变成地狱.

这也是为什么arguments.caller,__caller__以及其他类似技术现在都被弃用的原因.函数的"属性名称"比调用者更加不明确,几乎不切实际.至少调用者总是执行上下文(不一定是函数).

所以,不知道你的真正问题是什么,获得"属性名称"的最佳选择是使用闭包.