JavaScript'teki 'yeni' anahtar kelime nedir?


1744

newJavaScript anahtar kelime ilk karşılaşıldığında insanların JavaScript nesne yönelimli bir programlama dili değildir düşünüyorsanız eğilimindedir oldukça kafa karıştırıcı olabilir.

  • Bu ne?
  • Hangi sorunları çözüyor?
  • Ne zaman uygun ve ne zaman uygun değil?


Yanıtlar:


2144

5 şey yapar:

  1. Yeni bir nesne oluşturur. Bu nesnenin türü basitçe nesnedir .
  2. Bu yeni nesnenin dahili, erişilemeyen [[prototip]] (yani __proto__ ) özelliğini yapıcı işlevinin harici, erişilebilir, prototip nesnesi olarak ayarlar (her işlev nesnesinin otomatik olarak bir prototip özelliği vardır).
  3. Bu kılan thisyeni oluşturulan nesneye değişken noktası.
  4. Ne zaman thisbahsedilirse yeni oluşturulan nesneyi kullanarak yapıcı işlevini yürütür .
  5. Yapıcı işlevi nullnesne olmayan bir başvuru döndürmediği sürece yeni oluşturulan nesneyi döndürür . Bu durumda, bunun yerine nesne başvurusu döndürülür.

Not: yapıcı işlevinew , olduğu gibi , anahtar sözcükten sonraki işlevi ifade eder

new ConstructorFunction(arg1, arg2)

Bu yapıldıktan sonra, yeni nesnenin tanımsız bir özelliği istenirse, komut dosyası bunun yerine nesnenin [[prototip]] nesnesini kontrol eder . JavaScript'te geleneksel sınıf kalıtımına benzer bir şey bu şekilde elde edilebilir.

Bununla ilgili en zor kısım 2 numaralı noktadır. Her nesne (fonksiyonlar dahil) [[prototip]] adı verilen bu dahili özelliğe sahiptir . Bu olabilir ancak birlikte de, nesne oluşturma sırasında ayarlanabilir yeni olan Object.create (Number.prototype için sayılar, vb Function.prototype için fonksiyonları varsayılan) veya edebi dayalı. Yalnızca Object.getPrototypeOf (someObject) ile okunabilir . Orada hiçbir ayarlamak veya bu değeri okumak için başka bir yol.

Gizli [[prototip]] özelliğinin yanı sıra işlevler de prototip adı verilen bir özelliğe sahiptir ve yaptığınız nesneler için devralınan özellikler ve yöntemler sağlamak üzere erişebileceğiniz ve değiştirebileceğiniz budur.


İşte bir örnek:

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'

Sınıf mirası gibidir, çünkü şimdi yaptığınız nesneler new ObjMaker()de 'b' özelliğini miras almış gibi görünecektir.

Alt sınıf gibi bir şey istiyorsanız, bunu yaparsınız:

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

Nihayet bu sayfayı bulmadan önce bu konuyla ilgili bir ton çöp okudum, bunun güzel diyagramlarla çok iyi açıklandığı.


47
Sadece eklemek istedim: Aslında iç [[prototip]] 'e __proto__ ile erişmenin bir yolu var. Ancak bu standart değildir ve yalnızca nispeten yeni tarayıcılar tarafından desteklenir (hepsi değil). Standart bir yol var, yani Object.getPrototypeOf (obj), ancak Ecmascript3.1 ve kendisi sadece yeni tarayıcılarda destekleniyor - yine. Genellikle bu özelliği kullanmamanız tavsiye edilir, ancak şeyler içeride çok hızlı bir şekilde karmaşık hale gelir.
Blub

9
Soru: ObjMakerBir değer döndüren bir işlev olarak tanımlanırsa ne olur ?
Jim Blackler

13
@LonelyPixel , işlevler / nesneler oluşturmak / kopyalamak için fabrika yöntemleri yazmak zorunda kalmamanız için newvardır . "Bunu kopyalayın, tıpkı ana 'sınıfı' gibi yapın; verimli ve doğru bir şekilde yapın; ve yalnızca bana erişilebilen miras bilgilerini depolayın". Bunu yapmak için, klasik OO miras zincirlerini taklit ederek (çalışma zamanı değiştirilemez) miras alınan üyeleri opak bir şekilde kapsüllemek için yeni nesnenin erişilemeyen iç kısmını değiştirir. Bunu olmadan simüle edebilirsiniz , ancak devralma çalışma zamanı değiştirilebilir. İyi? Kötü? Sana bağlı. prototypenew
Mühendis

11
eklenecek küçük bir nokta: Yeni anahtar kelimeden önce yapıcıya yapılan çağrı otomatik olarak oluşturulan nesneyi döndürür; bunu yapıcıdan açıkça döndürmeye gerek yoktur.
charlie roberts

7
Diyor ki bir not var Notice that this pattern is deprecated!. Bir sınıfın prototipini ayarlamak için doğru güncel model nedir?
Tom Pažourek

400

Bu işleve sahip olduğunuzu varsayalım:

var Foo = function(){
  this.A = 1;
  this.B = 2;
};

Bunu bağımsız bir işlev olarak şöyle çağırırsanız:

Foo();

Bu işlevin yürütülmesi windownesneye ( Ave B) iki özellik ekleyecektir . Bunu , buna böyle yürüttüğünüzde işlevi çağıran nesnedir windowçünkü bir işlevde işlevi çağıran nesnedir. En azından Javascript'te.windowthis

Şimdi şöyle deyin new:

var bar = new Foo();

newBir işlev çağrısına eklediğinizde olan şey, yeni bir nesnenin (sadece var bar = new Object()) oluşturulmuş thisolması ve işlev içindeki, işlevi Objectçağıran nesneyi değil , yeni oluşturduğunuz yeniyi işaret etmesidir. Yani barşimdi özelliklere sahip bir nesnedir Ave B. Herhangi bir işlev bir kurucu olabilir, her zaman mantıklı değildir.


7
Yürütme bağlamına bağlıdır. Benim durumumda (Qt script) sadece küresel bir nesne.
Maxym

2
bu daha fazla bellek kullanımına neden olur mu?
Jürgen Paul

2
çünkü pencere işlevi çağıran nesnedir - olmalıdır: çünkü pencere işlevi içeren nesnedir .
Dávid Horváth

1
@Taurus Bir web tarayıcısında yöntem olmayan bir işlev windowörtük olarak bir yöntem olacaktır . Kapanışta bile, anonim olsa bile. Bununla birlikte, örnekte, pencerede basit bir yöntem çağırmadır: Foo();=> [default context].Foo();=> window.Foo();. Bu ifadede windowolduğu bağlam (sadece arayanın önemi yok).
Dávid Horváth

1
@Taurus Temel olarak evet. Ancak ECMA 6 ve 7'de işler daha karmaşıktır (bkz. Lambdalar, sınıflar, vb.).
Dávid Horváth

164

Daniel Howard'ın cevabına ek olarak, işte ne new(veya en azından öyle görünüyor):

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;
}

Süre

var obj = New(A, 1, 2);

eşittir

var obj = new A(1, 2);

73
Javascript'in İngilizce'den daha kolay anlaşıldığını
gördüm

Mükemmel cevap. Küçük bir sorum var: Nasıl olmak mümkün func.prototypeolabilir null? Bu konuda biraz ayrıntı verebilir misiniz?
Tom Pažourek

6
@tomp sadece yazarak prototip özelliğini geçersiz kılabilirsiniz A.prototype = null;Bu durumda new A()nesneye neden olur, bu iç prototip Objectnesneye işaret eder : jsfiddle.net/Mk42Z
basilikum

2
Bir host nesnesi "nesne" veya "işlev" den farklı bir şey üretebileceğinden, typeof check yanlış olabilir. Bir şeyin nesne olup olmadığını test etmek için tercih ederim Object(ret) === ret.
Oriol

2
@Oriol yorum için teşekkür ederim. Söyledikleriniz doğrudur ve herhangi bir gerçek test daha sağlam bir şekilde yapılmalıdır. Ancak, bu kavramsal cevap için, typeoftest sadece perde arkasında neler olduğunu anlamayı kolaylaştırıyor.
basilikum

109

Yeni başlayanlar için daha iyi anlamak için

tarayıcı konsolunda aşağıdaki kodu deneyin.

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

Artık topluluk wiki cevabını okuyabilirsiniz :)


4
İyi cevap. Ayrıca - dışarıda bırakmak return this;aynı çıktıyı verir.
Nelu

37

bu yüzden muhtemelen nesne örnekleri oluşturmak için değil

Tam olarak bunun için kullanılır. Bir işlev yapıcısını şu şekilde tanımlarsınız:

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

var john = new Person('John');

Bununla birlikte, ECMAScript'in sahip olduğu ekstra fayda, .prototypemülkle genişletebilmenizdir , böylece ...

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

Bu kurucudan oluşturulan tüm nesneler artık getNameerişebilecekleri prototip zincirinden dolayı olacaktır.


6
işlev yapıcılar sınıflar gibi kullanılır, classanahtar kelime yoktur, ancak hemen hemen aynı şeyi yapabilirsiniz.
meder omuraliev

Orada bir sınıf anahtar kelime var - sınıf ileride kullanılmak üzere ayrılmıştır
Greg

11
Bu nedenle bir CSS sınıfı ayarlamak için .className değil .class kullanıyorsunuz
Greg

23
Sözleşmeyle Kişi tarafından büyük harfle yazılmalıdır.
2013

27

JavaScript olan bir nesne yönelimli programlama dili ve örneklerini oluşturmak için tam olarak kullanılır. Sınıf temelli olmaktan ziyade prototip temellidir, ancak bu nesne yönelimli olmadığı anlamına gelmez.


6
JavaScript'in tüm bu sınıf tabanlı dillerden daha nesne yönelimli olduğunu söylemek isterim. JavaScript'te yazdığınız her şey hemen bir nesne haline gelir, ancak sınıf tabanlı dillerde önce bildirimler yazarsınız ve ancak daha sonra belirli sınıf örnekleri (nesneler) oluşturursunuz. JavaScript prototipi, sınıf tabanlı diller için tüm VTABLE öğelerini belirsiz bir şekilde hatırlatıyor gibi görünüyor.
JustAMartin

14

Javascript, nesne yönelimli programlama paradigmasını destekleyen dinamik bir programlama dilidir ve yeni nesne örnekleri oluşturmak için kullanılır.

Sınıflar nesneler için gerekli değildir - Javascript prototip tabanlı bir dildir.


12

Zaten bazı çok iyi cevaplar var, ancak aşağıdaki III . Davadaki gözlemimi vurgulamak için yeni bir mesaj yayınlıyorum new. Aşağıdaki durumlara bir göz atın:

Durum I :

var Foo = function(){
  this.A = 1; 
  this.B = 2;
};
console.log(Foo()); //prints undefined
console.log(window.A); //prints 1

Yukarıda işaret edilen anonim işlevi çağırmak için basit bir durum Foo. Bu işlevi çağırdığınızda geri döner undefined. Açık bir dönüş ifadesi olmadığından, JavaScript yorumlayıcısı return undefined;işlevin sonuna zorla bir ifade ekler . Burada pencere thisyeni Ave Bözellikleri alan çağırma nesnesidir (bağlamsal ) .

Durum 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

Burada newanahtar kelimeyi gören JavaScript yorumlayıcısı this, anonim işlevin işaretleme nesnesi (bağlamsal ) olarak işlev gören yeni bir nesne oluşturur Foo. Bu durumda Ave Byeni oluşturulan nesnenin özellikleri haline (pencere nesnesi yerine). Açık bir dönüş ifadeniz olmadığından, JavaScript yorumlayıcısı, newanahtar kelime kullanımı nedeniyle oluşturulan yeni nesneyi döndürmek için zorla bir dönüş ifadesi ekler .

Durum 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.

Burada yine newanahtar kelimeyi gören JavaScript yorumlayıcısı this, anonim işlevin işaretleme nesnesi (bağlamsal ) olarak işlev gören yeni bir nesne oluşturur Foo. Tekrar Ave Byeni oluşturulan nesnenin özellikleri haline gelir. JavaScript yorumlayıcısı böylece Ama bu sefer açık bir dönüş bildirimde değil kendi şey yapmak.

III durumunda dikkat edilmesi gereken şey, newanahtar kelime nedeniyle oluşturulan nesnenin radarınızdan kaybolmasıdır. baraslında tamamen farklı bir nesneye işaret ediyor, bu da newanahtar kelime nedeniyle JavaScript yorumlayıcısının oluşturduğu nesne değil .

David Flanagan'dan JavaScripit'ten alıntı: The Definitive Guide (6. Baskı), Ch. 4, Sayfa # 62:

Bir nesne oluşturma ifadesi değerlendirildiğinde, JavaScript ilk önce tıpkı {} nesne başlatıcısı tarafından oluşturulan gibi yeni bir boş nesne oluşturur. Ardından, yeni nesneyi bu anahtar kelimenin değeri olarak ileterek belirtilen işlevi belirtilen bağımsız değişkenlerle çağırır. İşlev daha sonra yeni oluşturulan nesnenin özelliklerini başlatmak için bunu kullanabilir. Yapıcı olarak kullanılmak üzere yazılan işlevler bir değer döndürmez ve nesne oluşturma ifadesinin değeri yeni oluşturulan ve başlatılan nesnedir. Bir kurucu bir nesne değeri döndürürse, bu değer nesne oluşturma ifadesinin değeri olur ve yeni oluşturulan nesne atılır.

--- Ek Bilgi ---

Yukarıdaki durumlarda kod snippet'inde kullanılan işlevlerin JS dünyasında aşağıdaki gibi özel adları vardır:

Durum I ve II - Yapıcı işlevi

Durum III - Fabrika fonksiyonu. Fabrika fonksiyonları olmamalı kullanılmalıdır newGeçerli iş parçacığı kavramını açıklamak için yaptık anahtar kelime.

Bunlar arasındaki farkı bu başlıkta okuyabilirsiniz .


sizin durum 3, bir gr8 gözlem
appu

5

bazen kod kelimelerden daha kolaydır:

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

benim için, prototip olmadığı sürece, fonksiyonun içinde ve dışında bana biraz daha esneklik sağladığı için func2 stilini kullanıyorum.


3
B1 = new func2(2); <- Neden böyle olmayacak B1.y ?
sunny_dev

@sunny_dev Ben JS uzman değilim, ama muhtemelen çünkü FUNC2 (bu) iç değerlerle dönen / a değerini doğrudan (z nesnesi) dönen yerine çalışıyor
Kartal

5

newKelime işlevi çalıştırılıyor altında içeriğini değiştirir ve bu bağlamda bir işaretçiyi geri döndürmektedir.

newAnahtar kelimeyi kullanmadığınızda, işlevin Vehicle()çalıştığı bağlam, Vehicleişlevi çağırdığınız bağlamla aynıdır . thisAnahtar kelime aynı bağlamda ilgili olacak. Kullandığınızda , işlevin içindeki new Vehicle()anahtar kelimenin thisyeni bağlamı göstermesi için yeni bir bağlam oluşturulur. Karşınıza çıkan şey yeni oluşturulan bağlamdır.


Bu, kapsam açısından çok anlayışlı bir cevap. Gr8 yanıtı ek.
appu

3

newAnahtar kelime yeni nesne örnekleri oluşturma içindir. Ve evet, javascript, nesne yönelimli programlama paradigmasını destekleyen dinamik bir programlama dilidir. Nesne adlandırma ile ilgili kural, yeni anahtar kelime tarafından somutlaştırılması beklenen nesneler için her zaman büyük harf kullanmaktır.

obj = new Element();

2

Özet:

newAnahtar kelime bir yapıcı işlevi bir nesne oluşturmak için javascript kullanılmaktadır. newAnahtar kelime yapıcı işlevi çağrısından önce yerleştirilmek zorundadır ve şunları yapar:

  1. Yeni bir nesne oluşturur
  2. Bu nesnenin prototipini yapıcı işlevinin prototip özelliğine ayarlar
  3. Bağlanır thisyeni oluşturulan nesneye anahtar kelime ve yapıcı işlevini yürütür
  4. Yeni oluşturulan nesneyi döndürür

Misal:

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

const doggie = new Dog(12);

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

Tam olarak ne olur:

  1. const doggie diyor: Bir değişkeni bildirmek için belleğe ihtiyacımız var.
  2. Değerlendirme operatörü =der ki: Bu değişkeni,=
  3. İfade new Dog(12). JS motoru yeni anahtar kelimeyi görür, yeni bir nesne oluşturur ve prototipi Dog.prototype olarak ayarlar
  4. Yapıcı işlevi, thisyeni nesneye ayarlanan değerle yürütülür . Bu adımda, yaş yeni oluşturulan köpek nesnesine atandı.
  5. Yeni oluşturulan nesne döndürülür ve değişken köpek için atanır.

1

newAnahtar kelime yapıcı olarak işlevleri kullanarak nesnelerin örneklerini oluşturur. Örneğin:

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

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

Örnekler prototypeyapıcı işlevinden miras alır . Yukarıdaki örnek göz önüne alındığında ...

foo.bar; // 'bar'

2
Yeni anahtar kelime temel olarak işlevi zaten yapıcı olarak ilişkilendirir; hiçbir şey iade etmeniz gerekmez. Şunları yapabilirsiniz: function foo (x) {this.bar = x; } var obj = yeni foo (10); uyarısı (obj.bar);
reko_t

Özellikle bir amaç için istemediğiniz sürece, yapıcı işlevinden nesne döndürmeniz gerekmez. Örneğin, her seferinde yeni bir nesne oluşturmak yerine belirli bir nesne örneğini döndürmeniz gerekiyorsa (herhangi bir nedenle). Ancak örneğinizde, bu tamamen gereksizdir.
Chetan Sastry

Bir örnekti. Sen edebilir bir nesne döndürür. Bu senaryoda kullanılan birçok örüntü var, bunlara "örneğin", dolayısıyla kelimelerim "örneğin" olarak verdim.
göz kapağısızlığı

1

Si başına JavaScript her zaman orijinal şartname EcmaScript'in bir uygulaması olduğundan platformdan platforma büyük farklılıklar gösterebilir.

Her durumda, uygulamadan bağımsız olarak EcmaScript spesifikasyonu hakkını izleyen tüm JavaScript uygulamaları size Nesneye Yönelik Bir Dil verecektir. ES standardına göre:

ECMAScript, bir ana bilgisayar ortamında hesaplama yapmak ve hesaplama nesnelerini değiştirmek için nesneye yönelik bir programlama dilidir.

Artık JavaScript'in EcmaScript'in bir uygulaması olduğunu ve bu nedenle nesneye yönelik bir dil olduğunu kabul ettik. newHerhangi bir Nesne yönelimli dilde işlemin tanımı, böyle bir anahtar kelimenin belirli bir sınıftan (C # gibi anonim türler dahil) bir nesne örneği oluşturmak için kullanıldığını belirtir.

EcmaScript'te, spesifikasyonlardan okuyabileceğiniz gibi sınıfları kullanmıyoruz:

ECMAScript, C ++, Smalltalk veya Java gibi sınıfları kullanmaz. Bunun yerine, nesneler, değişmez bir gösterim yoluyla veya nesneleri oluşturan ve daha sonra özelliklerine başlangıç ​​değerleri atayarak bunların tümünü veya bir kısmını başlatan kodu yürüten yapıcılar aracılığıyla çeşitli yollarla oluşturulabilir. Her yapıcı, prototip tabanlı kalıtım ve paylaşılan özellikleri uygulamak için kullanılan - prototip ‖ adlı bir özelliğe sahip bir işlevdir. Nesneler,
yeni ifadelerde yapıcılar kullanılarak oluşturulur ; örneğin, yeni Tarih (2009,11) yeni bir Tarih nesnesi oluşturur. Bir kurucuyu yeni kullanmadan çağırmanın, kurucuya bağlı sonuçları vardır. Örneğin, Date (), bir nesne yerine geçerli tarih ve saatin dize olarak temsilini üretir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.