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

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

  • Что это такое?
  • Какие проблемы он разрешает?
  • Когда это подходит, а когда нет?
+1647
источник поделиться
14 ответов

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

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

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

+2045
источник

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

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

+377
источник

В дополнение к ответу Даниэля Говарда, вот что делает 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);
+157
источник

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

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

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

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

+100
источник

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

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

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

var john = new Person('John');

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

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

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

+34
источник

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

+27
источник

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

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

+14
источник

Есть уже некоторые очень большие ответы, но я отправляю новый, чтобы подчеркнуть свое замечание по делу 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 ключевым словом, которое я сделал, чтобы объяснить концепцию в текущем потоке.

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

+7
источник

иногда код проще, чем слова:

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
источник

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

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

+4
источник

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

obj = new Element();
+3
источник

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

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

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

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

foo.bar; // 'bar'
+1
источник

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

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

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

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

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

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

+1
источник

Резюме:

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

  1. Создает новый объект
  2. Устанавливает прототип этого объекта в свойство прототипа функции конструктора
  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. Оператор assigment = говорит: мы собираемся инициализировать эту переменную с выражением после =
  3. Выражение - new Dog(12). Механизм JS видит новое ключевое слово, создает новый объект и задает прототип для Dog.prototype
  4. Функция конструктора выполняется с this значением, установленным для нового объекта. На этом этапе возраст назначается новому созданному объекту doggie.
  5. Созданный объект возвращается и присваивается переменной doggie.
+1
источник

Посмотрите другие вопросы по меткам или Задайте вопрос