【发布时间】:2011-01-20 12:42:55
【问题描述】:
考虑这个 javascript 代码:
var bar = function () { alert("A"); }
var foo = bar;
bar = function () { alert("B"); };
foo();
运行此代码时,我得到“A”。这种行为是 javascript 规范的一部分吗?我可以依赖它吗?
【问题讨论】:
标签: javascript function-pointers
考虑这个 javascript 代码:
var bar = function () { alert("A"); }
var foo = bar;
bar = function () { alert("B"); };
foo();
运行此代码时,我得到“A”。这种行为是 javascript 规范的一部分吗?我可以依赖它吗?
【问题讨论】:
标签: javascript function-pointers
是的,这是预期和设计的。
您的问题基本上是:foo 是否将 bar 引用为另一种语言的指针或引用?
答案是否定的:分配时bar 的值被分配给foo。
【讨论】:
foo = bar 之后, foo 接收到该指针的按值复制,因此 foo 和 bar 都指向独立函数对象。
这是将变量分配给未命名的函数,而不是指向函数的指针
【讨论】:
是的,您已经创建了指向原始“A”函数的指针。当您重新分配 bar 时,您正在重新分配它,但您仍然会单独留下对旧函数的任何引用。
所以要回答您的问题,是的,您可以信赖它。
【讨论】:
是的,变量引用函数这一事实没有什么特别之处,不涉及别名。
var bar = 1;
var foo = bar;
bar = "something entirely different";
// foo is still 1
【讨论】:
是的,这是正确的行为。
//create variable bar and assign a function to it
var bar = function () { alert("A"); }
//assign value of bar to the newly created variable foo
var foo = bar;
//assign a new function to the variable bar
//since foo and bar are not pointers, value of foo doesn't change
bar = function () { alert("B"); };
//call the function stored in foo
foo();
【讨论】:
那些不是函数指针(JS 本身没有指针)。 JS 中的函数可以是匿名的,并且是第一类对象。因此
function () { alert("A"); }
创建一个匿名函数,在执行时提醒“A”;
var bar = function () { alert("A"); };
将该函数分配给 bar;
var foo = bar;
将 foo 赋给 bar,即函数“A”。
bar = function () { alert("B"); };
将 bar 重新绑定到匿名函数“B”。这不会影响 foo 或其他函数“A”。
foo();
调用存储在foo中的函数,也就是函数“A”。
实际上在有功能点的语言中,例如C 它也不会影响foo。我不知道你从哪里得到重新分配“B”的想法。
void A(void) { printf("A\n"); }
void B(void) { printf("B\n"); }
typedef void(*fptr_t)(void);
fptr_t foo = A;
fptr_t bar = foo;
bar = B;
foo(); // should print "A"
【讨论】:
您将匿名函数的值分配给变量而不是指针。
如果你想玩指针,你可以使用通过引用传递的对象,而不是复制。
这里有一些例子:
“obj2”是“obj1”的引用,你改变“obj2”,“obj1”就改变了。它会提醒false:
var obj1 = {prop:true},
obj2 = obj1;
obj2.prop = false;
alert(obj1.prop);
“prop”指向一个不是对象的属性,“prop”不是指向这个对象的指针而是一个副本。如果更改“prop”,则“obj1”不会更改。它会提醒true:
var obj1 = {prop:true},
prop = obj1.prop;
prop = false;
alert(obj1.prop);
“obj2”是对“obj1”的“subObj”属性的引用。如果“obj2”改变了,“obj1”就改变了。它会提醒false:
var obj1 = {subObj:{prop:true}},
obj2 = obj1.subObj;
obj2.prop = false;
alert(obj1.subObj.prop);
【讨论】:
我在这里有点晚了,但我想我还是会给出答案并充实一些东西。
在处理规范时,在讨论 JavaScript(或 ECMAScript)的内部时,最好不要考虑指针和内存引用。变量是内部环境记录,按名称而不是内存地址存储和引用。您的赋值语句在内部和设计上所做的是查找环境记录名称(“foo”或“bar”)并将值分配给该记录。
所以,
var bar = function () { alert("A"); }
正在为环境记录“bar”赋值(匿名函数)。
var foo = bar;
在内部调用 GetValue("bar"),它检索与记录“bar”相关联的值,然后将该值与记录“foo”相关联。因此,之后 bar 的原始值仍然可以使用,因为它现在与 foo 相关联。
因为 JavaScript 通过字符串而不是内存地址引用正是您可以这样做的原因:
someObject["someProperty"]
根据属性名查找值。
【讨论】:
在其他示例中,没有按值传递;一切都是通过引用传递的。
bar 和 foo 都是指针
javascript 中所有非原始对象的变量/句柄都是指针;指针是 JavaScript 原生的,它们是默认的。
var bar = function () { alert("A"); } //bar is a pointer to function1
var foo = bar; //pointer copied; foo is now also a pointer to function1
bar = function () { alert("B"); }; //bar points to function2
foo(); //foo is still a pointer to function1
如果您认为它们是复制品,您将遇到隐藏的错误和错误。如果您使用复杂的对象,尤其如此。例如
function person(name){this.name = name}
var john = new person("john")
var backup = john
backup.name //john
john.name = "jack"
backup.name //jack, NOT john
要真正在 javascript 中复制非原始元素,需要的工作不仅仅是 a = b。 例如:
function person(name){ this.name = name}
var john = new person("john")
var backup = new Object()
backup = JSON.parse(JSON.stringify(john))
backup.__proto__ = john.__proto__ //useful in some cases
john.name = "jack"
backup.name //john
【讨论】:
我想补充一点,这也适用于预定义的命名函数:
function myfunc() { alert("A"); }
var bar = myfunc;
var foo = bar;
bar = function () { alert("B"); };
foo();
这将做同样的事情,表明函数名称的行为类似于数组名称(指针)。
【讨论】:
对于代码中的每个 FunctionDeclaration f,按源文本顺序执行:
令 fn 为 FunctionDeclaration f 中的标识符。
令 fo 为实例化 FunctionDeclaration f 的结果,如第 13 条所述。
设 funcAlreadyDeclared 为调用 env 的 HasBinding 具体方法并传递 fn 作为参数的结果。
如果 funcAlreadyDeclared 为 false,则调用 env 的 CreateMutableBinding 具体方法,将 fn 和 configureBindings 作为参数。
参考文献
【讨论】: