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

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

  • Что это?
  • Какие проблемы это решает?
  • Когда это уместно, а когда нет?

17 ответов

Решение

Это делает 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

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

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

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 является объектно-ориентированным языком программирования и используется именно для создания экземпляров. Он основан на прототипах, а не на классах, но это не значит, что он не объектно-ориентирован.

Резюме:

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.

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

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

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

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

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

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

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

 " Every object (including functions) has this internal property called [[prototype]]" 

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

вы, ребята, можете легко проверить:

const a = { name: "something" };
console.log(a.prototype); // undefined because it is not directly accessible

const b = function () {
  console.log("somethign");};

console.log(b.prototype); // returns b {}

Но каждая функция и объекты имеют __proto__ свойство, которое указывает на прототип этого объекта или функции. __proto__ а также prototypeэто 2 разных термина. Я думаю, что мы можем сделать этот комментарий: "Каждый объект связан с прототипом через прото "

console.log(a.__proto__); // returns {}
console.log(b.__proto__); // returns [Function]

Вы, ребята, можете легко это проверить на терминале. Итак, что такое функция-конструктор.

function CreateObject(name,age){
    this.name=name;
    this.age =age
}

три вещи, на которые следует обратить внимание в первую очередь:

1- Мы не используем return ключевое слово. new справится с этим.

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

3- Мы не используем стрелочную функцию. Потому что ценностьthisПараметр подбирается в момент создания стрелочной функции "окно". стрелочные функции имеют лексическую, а не динамическую область видимости. Лексически здесь означает локально. стрелочная функция несет свое локальное значение "this".

const me=new CreateObject("yilmaz","21")

new вызывает функцию и затем создает пустой объект {}, а затем добавляет ключ "name" со значением "name" и ключ "age" со значением аргумента "age".

Когда мы вызываем функцию, создается новый контекст выполнения с "this" и "arguments", поэтому "new" имеет доступ к этим аргументам.

По умолчанию эта функция внутри конструктора будет указывать на объект "окно", но newменяет это. "this" указывает на пустой объект {}, который создается, а затем свойства добавляются к вновь созданному объекту. Если у вас есть переменная, определенная без свойства this, она не будет добавлена ​​к объекту.

function CreateObject(name,age){
    this.name=name;
    this.age =age;
    const myJob="developer"
}

Свойство myJob не будет добавлено к объекту, потому что ничего не ссылается на вновь созданный объект.

   const me= {name:"yilmaz",age:21} // there is no myJob key

вначале я сказал, что каждая функция имеет свойство "прототип", включая функции конструктора. Мы можем добавить методы к прототипу конструктора, чтобы каждый объект, созданный из этой функции, имел к нему доступ.

 CreateObject.prototype.myActions=function(){ //define something}

Теперь объект "я" может использовать метод "myActions".

javascript имеет встроенные функции конструктора: Function,Boolean,Number,String..

если я создам

const a = new Number(5);
console.log(a);  // [Number: 5]
console.log(typeof a); // object

Все, что создано с помощью newимеет тип объекта. теперь "a" имеет доступ ко всем методам, хранящимся внутри Number.prototype. Если бы я определил

const b = 5;
console.log(a === b);//false

a и b равны 5, но a - объект, а b - примитив. хотя b является примитивным типом, когда он создается, javascript автоматически обертывает его с помощью Number(), поэтому b имеет доступ ко всем методам внутри Number.prototype.

Функция конструктора полезна, когда вы хотите создать несколько похожих объектов с одинаковыми свойствами и методами. Таким образом, вы не будете выделять дополнительную память, поэтому ваш код будет работать более эффективно.

Javascript не является объектно-ориентированным языком программирования, поэтому процесс LOOK UP в javascript работает с использованием "ПРОЦЕССА ДЕЛЕГАЦИИ", также известного как делегирование прототипа или прототипное наследование.

Если вы попытаетесь получить значение свойства из объекта, которого у него нет, движок JavaScript просматривает прототип объекта (и его прототип, на 1 шаг выше за раз), это цепочка прототипов, пока цепочка не заканчивается до нуля, который - это Object.prototype == null (стандартный прототип объекта). На этом этапе, если свойство или метод не определены, возвращается undefined.

Таким образом, с new ключевое слово некоторые задачи, которые были выполнены вручную, например

  1. Создание объекта вручную, например newObj.
  2. Создание скрытой связи с использованием прототипа (также известного как dunder proto) в спецификации JS [[прототип]] (т.е. прототип)
  3. ссылки и присвоение свойств newObj
  4. Возвращение newObj объект.

Все делается вручную.

function CreateObj(value1, value2) {
  const newObj = {};
  newObj.property1 = value1;
  newObj.property2 = value2;
  return newObj;
}
var obj = new CreateObj(10,20);

obj.__proto__ === Object.prototype;              // true
Object.getPrototypeOf(obj) === Object.prototype // true

Ключевое слово Javascript new помогает автоматизировать этот процесс:

  1. новый литерал объекта создается, идентифицированный this:{}
  2. ссылки и присвоение свойств this
  3. Создание скрытой связи [[прототип]] (т.е. прототип) с общим пространством Function.prototype.
  4. неявный возврат this объект {}
function CreateObj(value1, value2) {
  this.property1 = value1;
  this.property2 = value2;
}

var obj = new CreateObj(10,20);
obj.__proto__ === CreateObj.prototype             // true
Object.getPrototypeOf(obj) == CreateObj.prototype // true

Вызов функции конструктора без нового ключевого слова:

=> this: Window

function CreateObj(value1, value2) {
  var isWindowObj = this === window;
  console.log("Is Pointing to Window Object", isWindowObj);
  this.property1 = value1;
  this.property2 = value2;
}
var obj = new CreateObj(10,20); // Is Pointing to Window Object false
var obj = CreateObj(10,20); // Is Pointing to Window Object true
window.property1; // 10
window.property2; // 20

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

obj = new Element();

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

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

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

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

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

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

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

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

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

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

foo.bar; // 'bar'

Он имеет 3 этапа:

1.Create: он создает новый объект и устанавливает свойство [[prototype]] этого объекта в качестве свойства прототипа функции-конструктора.

2.Execute: указывает на вновь созданный объект и выполняет функцию конструктора.

3.Return: в обычном случае возвращается только что созданный объект. Однако если вы явно возвращаете ненулевой объект или функцию, вместо этого возвращается это значение. Следует отметить, что если вы возвращаете ненулевое значение, но это не объект (например, значение символа, неопределенное, NaN), это значение игнорируется, и возвращается вновь созданный объект.

      function myNew(constructor, ...args) {
  const obj = {}
  Object.setPrototypeOf(obj, constructor.prototype)
  
  const returnedVal = constructor.apply(obj, args)
  
  if (
    typeof returnedVal === 'function' 
    || (typeof returnedVal === 'object' && returnedVal !== null)) {
      return returnedVal
  }
  return obj
}

Для получения дополнительной информации и тестов дляmyNew, вы можете прочитать мой блог: https://medium.com/@magenta2127/how-does-the-new-operator-work-f7eaac692026

Другие вопросы по тегам