Что такое «новое» ключевое слово в JavaScript?

newКлючевое слово в JavaScript может быть довольно запутанным , когда он впервые встречается, так как люди склонны думать , что JavaScript не является объектно-ориентированный язык программирования.

  • Что это?
  • Какие проблемы это решает?
  • Когда это уместно, а когда нет?
29.10.2009 21:32:45
Кроме того, связанный поток - stackoverflow.com/questions/383402/…
Chetan Sastry 29.10.2009 22:04:46
Сначала прочтите эти примеры, developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Martian2049 30.12.2018 17:00:39
14 ОТВЕТОВ
РЕШЕНИЕ

Это делает 5 вещей:

  1. Это создает новый объект. Тип этого объекта - просто объект .
  2. Он устанавливает внутреннее недоступное свойство [[prototype]] (т. Е. __Proto__ ) этого нового объекта как внешний, доступный объект- прототип функции конструктора (каждый объект функции автоматически имеет свойство prototype ).
  3. Это делает thisточку переменной для вновь созданного объекта.
  4. Он выполняет функцию конструктора, используя вновь созданный объект всякий раз, когда thisупоминается.
  5. Он возвращает вновь созданный объект, если только функция конструктора не возвращает nullссылку на не объект. В этом случае вместо этого возвращается ссылка на объект.

Примечание: функция конструктора ссылается на функцию после 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'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

Я прочитал кучу мусора на эту тему, прежде чем наконец нашел эту страницу , где это очень хорошо объясняется с помощью хороших диаграмм.

2134
25.12.2018 14:57:13
Просто хотел добавить: на самом деле есть способ получить доступ к внутреннему [[prototype]] с помощью __proto__. Однако это нестандартно и поддерживается только относительно новыми браузерами (и не всеми). Существует стандартизированный способ, а именно Object.getPrototypeOf (obj), но это Ecmascript3.1, и он сам по себе поддерживается только в новых браузерах - опять же. Как правило, рекомендуется не использовать это свойство, но там все очень быстро усложняется.
Blub 14.04.2011 14:55:40
Вопрос: что происходит по-другому, если ObjMakerопределяется как функция, которая возвращает значение?
Jim Blackler 27.02.2012 19:05:32
@LonelyPixel newсуществует, так что вам не нужно писать фабричные методы для конструирования / копирования функций / объектов. Это означает: «Скопируйте это, сделав его таким же, как его родительский« класс »; делайте это эффективно и правильно; и храните информацию о наследовании, которая доступна только мне, JS, внутри». Для этого он изменяет недоступный в противном случае внутренний prototypeобъект нового объекта, чтобы непрозрачно инкапсулировать унаследованные элементы, имитируя классические цепочки наследования ОО (которые нельзя изменить во время выполнения). Вы можете смоделировать это без new, но наследование будет изменяемым во время выполнения. Хорошо? Плохой? Вам решать.
Engineer 23.10.2012 22:36:20
небольшая точка для добавления: вызов конструктора, которому предшествует ключевое слово new, автоматически возвращает созданный объект; нет необходимости явно возвращать его из конструктора.
charlie roberts 6.06.2013 02:04:18
Есть записка с надписью Notice that this pattern is deprecated!. Каков правильный современный шаблон для установки прототипа класса?
Tom Pažourek 17.02.2014 12:18:41

так что это, вероятно, не для создания экземпляров объекта

Это используется именно для этого. Вы определяете конструктор функции так:

function Person(name) {
    this.name = name;
}

var john = new Person('John');

Однако дополнительное преимущество, которое имеет ECMAScript, заключается в том, что вы можете расширять его с помощью .prototypeсвойства, поэтому мы можем сделать что-то вроде ...

Person.prototype.getName = function() { return this.name; }

Все объекты, созданные из этого конструктора, теперь будут иметь getNameцепочку прототипов, к которой они имеют доступ.

37
6.01.2016 08:49:34
конструкторы функций используются как классы, здесь нет classключевого слова, но вы можете сделать то же самое.
meder omuraliev 29.10.2009 21:37:07
Там kindof является ключевым словом класса - класс зарезервирован для будущего использования
Greg 29.10.2009 21:41:09
Кстати, именно поэтому вы используете .className, а не .class, чтобы установить класс CSS
Greg 29.10.2009 21:41:47
Он должен быть написан заглавными буквами.
eomeroff 26.06.2013 13:56:32

JavaScript является объектно-ориентированным языком программирования и используется именно для создания экземпляров. Он основан на прототипах, а не на классах, но это не значит, что он не объектно-ориентирован.

27
3.02.2011 16:01:00
Мне нравится говорить, что JavaScript кажется еще более объектно-ориентированным, чем все эти языки на основе классов. В JavaScript все, что вы пишете, немедленно становится объектом, но в языках на основе классов вы сначала пишете объявления, а только потом вы создаете конкретные экземпляры (объекты) классов. И прототип JavaScript, кажется, смутно напоминает все эти VTABLE вещи для языков на основе классов.
JustAMartin 7.10.2013 07:33:29

Javascript - это динамический язык программирования, который поддерживает парадигму объектно-ориентированного программирования и использует его для создания новых экземпляров объекта.

Классы не нужны для объектов - Javascript - это язык, основанный на прототипах .

14
18.03.2014 20:00:15

newКлючевые слова создают экземпляры объектов с использованием функции в качестве конструктора. Например:

var Foo = function() {};
Foo.prototype.bar = 'bar';

var foo = new Foo();
foo instanceof Foo; // true

Экземпляры наследуются от prototypeфункции конструктора. Итак, приведенный выше пример ...

foo.bar; // 'bar'
1
30.06.2014 21:36:41
Ключевое слово new в основном связывает функцию уже как конструктор; вам не нужно ничего возвращать. Вы можете просто сделать: function foo (x) {this.bar = x; } var obj = new foo (10); оповещения (obj.bar);
reko_t 29.10.2009 21:40:44
Вам не нужно возвращать объекты из функции конструктора, если вы не хотите специально для этой цели. Например, если вам нужно возвращать конкретный экземпляр объекта вместо создания нового объекта каждый раз (по какой-либо причине). В вашем примере, однако, это совершенно не нужно.
Chetan Sastry 29.10.2009 21:43:16
Ну, это был пример. Вы можете вернуть объект. В этом сценарии используется много шаблонов, я предоставил один как «например», отсюда и мои слова «например».
eyelidlessness 29.10.2009 21:43:26

newКлючевое слово для создания новых экземпляров объектов. И да, javascript - это динамический язык программирования, который поддерживает парадигму объектно-ориентированного программирования. Соглашение о присвоении имен объектам заключается в том, чтобы всегда использовать заглавную букву для объектов, для которых предполагается создание нового ключевого слова.

obj = new Element();
3
18.03.2014 19:59:50

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

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. Любая функция может быть конструктором, просто она не всегда имеет смысл.

398
20.04.2013 22:54:36
Зависит от контекста исполнения. В моем случае (Qt scripting) это просто глобальный объект.
Maxym 21.01.2013 13:24:27
это вызовет больше использования памяти?
Jürgen Paul 24.07.2013 19:20:44
потому что окно является объектом, который вызвал функцию - должно быть: потому что окно является объектом, который содержит функцию.
Dávid Horváth 23.07.2016 13:22:05
@Taurus В веб-браузере windowнеявная функция будет методом неявно. Даже в закрытии, даже если анонимус. Однако в этом примере это простой вызов метода для окна: Foo();=> [default context].Foo();=> window.Foo();. В этом выражении windowесть контекст (не только вызывающий , что не имеет значения).
Dávid Horváth 11.09.2017 11:47:02
@ Телец В основном да. Однако в ECMA 6 и 7 все более сложно (см. Лямбды, классы и т. Д.).
Dávid Horváth 11.09.2017 12:00:32

В дополнение к ответу Дэниела Ховарда, вот что 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);
162
10.12.2014 12:54:40
Я обнаружил, что JavaScript легче понять, чем английский: V
damphat 20.10.2013 10:11:10
Отличный ответ. У меня есть один крошечный вопрос: Как это может быть возможным , func.prototypeчтобы быть null? Не могли бы вы рассказать подробнее об этом?
Tom Pažourek 2.04.2014 11:12:10
@tomp, вы можете переопределить свойство prototype, просто написав. A.prototype = null;В этом случае вы new A()получите объект on, то есть внутренний прототип указывает на Objectобъект: jsfiddle.net/Mk42Z
basilikum 28.04.2014 18:19:32
Проверка typeof может быть неправильной, потому что хост-объект может производить что-то отличное от «object» или «function». Чтобы проверить, если что-то является объектом, я предпочитаю Object(ret) === ret.
Oriol 8.10.2015 21:40:25
@Oriol спасибо за комментарий. Это правда, что вы говорите, и любой реальный тест должен быть сделан более надежным способом. Тем не менее, я думаю, что для этого концептуального ответа, typeofтест просто облегчает понимание того, что происходит за кулисами.
basilikum 8.10.2015 21:53:27

Ну, JavaScript на Си может сильно отличаться от платформы к платформе, поскольку это всегда реализация оригинальной спецификации EcmaScript.

В любом случае, независимо от реализации, все реализации JavaScript, которые соответствуют спецификации EcmaScript, дадут вам объектно-ориентированный язык. Согласно стандарту ES:

ECMAScript - это объектно-ориентированный язык программирования для выполнения вычислений и манипулирования вычислительными объектами в среде хоста.

Итак, теперь, когда мы договорились, что JavaScript - это реализация EcmaScript и, следовательно, это объектно-ориентированный язык. Определение newоперации в любом объектно-ориентированном языке говорит, что такое ключевое слово используется для создания экземпляра объекта из класса определенного типа (включая анонимные типы, в случаях, подобных C #).

В EcmaScript мы не используем классы, как вы можете прочитать из спецификации:

ECMAScript не использует классы, такие как в C ++, Smalltalk или Java. Вместо этого объекты могут создаваться различными способами, в том числе посредством буквенной нотации или с помощью конструкторов, которые создают объекты и затем выполняют код, который инициализирует все или часть из них, назначая начальные значения их свойствам. Каждый конструктор - это функция, которая имеет свойство с именем - prototype ‖, которое используется для реализации наследования на основе прототипа и общих свойств. Объекты создаются с
помощью конструкторов в новых выражениях; например, new Date (2009,11) создает новый объект Date. Вызов конструктора без использования new имеет последствия, которые зависят от конструктора. Например, Date () создает строковое представление текущей даты и времени, а не объекта.

1
13.05.2015 23:05:28

иногда код легче слов:

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, поскольку он дает мне немного больше гибкости внутри и снаружи функции.

5
16.05.2015 07:21:57
B1 = new func2(2); <- Почему этого не будет B1.y ?
sunny_dev 17.11.2015 09:37:24
@sunny_dev Я не эксперт по JS, но, вероятно, потому что func2 возвращает непосредственно значение (объект z) вместо того, чтобы работать / возвращать с внутренними значениями (это)
Eagle 19.12.2016 09:05:45

Для начинающих, чтобы понять это лучше

Попробуйте следующий код в консоли браузера.

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

Теперь вы можете прочитать ответ сообщества вики :)

107
28.12.2018 14:07:23
Хороший ответ. Кроме того, return this;опускание дает тот же результат.
Nelu 2.02.2017 21:26:52

Уже есть несколько очень хороших ответов, но я публикую новый, чтобы подчеркнуть мое наблюдение в случае 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становятся свойства вновь создаваемого объекта (вместо оконного объекта). Поскольку у вас нет явного оператора 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, как показано ниже:

Случай I и II - функция конструктора

Случай III - Заводская функция. Фабричные функции не должны использоваться с newключевым словом, которое я сделал, чтобы объяснить концепцию в текущем потоке.

Вы можете прочитать о разнице между ними в этой теме.

12
12.07.2019 01:03:38
ваш случай 3, наблюдение gr8
appu 16.06.2019 16:51:55

newКлючевое слово изменяет контекст , в котором функция времени запуска и возвращает указатель на этот контекст.

Если вы не используете newключевое слово, контекст, в котором Vehicle()выполняется функция, совпадает с контекстом, из которого вы вызываете Vehicleфункцию. thisКлючевое слово будет ссылаться на тот же контекст. Когда вы используете new Vehicle(), создается новый контекст, поэтому ключевое слово thisвнутри функции ссылается на новый контекст. В ответ вы получаете только что созданный контекст.

5
27.11.2017 13:13:55
Это очень проницательный ответ с точки зрения объема. Gr8 дополнение к ответу.
appu 16.06.2019 16:53:41

Резюме:

newКлючевое слово используется в JavaScript для создания объекта из функции конструктора. newКлючевое слово должно быть перед вызовом функции конструкторы и будет делать следующие вещи:

  1. Создает новый объект
  2. Устанавливает прототип этого объекта в свойство prototype функции конструктора
  3. Привязывает thisключевое слово к вновь созданному объекту и выполняет функцию конструктора
  4. Возвращает вновь созданный объект

Пример:

function Dog (age) {
  this.age = age;
}

const doggie = new Dog(12);

console.log(doggie);
console.log(doggie.__proto__ === Dog.prototype) // true

Что именно происходит:

  1. const doggie говорит: нам нужна память для объявления переменной.
  2. Оператор присвоения =говорит: мы собираемся инициализировать эту переменную с помощью выражения после=
  3. Выражение есть new Dog(12). Движок JS видит новое ключевое слово, создает новый объект и устанавливает прототип в Dog.prototype
  4. Функция конструктора выполняется со thisзначением, установленным для нового объекта. На этом этапе возраст назначается вновь созданному объекту собачка.
  5. Вновь созданный объект возвращается и присваивается переменной doggie.
2
31.08.2018 08:22:51