Технически вы можете использовать столько отдельных соединений, сколько хотите, в то время как ваша проблема вызвана простой опечаткой - вы не можете использовать ресурсы только из одного расширения с функциями из другого, что вполне очевидно.
Однако вам следует избегать нескольких подключений от одного и того же сценария, независимо от одного API или другого. Поскольку это будет обременять ваш сервер базы данных и исчерпывать его ресурсы. Итак, хотя технически вы можете, вы не должны смешивать разные расширения в своем коде, за исключением короткого периода рефакторинга.
В следующем я предполагаю, что вас интересует только то, почему Object.create
является предпочтительным для настройки наследования.
Чтобы понять преимущества, давайте сначала проясним, что такое «класс» в JavaScript. У вас есть две части:
Наследование устанавливает отношение is-a , например, Dog
- a Animal
. Как это выражается в терминах функции-конструктора и объекта-прототипа?
Очевидно, что собака должна иметь те же методы, что и животное, то есть объект Dog
prototype должен каким-то образом включать методы из прототипа Animal
. Существует несколько способов сделать это. Вы часто увидите это:
Dog.prototype = new Animal();
Это работает, потому что экземпляр Animal
наследуется от объекта Animal
прототипа . Но это также означает, что каждая собака наследует от один специфический экземпляр Animal
. Кажется, это немного странно. Может ли конкретный код экземпляра запускаться только в функции конструктора ? Внезапно экземпляр специфический код и прототип методы кажутся смешанными.
Мы фактически не хотим запускать экземпляр Animal
в этот момент, нам нужны только все методы из объекта Animal
prototype . Это позволяет нам Object.create
:
Dog.prototype = Object.create(Animal.prototype);
Здесь мы , а не , создаем новый экземпляр Animal
, получаем только прототипы. Конкретный код экземпляра экземпляра выполняется точно там, где он должен быть, внутри конструктора:
function Dog() {
Animal.call(this, 'Dog');
}
Самое большое преимущество заключается в том, что Object.create
всегда будет Работа. Использование new Animal()
работает только в том случае, если конструктор не ожидает никаких аргументов. Представьте, если конструктор выглядел так:
function Animal(name) {
this.name = name.toLowerCase();
}
Вам всегда нужно передать строку в Animal
, иначе вы получите сообщение об ошибке. Что вы пройдете, когда будете делать Dog.prototype = new Animal(??);
? На самом деле не имеет значения, какую строку вы передаете, если передать что-то , которое, надеюсь, покажет вам, что это плохой дизайн.
Некоторые говорят, что
blockquote>Dog.prototype = Animal.prototype;
также может работать. Итак, теперь я полностью смущенВсе, что «добавляет» свойства от
Animal.prototype
доDog.prototype
, «будет работать». Но решения имеют разное качество. В этом случае у вас будет проблема, что любой метод, который вы добавите вDog.prototype
, также будет добавлен вAnimal.prototype
.Пример:
Dog.prototype.bark = function() { alert('bark'); };
Поскольку
Dog.prototype === Animal.prototype
, все экземплярыAnimal
теперь имеют методbark
, что, конечно же, не то, что вы хотите.< hr>
Object.create
(и дажеnew Animal
) добавляют один уровень косвенности к наследованию, создавая новый объект, который наследует отAnimal.prototype
, и этот новый объект становитсяDog.prototype
.Наследование в ES6
ES6 вводит новый синтаксис для создания функций-конструкторов и методов прототипа, который выглядит следующим образом:
class Dog extends Animal { bark() { alert('bark'); } }
Это более удобно, чем то, что я объясняется выше, но, как оказалось,
extends
также использует внутренний эквивалентObject.create
для настройки наследования. См. Шаги 2 и 3 в черновике ES6 . Это означает, что использованиеObject.create(SuperClass.prototype)
является «более правильным» подходом в ES5.
Давайте будем понимать это только с кодом;
A.prototype = B.prototype;
function B() {console.log("I am B");this.b1= 30;}
B.prototype.b2 = 40;
function A() {console.log("I am A");this.a1= 10;}
A.prototype.a2 = 20;
A.prototype = B.prototype;
A.prototype.constructor = A;
var a = new A;
var b = new B;
console.log(a);//A {a1: 10, b2: 40}
console.log(b);//B {b1: 30, b2: 40}
console.log(A.prototype.constructor);//A
console.log(B.prototype.constructor);//A
console.log(A.prototype);//A {b2: 40}
console.log(B.prototype);//A {b2: 40}
console.log(a.constructor === A); //true
console.log(b.constructor === A); //true
console.log(a.a2);//undefined
[/g0]
A .prototype = Object.create (B.prototype);
function B() {console.log("I am B");this.b1= 30;}
B.prototype.b2 = 40;
function A() {console.log("I am A");this.a1= 10;}
A.prototype.a2 = 20;
A.prototype = Object.create(B.prototype);
A.prototype.constructor = A;
var a = new A;
var b = new B;
console.log(a);//A {a1: 10, constructor: function, b2: 40}
console.log(b);//B {b1: 30, b2: 40}
console.log(A.prototype.constructor);//A
console.log(B.prototype.constructor);//B
console.log(A.prototype);//A {constructor: function, b2: 40}
console.log(B.prototype);//B {b2: 40}
console.log(a.constructor === A); //true
console.log(b.constructor === B); //true
console.log(a.a2);//undefined
[/g1]
Я немного проиллюстрирую разницу:
Вот что в основном происходит, когда вы пишете new Animal()
:
//creating a new object
var res = {};
//setting the internal [[prototype]] property to the prototype of Animal
if (typeof Animal.prototype === "object" && Animal.prototype !== null) {
res.__proto__ = Animal.prototype;
}
//calling Animal with the new created object as this
var ret = Animal.apply(res, arguments);
//returning the result of the Animal call if it is an object
if (typeof ret === "object" && ret !== null) {
return ret;
}
//otherise return the new created object
return res;
И вот что в принципе происходит с Object.create
:
//creating a new object
var res = {};
//setting the internal [[prototype]] property to the prototype of Animal
if (typeof Animal.prototype !== "object") {
throw "....";
}
res.__proto__ = Animal.prototype;
//return the new created object
return res;
Таким образом, он делает то же самое, но не вызывает функцию Animal
, а также всегда возвращает новый созданный объект. В вашем случае вы получаете два разных объекта. С помощью первого метода вы получите:
Dog.prototype = {
name: undefined,
__proto__: Animal.prototype
};
и со вторым методом:
Dog.prototype = {
__proto__: Animal.prototype
};
Вам действительно не нужно иметь свойство name
в вашем прототип, потому что вы уже назначили его вашему экземпляру Dog
с помощью Animal.call(this, 'Dog');
.
Ваша основная цель - предоставить вашему экземпляру Dog
доступ ко всем свойствам прототипа Animal
, который достигается с помощью обоих методов. Первый способ, однако, делает некоторые дополнительные вещи, которые на самом деле не нужны в вашем случае, или даже могут вызывать нежелательные результаты, о которых упоминал Pumbaa80.
Во-первых, запуск конструктора Animal
может иметь нежелательные побочные эффекты. Рассмотрим это:
var Animal = function(name) {
this.name = name;
Animal.instances.push(this);
};
Animal.instances = [];
Эта версия будет отслеживать все созданные экземпляры. Вы не хотите, чтобы ваш Dog.prototype
был записан там.
Во-вторых, Dog.prototype = Animal.prototype
- плохая идея, поскольку это означало бы, что bark
станет методом Animal
.
new Animal()
, но с параметрами, это выглядело бы какnew Animal({ species: 'dog', sound: 'bark' })
. С этим, однако, если вы не используете jQuery, вам нужно создать собственную функцию расширения. – Banning 6 March 2016 в 21:56