Что такое «новое» ключевое слово в JavaScript?
-
22-07-2019 - |
Вопрос
А new
Ключевое слово в JavaScript может сбить с толку, когда оно впервые встречается, поскольку люди склонны думать, что JavaScript не является объектно-ориентированным языком программирования.
- Что это такое?
- Какие проблемы он решает?
- Когда это уместно, а когда нет?
Решение
Он делает 5 вещей:
- Он создает новый объект.Тип этого объекта просто объект.
- Он устанавливает внутреннюю, недоступную, [[опытный образец]] (т.е. __прото__) свойство быть внешним, доступным, опытный образец объект (каждый функциональный объект автоматически имеет опытный образец свойство).
- Это делает
this
переменная указывает на вновь созданный объект. - Он выполняет функцию конструктора, используя вновь созданный объект всякий раз, когда
this
упомянуто. - Она возвращает вновь созданный объект, если только функция-конструктор не возвращает не-
null
ссылка на объект.В этом случае вместо этого возвращается ссылка на этот объект.
Примечание: функция-конструктор относится к функции после new
ключевое слово, как в
new ConstructorFunction(arg1, arg2)
Как только это будет сделано, если будет запрошено неопределенное свойство нового объекта, скрипт проверит свойство объекта. [[опытный образец]] вместо этого объект для собственности.Вот как вы можете получить что-то похожее на традиционное наследование классов в JavaScript.
Самое сложное в этом — пункт номер 2.Каждый объект (включая функции) имеет внутреннее свойство, называемое [[опытный образец]].Он может только быть установлен во время создания объекта, либо с помощью новый, с Object.create, или на основе литерала (функции по умолчанию — Function.prototype, числа — Number.prototype и т. д.).Его можно прочитать только с помощью Object.getPrototypeOf(someObject).Есть нет другой способ установить или прочитать это значение.
Функции, помимо скрытых [[опытный образец]] собственность, также есть свойство под названием опытный образец, и именно к нему вы можете получить доступ и изменить его, чтобы предоставить унаследованные свойства и методы для создаваемых вами объектов.
Вот пример:
ObjMaker = function() {this.a = 'first';};
// ObjMaker is just a function, there's nothing special about it that makes
// it a constructor.
ObjMaker.prototype.b = 'second';
// like all functions, ObjMaker has an accessible prototype property that
// we can alter. I just added a property called 'b' to it. Like
// all objects, ObjMaker also has an inaccessible [[prototype]] property
// that we can't do anything with
obj1 = new ObjMaker();
// 3 things just happened.
// A new, empty object was created called obj1. At first obj1 was the same
// as {}. The [[prototype]] property of obj1 was then set to the current
// object value of the ObjMaker.prototype (if ObjMaker.prototype is later
// assigned a new object value, obj1's [[prototype]] will not change, but you
// can alter the properties of ObjMaker.prototype to add to both the
// prototype and [[prototype]]). The ObjMaker function was executed, with
// obj1 in place of this... so obj1.a was set to 'first'.
obj1.a;
// returns 'first'
obj1.b;
// obj1 doesn't have a property called 'b', so JavaScript checks
// its [[prototype]]. Its [[prototype]] is the same as ObjMaker.prototype
// ObjMaker.prototype has a property called 'b' with value 'second'
// returns 'second'
Это похоже на наследование классов, потому что теперь любые объекты, которые вы создаете с помощью new ObjMaker()
также окажется, что он унаследовал свойство «b».
Если вам нужно что-то вроде подкласса, сделайте следующее:
SubObjMaker = function () {};
SubObjMaker.prototype = new ObjMaker(); // note: this pattern is deprecated!
// Because we used 'new', the [[prototype]] property of SubObjMaker.prototype
// is now set to the object value of ObjMaker.prototype.
// The modern way to do this is with Object.create(), which was added in ECMAScript 5:
// SubObjMaker.prototype = Object.create(ObjMaker.prototype);
SubObjMaker.prototype.c = 'third';
obj2 = new SubObjMaker();
// [[prototype]] property of obj2 is now set to SubObjMaker.prototype
// Remember that the [[prototype]] property of SubObjMaker.prototype
// is ObjMaker.prototype. So now obj2 has a prototype chain!
// obj2 ---> SubObjMaker.prototype ---> ObjMaker.prototype
obj2.c;
// returns 'third', from SubObjMaker.prototype
obj2.b;
// returns 'second', from ObjMaker.prototype
obj2.a;
// returns 'first', from SubObjMaker.prototype, because SubObjMaker.prototype
// was created with the ObjMaker function, which assigned a for us
Я прочитал кучу всякой ерунды на эту тему, прежде чем наконец нашел эта страница, где это очень хорошо объяснено с красивыми диаграммами.
Другие советы
Предположим, у вас есть эта функция:
var Foo = function(){
this.A = 1;
this.B = 2;
};
Если вы вызовете это как отдельную функцию, например:
Foo();
Выполнение этой функции добавит два свойства в window
объект (A
и B
).Он добавляет его в window
потому что window
это объект, который вызвал функцию, когда вы выполняете ее таким образом, и this
в функции — это объект, вызвавший функцию.По крайней мере, в Javascript.
Теперь назовите это так с помощью new
:
var bar = new Foo();
Что произойдет, если вы добавите new
вызову функции заключается в том, что создается новый объект (просто var bar = new Object()
) и что this
внутри функции указывает на новый Object
вы только что создали, а не к объекту, вызвавшему функцию.Так bar
теперь является объектом со свойствами A
и B
.Конструктором может быть любая функция, просто это не всегда имеет смысл.
В дополнение к ответу Дэниела Ховарда, вот что new
делает (или, по крайней мере, кажется, делает):
function New(func) {
var res = {};
if (func.prototype !== null) {
res.__proto__ = func.prototype;
}
var ret = func.apply(res, Array.prototype.slice.call(arguments, 1));
if ((typeof ret === "object" || typeof ret === "function") && ret !== null) {
return ret;
}
return res;
}
Пока
var obj = New(A, 1, 2);
эквивалентно
var obj = new A(1, 2);
Для новичков, чтобы лучше понять это
попробуйте следующий код в консоли браузера.
function Foo() {
return this;
}
var a = Foo(); //returns window object
var b = new Foo(); //returns empty object of foo
a instanceof Window; // true
a instanceof Foo; // false
b instanceof Window; // false
b instanceof Foo; // true
Теперь вы можете прочитать ответ вики-сообщества :)
Так что, вероятно, не для создания экземпляров объекта
Он используется именно для этого.Вы определяете конструктор функции следующим образом:
function Person(name) {
this.name = name;
}
var john = new Person('John');
Однако дополнительное преимущество ECMAScript заключается в том, что вы можете расширить его с помощью .prototype
собственность, поэтому мы можем сделать что-то вроде...
Person.prototype.getName = function() { return this.name; }
Все объекты, созданные с помощью этого конструктора, теперь будут иметь getName
из-за цепочки прототипов, к которой у них есть доступ.
JavaScript является объектно-ориентированный язык программирования, используемый именно для создания экземпляров.Он основан на прототипах, а не на классах, но это не означает, что он не объектно-ориентирован.
Javascript — это динамический язык программирования, который поддерживает парадигму объектно-ориентированного программирования и используется для создания новых экземпляров объекта.
Классы не обязательны для объектов — Javascript — это на основе прототипа язык.
Уже есть несколько отличных ответов, но я публикую новый, чтобы подчеркнуть свое наблюдение по делу. III ниже о том, что происходит, когда у вас есть явный оператор возврата в функции, которую вы выполняете. new
поднимаюсь.Посмотрите на следующие случаи:
Случай I:
var Foo = function(){
this.A = 1;
this.B = 2;
};
console.log(Foo()); //prints undefined
console.log(window.A); //prints 1
Выше приведен простой случай вызова анонимной функции, на которую указывает Foo
.Когда вы вызываете эту функцию, она возвращает undefined
.Поскольку явного оператора возврата нет, интерпретатор JavaScript принудительно вставляет return undefined;
оператор в конце функции.Здесь окно — это объект вызова (контекстный this
), который становится новым A
и B
характеристики.
Случай II:
var Foo = function(){
this.A = 1;
this.B = 2;
};
var bar = new Foo();
console.log(bar()); //illegal isn't pointing to a function but an object
console.log(bar.A); //prints 1
Здесь интерпретатор JavaScript видит new
Ключевое слово создает новый объект, который действует как объект вызова (контекстный this
) анонимной функции, на которую указывает Foo
.В этом случае A
и B
станут свойствами вновь созданного объекта (вместо объекта окна).Поскольку у вас нет явного оператора возврата, интерпретатор JavaScript принудительно вставляет оператор возврата, чтобы вернуть новый объект, созданный в результате использования new
ключевое слово.
Случай III:
var Foo = function(){
this.A = 1;
this.B = 2;
return {C:20,D:30};
};
var bar = new Foo();
console.log(bar.C);//prints 20
console.log(bar.A); //prints undefined. bar is not pointing to the object which got created due to new keyword.
Здесь интерпретатор JavaScript снова видит new
Ключевое слово создает новый объект, который действует как объект вызова (контекстный this
) анонимной функции, на которую указывает Foo
.Снова, A
и B
станут свойствами вновь созданного объекта.Но на этот раз у вас есть явный оператор возврата, поэтому интерпретатор JavaScript нет сделать что-нибудь свое.
На что обратить внимание на всякий случай III заключается в том, что объект, создаваемый благодаря new
Ключевое слово потерялось с вашего радара. bar
на самом деле указывает на совершенно другой объект, который не является тем, который интерпретатор JavaScript создал из-за new
ключевое слово.
Цитирую Дэвида Фланагана из JavaScripit:Полное руководство (6-е издание), гл.4, страница № 62:
Когда оценивается выражение создания объекта, JavaScript сначала создает новый пустой объект, точно так же, как тот, который создан инициализатором объекта {}.Затем он вызывает указанную функцию с указанными аргументами, передавая новый объект как значение этого ключевого слова.Затем функция может использовать это для инициализации свойств недавно созданного объекта.Функции, написанные для использования в качестве конструкторов, не возвращают значение, а значение выражения создания объекта - это недавно созданный и инициализированный объект.Если конструктор действительно возвращает значение объекта, это значение становится значением выражения создания объекта, а недавно созданный объект отбрасывается.
---Дополнительная информация---
Функции, используемые в приведенном выше фрагменте кода, имеют специальные имена в мире JS, как показано ниже:
Случай I и II - Функция конструктора
Случай III - Заводская функция.Заводские функции не должен использоваться с new
ключевое слово, которое я сделал, чтобы объяснить концепцию в текущей теме.
О разнице между ними вы можете прочитать в этот нить.
иногда код проще слов:
var func1 = function (x) { this.x = x; } // used with 'new' only
var func2 = function (x) { var z={}; z.x = x; return z; } // used both ways
func1.prototype.y = 11;
func2.prototype.y = 12;
A1 = new func1(1); // has A1.x AND A1.y
A2 = func1(1); // undefined ('this' refers to 'window')
B1 = new func2(2); // has B1.x ONLY
B2 = func2(2); // has B2.x ONLY
Что касается меня, пока я не создаю прототип, я использую стиль func2, поскольку он дает мне немного больше гибкости внутри и снаружи функции.
А new
Ключевое слово изменяет контекст, в котором запускается функция, и возвращает указатель на этот контекст.
Когда вы не используете new
ключевое слово, контекст, в котором функция Vehicle()
работает тот же контекст, из которого вы вызываете Vehicle
функция.А this
Ключевое слово будет относиться к тому же контексту.Когда вы используете new Vehicle()
, создается новый контекст, поэтому ключевое слово this
внутри функции относится к новому контексту.Взамен вы получаете вновь созданный контекст.
А new
Ключевое слово предназначено для создания новых экземпляров объектов.И да, javascript — это динамический язык программирования, поддерживающий парадигму объектно-ориентированного программирования.Соглашение об именовании объектов таково: всегда используйте заглавную букву для объектов, экземпляры которых должны быть созданы с помощью ключевого слова new.
obj = new Element();
А new
Ключевое слово создает экземпляры объектов, используя функции в качестве конструктора.Например:
var Foo = function() {};
Foo.prototype.bar = 'bar';
var foo = new Foo();
foo instanceof Foo; // true
Экземпляры наследуются от prototype
функции-конструктора.Итак, учитывая пример выше...
foo.bar; // 'bar'
Что ж, JavaScript сам по себе может сильно отличаться от платформы к платформе, поскольку он всегда является реализацией исходной спецификации EcmaScript.
В любом случае, независимо от реализации, все реализации JavaScript, соответствующие спецификации EcmaScript, дадут вам объектно-ориентированный язык.По стандарту ES:
Ecmascript-это объектно-ориентированный язык программирования для выполнения вычислений и манипулирования вычислительными объектами в среде хоста.
Итак, теперь мы пришли к соглашению, что JavaScript является реализацией EcmaScript и, следовательно, является объектно-ориентированным языком.Определение new
операция на любом объектно-ориентированном языке говорит, что такое ключевое слово используется для создания экземпляра объекта из класса определенного типа (включая анонимные типы, в таких случаях, как C#).
В EcmaScript мы не используем классы, как вы можете прочитать из спецификации:
ECMAScript не использует классы, подобные тем, которые есть в C++, Smalltalk или Java.Вместо этого объекты могут создаваться различными способами, включая буквальную нотацию или через конструкторы, которые создают объекты, а затем выполняют код, который инициализирует все или часть из них путем назначения начальных значений их свойствам.Каждый конструктор - это функция, которая имеет свойство, названное «прототип», которое используется для реализации прототипа - основанного на наследии и общих свойствах.Объекты создаются
использование конструкторов в новых выражениях;Например, новая дата (2009,11) создает новый объект даты.Вызов конструктора без использования нового имеет последствия, которые зависят от конструктора.Например, Date () создает строковое представление текущей даты и времени, а не объекта.
Краткое содержание:
А new
Ключевое слово используется в JavaScript для создания объекта из функции-конструктора.А new
Ключевое слово должно быть помещено перед вызовом функции конструктора и будет выполнять следующие действия:
- Создает новый объект
- Устанавливает прототип этого объекта в свойство прототипа функции-конструктора.
- Связывает
this
ключевое слово для вновь созданного объекта и выполняет функцию конструктора - Возвращает вновь созданный объект
Пример:
function Dog (age) {
this.age = age;
}
const doggie = new Dog(12);
console.log(doggie);
console.log(doggie.__proto__ === Dog.prototype) // true
Что именно происходит:
const doggie
говорит:Нам нужна память для объявления переменной.- Оператор присваивания
=
говорит:Мы собираемся инициализировать эту переменную выражением после=
- Выражение
new Dog(12)
.Движок JS видит новое ключевое слово, создает новый объект и устанавливает прототип Dog.prototype. - Функция конструктора выполняется с помощью
this
значение, установленное для нового объекта.На этом этапе новому созданному объекту собачки присваивается возраст. - Вновь созданный объект возвращается и присваивается переменной Doggie.