Назначение указателя функции Javascript - PullRequest
47 голосов
/ 24 февраля 2010

Рассмотрим этот код JavaScript:

var bar = function () { alert("A"); }
var foo = bar;
bar = function () { alert("B"); };
foo();

При запуске этого кода я получаю "A". Является ли это поведение частью спецификации javascript и могу ли я положиться на него?

Ответы [ 11 ]

62 голосов
/ 22 июля 2012

В других примерах ничего не передавалось по значению; все было передано по ссылке.

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
37 голосов
/ 24 февраля 2010

Да, что ожидается и по замыслу.

Ваш вопрос в основном: foo ссылается на bar как указатель или ссылка на другом языке?

Ответ - нет: значение из bar на момент назначения присваивается foo.

19 голосов
/ 24 февраля 2010

Я немного опоздал, но я все равно решил дать ответ и кое-что прояснить.

Лучше не думать в терминах указателей и ссылок на память при обсуждении внутренних частей JavaScript (или ECMAScript) при работе со спецификациями. Переменные являются внутренними записями среды и хранятся по имени, а не по адресу памяти. То, что делает ваш оператор присваивания, внутренне и по замыслу, ищет имя записи среды («foo» или «bar») и присваивает значение этой записи.

Итак,

var bar = function () { alert("A"); }

присваивает записи среды «бар» значение (анонимная функция).

var foo = bar;

внутренне вызывает GetValue ("bar"), который получает значение, связанное с записью "bar", а затем связывает это значение с записью "foo". Следовательно, впоследствии исходное значение bar все еще может использоваться, поскольку теперь оно связано с foo.

Поскольку ссылки JavaScript по строке, а не по адресу памяти, именно поэтому вы можете делать такие вещи:

someObject["someProperty"]

, который ищет значение на основе имени свойства.

5 голосов
/ 24 февраля 2010

Вы присваиваете значение анонимной функции переменной, а не указателю.
Если вы хотите поиграть с указателями, вы можете использовать объекты, которые передаются по ссылке, а не при копировании.

Вот несколько примеров:

«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" является ссылкой на свойство "subObj" объекта "obj1". если «obj2» изменяется, «obj1» изменяется. Это предупредит false.

var obj1 = {subObj:{prop:true}},
    obj2 = obj1.subObj;
obj2.prop = false;
alert(obj1.subObj.prop);
5 голосов
/ 24 февраля 2010

Да, нет ничего особенного в том, что переменные ссылаются на функции, здесь нет псевдонимов.

var bar = 1;
var foo = bar;
bar = "something entirely different";
// foo is still 1
3 голосов
/ 24 февраля 2010

Да, это правильное поведение.

//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();
2 голосов
/ 24 февраля 2010

Это не указатели на функции (и в JS нет указателей изначально). Функции в JS могут быть анонимными и являются объектами первого класса. Следовательно

function () { alert("A"); }

создает анонимную функцию, которая предупреждает «A» при выполнении;

var bar = function () { alert("A"); };

назначить эту функцию на бар;

var foo = bar;

назначить foo для bar, который является функцией "A".

bar = function () { alert("B"); };

привязка бара к анонимной функции "B". Это не повлияет на foo или другую функцию «A».

foo();

Вызовите функцию, хранящуюся в foo, которая является функцией «A».


На самом деле на языках, где есть функциональные точки, например, С это тоже не повлияет 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"
1 голос
/ 24 февраля 2010

Да, вы создали указатель на оригинальную функцию «А». Когда вы переназначаете bar, вы переназначаете ее , но все равно оставляете любые ссылки на старую функцию в одиночку.

Так что, чтобы ответить на ваш вопрос, да, вы можете положиться на него.

1 голос
/ 24 февраля 2010

Это присвоение переменной неназванной функции, а не указатель на функцию

0 голосов
/ 27 марта 2014

Для каждого FunctionDeclaration, найденного в коде, в исходном текстовом порядке выполните:

Пусть fn будет идентификатором в FunctionDeclaration f.

Пусть fo будет результатом создания FunctionDeclaration f, как описано в разделе 13.

Пусть funcAlreadyDeclared будет результатом вызова конкретного метода enB HasBinding с передачей fn в качестве аргумента.

Если funcAlreadyDeclared имеет значение false, вызовите конкретный метод env CreateMutableBinding, передав в качестве аргументов fn и configurableBindings.

Ссылки

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...