Самое простое решение - создать функцию JavaScript и вызвать его для обратного вызова Ajax success
.
function callServerAsync(){
$.ajax({
url: '...',
success: function(response) {
successCallback(response);
}
});
}
function successCallback(responseObj){
// Do something like read the response and show data
alert(JSON.stringify(responseObj)); // Only applicable to JSON response
}
function foo(callback) {
$.ajax({
url: '...',
success: function(response) {
return callback(null, response);
}
});
}
var result = foo(function(err, result){
if (!err)
console.log(result);
});
Согласно спецификациям ECMA Script 5 ,
Значение свойства
blockquote>prototype
используется для инициализации внутреннего свойства[[Prototype]]
для вновь созданного объекта перед тем как объект Function вызывается как конструктор для этого вновь созданного объекта.Понятно, что
prototype
просто инициализирует свойство[[Prototype]]
. Когда мы создаем объект,[[Prototype]]
устанавливается как объектprototype
функции конструктора и устанавливается цепочка прототипов. В вашем случае, когда вы делаетеvar obj = function() {}; obj.prototype.x = 5; var instance1 = new obj();
,
[[Prototype]]
выглядит такconsole.log(Object.getPrototypeOf(instance1)); # { x: 5 }
(Да, вы можете получить доступ к
[[Prototype]]
с помощьюObject.getPrototypeOf
]Итак, когда JS Engine ищет
x
вinstance1
, он находит значение как5
, а посколькуy
не определен, он используетundefined
.Во втором случае
obj.prototype = {y: 6}; var instance2 = new obj();
вы меняете объект
prototype
объектаobj
, так что новые объекты, построенные с помощью этих функций, будут использовать новый объект, назначенный ему. Таким образом,[[Prototype]]
выглядит так:instance2
console.log(Object.getPrototypeOf(instance2)); # { y: 6 }
Вот почему
< hr>instance2
не смог найти в немx
, ноy
.Чтобы ответить на обновленный вопрос,
EDIT: Как я могу изменить прототип всех экземпляров?
blockquote>Вы можете изменить , прототип старого объекта с
Object.setPrototypeOf
, как этоObject.setPrototypeOf(instance1, { y: 6 });
Так как это
[[Prototype]]
instance1
отличается отinstance2
, мы можем просто обновить функцию конструктораprototype
, напримерdelete obj.prototype.x; obj.prototype.y = 6;
Теперь мы не изменили внутреннего свойства как
instance1
, так иinstance2
. Мы можем проверить, что такconsole.log(Object.getPrototypeOf(instance1) === Object.getPrototypeOf(instance2)); # true console.log(Object.getPrototypeOf(instance1) === obj.prototype); # true
Примечание: Соглашение должно называть функции-конструкторы с начальной буквой заглавной буквой.
Поскольку instance1
уже создан. Ключевое слово new
создает новый объект, выполняя функцию-конструктор, которая в вашем случае obj
.
Поскольку вы изменили прототип после инициализации первого экземпляра, вы больше не имеете того же состояния (например, прототип) конструктора и не можете создать тот же объект. Но созданные все еще существуют, ссылаясь на старый прототип.
Когда вы снова используете конструктор obj
, вы создаете еще один объект, который может быть очень грубо переведен в классический тип терминологии наследования как экземпляр другого класса.
Изменить: # 4 Эта скрипка: http://jsfiddle.net/doy3g1fh/ показывает, что
obj.prototype.y=6
преуспевает в изменении все существующие объекты. Таким образом, ответ, очевидно, заключается в том, что вы не должны назначать новый объект в качестве прототипа, а просто модифицировать текущий прототип.
Прототип экземпляров не ссылается на класс, вместо этого они ссылаются на сам объект-прототип. Это станет ясным, когда вы попробуете Object.getPrototypeOf()
, чтобы увидеть, какой прототип-объект ссылается на экземпляр.
Object.getPrototypeOf(instance1)
Object { x: 5, 1 more… }
Object.getPrototypeOf(instance2)
Object { y: 6 }
Это поле getPrototypeOf
ссылки должно быть внутренним, которое существует для каждого экземпляра. До getPrototypeOf
существовало, вы можете получить это через __proto__
.
blockquote>
- Почему этот журнал
5
,undefined
,undefined
,6
вместоundefined
,6
,undefined
,6
?- Почему замена прототипа не меняет прототип всех экземпляров объекта, как это обычно бывает?
По сути, это сводится к тому, что ссылки на объекты - это значения, а скорее числа, которые указывают механизм JavaScript (V8 в вашем случае), где объект находится в памяти. Когда вы копируете значение, вы делаете именно это: вы копируете значение. Копирование ссылки на объект делает копию ссылки (а не объекта) и никоим образом не связывает место назначения этого значения с источником значения больше, чем это связывает
b
сa
:var a = 5; var b = a; a = 6; console.log(b, a); // 5, 6
Итак, ваш код регистрирует то, что он регистрирует, и не изменяет прототип
instance1
, по той же причине этот код записывает то же самое и не меняет значениеinstance1.p
:
var foo = {x: 5}; var instance1 = {p: foo}; foo = {y: 6}; var instance2 = {p: foo}; console.log(instance1.p.x, instance1.p.y, instance2.p.x, instance2.p.y);
Давайте набросим на него некоторое ASCII-искусство (ну, Unicode-art), которое также ответит:
blockquote>
- Что делает двигатель V8, шаг за шагом, в этом коде?
После запуска этого:
var obj = function() {}; obj.prototype.x = 5; var instance1 = new obj();
... у вас есть что-то примерно так в памяти (игнорируя некоторые детали):
+−−−−−−−−−−−−−−−−−−−−−+ | (function) | +−−−−−−−−−−−−−−−−−−−−−+ obj<Ref55461>−−−>| prototype<Ref32156> |−−−−−−−−−−−+ +−−−−−−−−−−−−−−−−−−−−−+ \ \ \ \ +−−−−−−−−−−+ +−>| (object) | / +−−−−−−−−−−+ / | x<5> | +−−−−−−−−−−−−−−−−−−−−−−−−−+ / +−−−−−−−−−−+ | (object) | / +−−−−−−−−−−−−−−−−−−−−−−−−−+ / instance1<Ref86545>−−>| [[Prototype]]<Ref32156> |−+ +−−−−−−−−−−−−−−−−−−−−−−−−−+Поскольку ссылки на объекты являются значениями, а присваивание всегда копирует значения , когда V8 (или любой другой движок) создает
instance1
, он копирует значение изobj.prototype
(показано здесь концептуально как<Ref32156>
) на внутренний слотinstance1
[[Prototype]]
.Тогда, когда вы делаете
obj.prototype = {y: 6};
... вы меняете значение в
obj.prototype
(показано здесь как изменение<Ref32156>
на<Ref77458>
), но это не влияет на значение (<Ref32156>
]) в слотеinstance1
[[Prototype]]
:+−−−−−−−−−−−−−−−−−−−−−+ | (function) | +−−−−−−−−−−−−−−−−−−−−−+ +−−−−−−−−−−+ obj<Ref55461>−−−>| prototype<Ref77458> |−−−−−−−−−−−−−−−−−−>| (object) | +−−−−−−−−−−−−−−−−−−−−−+ +−−−−−−−−−−+ | y<6> | +−−−−−−−−−−+ +−−−−−−−−−−+ +−>| (object) | / +−−−−−−−−−−+ / | x<5> | +−−−−−−−−−−−−−−−−−−−−−−−−−+ / +−−−−−−−−−−+ | (object) | / +−−−−−−−−−−−−−−−−−−−−−−−−−+ / instance1<Ref86545>−−>| [[Prototype]]<Ref32156> |−+ +−−−−−−−−−−−−−−−−−−−−−−−−−+... и поэтому, когда вы делаете
var instance2 = new obj();
... у вас есть:
+−−−−−−−−−−−−−−−−−−−−−+ | (function) | +−−−−−−−−−−−−−−−−−−−−−+ +−−−−−−−−−−+ obj<Ref55461>−−−>| prototype<Ref77458> |−−−−−−−−−−−−−−−−+−>| (object) | +−−−−−−−−−−−−−−−−−−−−−+ / +−−−−−−−−−−+ / | y<6> | +−−−−−−−−−−−−−−−−−−−−−−−−−+ / +−−−−−−−−−−+ | (object) | / +−−−−−−−−−−−−−−−−−−−−−−−−−+ / instance2<Ref98465>−−>| [[Prototype]]<Ref77458> |−+ +−−−−−−−−−−+ +−−−−−−−−−−−−−−−−−−−−−−−−−+ +−>| (object) | / +−−−−−−−−−−+ / | x<5> | +−−−−−−−−−−−−−−−−−−−−−−−−−+ / +−−−−−−−−−−+ | (object) | / +−−−−−−−−−−−−−−−−−−−−−−−−−+ / instance1<Ref86545>−−>| [[Prototype]]<Ref32156> |−+ +−−−−−−−−−−−−−−−−−−−−−−−−−+... что объясняет результат
console.log
.blockquote>
- EDIT: Как мне пойти на смену прототипа всех экземпляров?
Если вы хотите фактически изменить какой объект, который они используют в качестве своего прототипа, вы можете сделать это только в том случае, если у вас есть ссылка на экземпляр (ы), который вы хотите изменить, и только на JavaScript-движке, поддерживающем функции ES2015, с помощью
Object.setPrototypeOf
или (в среде веб-браузера, и если объект в конечном итоге наследуется отObject.prototype
) через аксессуар__proto__
свойство (не рекомендуется):Object.setPrototypeOf(instance1, obj.prototype);
setPrototypeOf
изменяет значение внутреннего слота[[Prototype]]
в объекте (как и установка__proto__
, если объект имеет его) .Вы не можете этого сделать, если у вас нет ac
Я не думаю, что вы это делаете, учитывая этот вопрос, но если вы просто хотите изменить состояние объекта, который они используют в качестве своего прототипа (возможно, добавив
y
), вы можете, конечно, просто установить на нем свойства, а так как прототипное наследование JavaScript является «живым» (есть прямая ссылка на прототип из экземпляра), вы можете затем получить доступ к этим свойствам в любом экземпляре, который наследуется от прототипа, даже если они были созданы до того, как вы внесли изменение:var Example = function() { }; Example.prototype.x = 5; var instance1 = new Example(); console.log(instance1.x, instance1.y); // 5, undefined Example.prototype.y = 6; console.log(instance1.x, instance1.y); // 5, 6
- это функция, которая сочетается с новыми за кулисами. Он применяется ко всем экземплярам этой функции, используемой с новым. В первом примере вы добавляете .x = 5 к прототипу, а созданный экземпляр имеет значение .x = 5 в качестве значения. Позже вы модифицируете прототип для нового объекта. Теперь это прототип, который используется в любых новых экземплярах. Вот почему первый экземпляр имеет .x = 5, а второй имеет только .y = 6
Объяснение
Итак, во-первых, ваши две строки кода создают функцию obj
и назначают ее прототипу {x: 5}
.
Когда вы создаете экземпляр этого объект, он, по-видимому, имеет внутреннюю ссылку на прототип, который существовал, когда он был new
'd.
. После этого вы переназначите прототип на {y: 6}
, который не влияет на внутренний instance1
ссылка на первый прототип.
Затем, когда вы создаете instance2
, он имеет внутреннюю ссылку на 2-й прототип, и поэтому запись в них приведет к 5, undefined, undefined, 6
.
# 4
Вы могли бы вместо переназначения прототипа новому объекту:
obj.prototype = {y: 6};
Изменить вместо этого прототип:
delete obj.prototype.x; // Setting to undefined should produce same behaviour
obj.prototype.y = 6;
Это приведет к выходу: undefined, 6, undefined, 6
Я тестировал это с помощью http://jsfiddle.net/9j3260gp/ в последних версиях Chrome и Firefox в Windows.