考虑这个javascript代码:
var bar = function () { alert("A"); }
var foo = bar;
bar = function () { alert("B"); };
foo();
运行此代码时,我得到“A”。这种行为是javascript规范的一部分吗?我可以依赖它吗?
答案 0 :(得分:62)
在其他示例中,没有任何值按值传递;一切都通过参考传递。
bar和foo是两个指针
javascript中NON原始对象的所有变量/句柄都是指针;指针是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
答案 1 :(得分:37)
是的,这是预期的和设计的。
您的问题基本上是:foo
引用bar
作为指针或引用会用另一种语言吗?
答案是否定的:分配时bar
的值已分配给foo
。
答案 2 :(得分:19)
我在这里有点迟了但是我觉得无论如何我都会给出一个答案并且有点出色。
在处理规范时讨论JavaScript(或ECMAScript)的内部时,最好不要考虑指针和内存引用。变量是内部的环境记录,由名称而不是内存地址存储和引用。您的赋值语句在内部和设计上正在查找环境记录名称(“foo”或“bar”)并将值分配给该记录。
所以,
var bar = function () { alert("A"); }
正在为环境记录“bar”分配值(匿名函数)。
var foo = bar;
内部调用GetValue(“bar”),它检索与记录“bar”关联的值,然后将该值与记录“foo”相关联。因此,之后bar的原始值仍然可以使用,因为它现在与foo相关联。
因为JavaScript引用字符串而不是内存地址正是为什么你可以这样做的原因:
someObject["someProperty"]
根据属性名称查找值。
答案 3 :(得分:5)
是的,变量指的是函数没有什么特别之处,没有涉及别名。
var bar = 1;
var foo = bar;
bar = "something entirely different";
// foo is still 1
答案 4 :(得分:5)
您正在将匿名函数的值赋给变量而不是指针 如果要使用指针,可以使用通过引用传递的对象,而不是复制。
以下是一些例子:
“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);
答案 5 :(得分:3)
是的,这是正确的行为。
//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();
答案 6 :(得分:2)
这些不是函数指针(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"
答案 7 :(得分:1)
这是为未命名的函数赋值变量,而不是指向函数的指针
答案 8 :(得分:1)
是的,您已经创建了一个指向原始“A”功能的指针。当您重新分配bar时,您重新分配它,但您仍然只留下对旧功能的任何引用。
所以回答你的问题,是的,你可以依靠它。
答案 9 :(得分:0)
我想添加它也适用于预定义的命名函数:
function myfunc() { alert("A"); }
var bar = myfunc;
var foo = bar;
bar = function () { alert("B"); };
foo();
这将做同样的事情,表明函数名称就像数组名(指针)。
答案 10 :(得分:0)
对于代码中的每个FunctionDeclaration f,在源文本顺序中执行:
让fn成为FunctionDeclaration f。
中的标识符设fo是如第13章所述实例化FunctionDeclaration f的结果。
让funcAlreadyDeclared成为调用env的HasBinding具体方法传递fn作为参数的结果。
如果funcAlreadyDeclared为false,则调用env的CreateMutableBinding具体方法,将fn和configurableBindings作为参数传递。
<强>参考强>