Что такое "новое" ключевое слово в JavaScript?
Ключевое слово new
в JavaScript может быть довольно запутанным, когда оно впервые встречается, поскольку люди склонны думать, что JavaScript не является объектно-ориентированным языком программирования.
- Что это такое?
- Какие проблемы он разрешает?
- Когда это подходит, а когда нет?
Ответы
Ответ 1
Это делает 5 вещей:
- Это создает новый объект. Тип этого объекта - просто объект.
- Он устанавливает внутреннее недоступное свойство [[prototype]] (т. Е. __Proto__) этого нового объекта в качестве функции-конструктора внешнего, доступного объекта-прототипа (каждый объект функции автоматически имеет свойство prototype).
- Это заставляет переменную
this
указывать на вновь созданный объект. - Он выполняет функцию конструктора, используя вновь созданный объект всякий раз, когда
this
упоминается. - Он возвращает вновь созданный объект, если только функция конструктора не возвращает ссылку на
null
объект non-. В этом случае вместо этого возвращается ссылка на объект.
Примечание: функция конструктора ссылается на функцию после new
ключевого слова, как в
new ConstructorFunction(arg1, arg2)
Как только это будет сделано, если запрошено неопределенное свойство нового объекта, сценарий проверит объектный объект [[prototype]] вместо этого свойства. Вот как вы можете получить нечто похожее на традиционное наследование классов в JavaScript.
Самая сложная часть этого - точка № 2. Каждый объект (включая функции) имеет это внутреннее свойство, называемое [[prototype]]. Это может быть установлено только во время создания объекта, либо с новым, с Object.create, либо на основе литерала (функции по умолчанию для Function.prototype, числа для Number.prototype и т.д.). Его можно прочитать только с помощью Object.getPrototypeOf(someObject). Нет другого способа установить или прочитать это значение.
Функции, в дополнение к скрытому свойству [[prototype]], также имеют свойство с именем prototype, и именно этим вы можете обращаться и изменять, чтобы предоставлять унаследованные свойства и методы для создаваемых вами объектов.
Вот пример:
ObjMaker = function() {this.a = 'first';};
// ObjMaker is just a function, there 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 [[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
Я прочитал тонну мусора на эту тему, прежде чем наконец нашел эту страницу, где это очень хорошо объясняется с помощью хороших диаграмм.
Ответ 2
Предположим, что у вас есть эта функция:
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
. Любая функция может быть конструктором, она не всегда имеет смысл.
Ответ 3
В дополнение к ответу Даниэля Говарда, вот что делает 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);
Ответ 4
Для начинающих, чтобы понять это лучше
Попробуйте следующий код в консоли браузера.
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
Теперь вы можете прочитать ответ вики сообщества :)
Ответ 5
поэтому он, вероятно, не для создания экземпляры объекта
Он использовал именно для этого. Вы определяете конструктор функции следующим образом:
function Person(name) {
this.name = name;
}
var john = new Person('John');
Однако дополнительная выгода, которую имеет ECMAScript, заключается в том, что вы можете расширить с помощью свойства .prototype
, поэтому мы можем сделать что-то вроде...
Person.prototype.getName = function() { return this.name; }
Все объекты, созданные из этого конструктора, теперь будут иметь getName
из-за цепи прототипа, к которой у них есть доступ.
Ответ 6
JavaScript - это объектно-ориентированный язык программирования, который используется именно для создания экземпляров. Он основан на прототипах, а не на основе классов, но это не значит, что он не является объектно-ориентированным.
Ответ 7
Javascript - это динамический язык программирования, который поддерживает парадигму объектно-ориентированного программирования, и его используют для создания новых экземпляров объекта.
Классы не нужны для объектов - Javascript - это язык, основанный на прототипах.
Ответ 8
Есть уже некоторые очень большие ответы, но я отправляю новый, чтобы подчеркнуть свое замечание по делу 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
. Поскольку нет явного оператора return, интерпретатор 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
становятся свойствами вновь созданного объекта (вместо объекта окна). Поскольку у вас нет явного оператора return, интерпретатор JavaScript принудительно вставляет оператор return, чтобы вернуть новый объект, созданный из-за использования 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
становятся свойствами вновь созданного объекта. Но на этот раз у вас есть явное выражение return, поэтому интерпретатор JavaScript не будет ничего делать самостоятельно.
В случае III следует отметить, что объект, созданный из-за new
ключевого слова, потерян с вашего радара. bar
фактически указывает на совершенно другой объект, который не является тем, который интерпретатор JavaScript создал из-за new
ключевого слова.
Цитата Дэвида Фланагана из JavaScripit: Полное руководство (6-е издание), гл. 4, страница № 62:
Когда выражение создания объекта оценивается, JavaScript сначала создает новый пустой объект, такой же, как тот, который создан инициализатором объекта {}. Затем он вызывает указанную функцию с указанными аргументами, передавая новый объект в качестве значения ключевого слова this. Затем функция может использовать это для инициализации свойств вновь созданного объекта. Функции, написанные для использования в качестве конструкторов, не возвращают значение, а значением выражения создания объекта является вновь созданный и инициализированный объект. Если конструктор возвращает значение объекта, это значение становится значением выражения создания объекта, и вновь созданный объект отбрасывается.
--- Дополнительная информация ---
Функции, используемые в фрагменте кода вышеупомянутых случаев, имеют специальные имена в мире JS, как показано ниже:
Случай я и II - функция конструктора
Случай III - Заводская функция. Фабричные функции не должны использоваться с new
ключевым словом, которое я сделал, чтобы объяснить концепцию в текущем потоке.
Вы можете прочитать о разнице между ними в этой теме.
Ответ 9
иногда код проще, чем слова:
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, поскольку он дает мне немного большую гибкость внутри и снаружи функции.
Ответ 10
Ключевое слово new
изменяет контекст, в котором выполняется эта функция, и возвращает указатель на этот контекст.
Если вы не используете ключевое слово new
, контекст, под которым запускается функция Vehicle()
, представляет собой тот же контекст, из которого вы вызываете функцию Vehicle
. Ключевое слово this
будет ссылаться на один и тот же контекст. Когда вы используете new Vehicle()
, создается новый контекст, поэтому ключевое слово this
внутри функции ссылается на новый контекст. То, что вы получаете взамен, - это вновь созданный контекст.
Ответ 11
Ключевое слово new
предназначено для создания новых экземпляров объектов. И да, javascript - это язык динамического программирования, который поддерживает парадигму объектно-ориентированного программирования. Соглашение об именовании объектов всегда использует заглавную букву для объектов, которые должны быть созданы новым ключевым словом.
obj = new Element();
Ответ 12
Ключевое слово new
создает экземпляры объектов, используя функции в качестве конструктора. Например:
var Foo = function() {};
Foo.prototype.bar = 'bar';
var foo = new Foo();
foo instanceof Foo; // true
Экземпляры наследуют от prototype
функции-конструктора. Итак, приведенный выше пример...
foo.bar; // 'bar'
Ответ 13
Ну JavaScript на si может сильно отличаться от платформы к платформе, поскольку она всегда является реализацией исходной спецификации EcmaScript.
В любом случае независимо от реализации все реализации JavaScript, соответствующие спецификации спецификации EcmaScript, предоставят вам объектно-ориентированный язык. Согласно стандарту ES:
ECMAScript - это объектно-ориентированный язык программирования для выполнение вычислений и манипулирование вычислительными объектами в среде хоста.
Итак, теперь, когда мы согласились, что JavaScript является реализацией EcmaScript и поэтому является объектно-ориентированным языком. Определение операции new
на любом объектно-ориентированном языке говорит о том, что такое ключевое слово используется для создания экземпляра объекта из класса определенного типа (включая анонимные типы, в случаях, подобных С#).
В EcmaScript мы не используем классы, как вы можете прочитать из спецификаций:
ECMAScript не использует классы, например, в С++, Smalltalk или Java. Вместо этого объекты могут быть созданы различными способами, включая буквальное обозначение или через конструкторы, которые создают объекты, а затем выполняют код, который инициализирует все или часть из них, назначая начальные значения к их свойствам. Каждый конструктор является функцией, которая имеет свойство - прототип ‖, который используется для реализации наследования на основе прототипов и общих свойств. Объекты создаются с помощью использование конструкторов в новых выражениях; например, новых Дата (2009,11) создает новый объект Date. Вызов конструктора без использования новых имеет последствия, которые зависят от конструктора. Например, Date() создает строковое представление текущая дата и время, а не объект.
Ответ 14
Резюме:
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