Reflect nesnesi JavaScript'te ne yapar?


91

Bir süre önce Reflectjavascript'teki nesne için MDN'de boş bir saplama gördüm ama hayatım boyunca Google'da hiçbir şey bulamıyorum. Bugün bunu http://people.mozilla.org/~jorendorff/es6-draft.html#sec-reflect-object buldum nesnesini ve bölge ve yükleyici işlevselliğinden ayrı olarak Proxy nesnesine benziyor.

Temel olarak, bulduğum bu sayfanın yalnızca Reflect'in nasıl uygulanacağını açıklayıp açıklamadığını veya sadece ifadelerini anlayamadığımı bilmiyorum. Lütfen birisi bana genel olarak hangi yöntemlerin ne olduğunu açıklayabilir mi?Reflect mi?

Örneğin, bulduğum sayfada aramanın Reflect.apply ( target, thisArgument, argumentsList ) "thisArgument ve argümanlar ile [[Call]] dahili hedef yöntemini çağırmanın sonucunu döndüreceğini söylüyor. ama bunun sadece aramaktan farkı ne target.apply(thisArgument, argumentsList)?

Güncelleme:

@Blue sayesinde, bu sayfayı wiki http://wiki.ecmascript.org/doku.php?id=harmony:reflect_api&s=reflect'te buldum, bildiğim kadarıyla, yansıyan nesnenin tüm yöntemlerin iletmeyi kolaylaştırmak için proxy'ler tarafından yakalanabilecek eylemler. Ama bunun tamamen gerekli olduğunu anlamadığım için bu bana biraz tuhaf geliyor. Ama bundan biraz daha fazlasını yapıyor gibi görünüyor, özellikle double-liftingde eski proxy spesifikasyonuna işaret eden par.


1
Spec "nesne tek sıradan nesnedir yansıtın." Diyor, benim anlayış için Reflectsadece bir kapsayıcıdır Realmve Loadernesneler, ama ikincisi ikisini de bilmiyorum.
simonzack

Teşekkürler :), Bağlandığım sayfadan (ne kadar meşru olduğunu bilmiyorum) her Realm kendi "java betiği bağlamı" gibi görünüyor ve bir yükleyici, yansıtma arasındaki benzerliklere dayalı olarak, modüller gibi Realms yüklüyor. ve proxy ve proxy türünün yerleşik işlevsellikte "aşırı yükler" olması, modülün aşırı yükleme işlevselliği ile ilgili olabilir Reflect.Loaderve olabilir Reflect.Realmmi?
Jim Jones

1
Böyle görünüyor statik yöntemleri ile (JSON gibi) 'statik sınıf' var: isExtensible, ownKeysvb yılında ES 6, gerçek sınıfları ile, bu (daha bir sınıf hakkında bilgi edinmek faydalıdır targetiçinde 16.1.2 sanırım).
Rudie

Yanıtlar:


131

GÜNCELLEME 2015: As tarafından işaret 7 'nin cevabı , şimdi ES6 (2015 ECMAScript) sonuçlandığı kamuya, daha uygun dokümantasyon artık kullanılabilir:


Orijinal cevap ((tarihsel) anlayış ve ekstra örnekler için) :

Reflection proposalİlerlemiştir görünüyor Taslak ECMAScript 6 Şartname . Bu belge şu anda Reflect-nesnenin yöntemlerini özetlemektedir ve yalnızca Reflect-nesnenin kendisi hakkında şunları belirtmektedir:

Yansıtma nesnesi tek bir sıradan nesnedir.

Reflect nesnesinin [[Prototype]] dahili yuvasının değeri, standart yerleşik Object prototip nesnesidir (19.1.3).

Reflect nesnesi bir işlev nesnesi değildir. [[Construct]] dahili bir metodu yoktur; Reflect nesnesini yeni operatörle bir yapıcı olarak kullanmak mümkün değildir . Reflect nesnesinin ayrıca bir [[Call]] dahili yöntemi yoktur; Reflect nesnesini bir işlev olarak çağırmak mümkün değildir.

Ancak, ES Harmony'de amacına dair kısa bir açıklama var :

"@Reflect" modülü birden çok amaca hizmet eder:
  • Artık modüllerimiz olduğuna göre, "@reflect" modülü, daha önce Object üzerinde tanımlanmış yansıtma yöntemlerinin çoğu için daha doğal bir yerdir. Geriye dönük uyumluluk amaçları için, Object üzerindeki statik yöntemlerin kaybolması pek olası değildir. Ancak, yeni yöntemler muhtemelen Object yapıcısından ziyade “@reflect” modülüne eklenmelidir.
  • Küresel bir Proxy bağlama ihtiyacını ortadan kaldıran proxy'ler için doğal bir yuva.
  • Bu modüldeki çoğu yöntem, Proxy tuzaklarıyla bire bir eşleşir. Proxy işleyicileri, aşağıda gösterildiği gibi işlemleri uygun şekilde iletmek için bu yöntemlere ihtiyaç duyar.



Dolayısıyla, Reflectnesne, birçoğu genel Nesnede tanımlanan ES5 yöntemleriyle örtüşüyor gibi görünen bir dizi yardımcı program işlevi sağlar.

Ancak bu, çözmeyi amaçladığı mevcut sorunları veya hangi işlevselliğin eklendiğini gerçekten açıklamıyor. Bunun yanıltılabileceğinden şüpheleniyordum ve aslında, yukarıdaki armoni spesifikasyonu , 'bu yöntemlerin normatif olmayan, yaklaşık uygulaması' ile bağlantılı .

Bu kodu incelemek, kullanımı hakkında (daha fazla) fikir verebilir, ancak şükürler olsun ki Reflect nesnesinin neden yararlı olduğunun birkaç nedenini özetleyen bir wiki var :
(Aşağıdaki metni, bundan sonra referans olması için kopyaladım (ve biçimlendirdim) kaynak çünkü bulabildiğim tek örnek bunlar . Bunun yanı sıra, mantıklı, zaten iyi bir açıklamaları var ve sorunun applyörneğine dokunuyorlar .)


Daha kullanışlı dönüş değerleri

Reflectİçindeki birçok işlem, ve Objectgibi üzerinde tanımlanan ES5 işlemlerine benzer . Bununla birlikte, özellik başarıyla tanımlandığında veya başka bir şekilde atıldığında geri döneceği için , yalnızca özelliğin başarıyla tanımlanıp tanımlanmadığını gösteren bir boole döndürmek için belirtilir. Bu, bu kodu yeniden düzenlemenizi sağlar:Reflect.getOwnPropertyDescriptorReflect.definePropertyObject.defineProperty(obj, name, desc)objTypeErrorReflect.defineProperty(obj, name, desc)

try {
  Object.defineProperty(obj, name, desc);
  // property defined successfully
} catch (e) {
  // possible failure (and might accidentally catch the wrong exception)
}

Buna:

if (Reflect.defineProperty(obj, name, desc)) {
  // success
} else {
  // failure
}

Böyle bir mantıksal başarı durumu döndüren diğer yöntemler, Reflect.set(bir özelliği güncellemek için), Reflect.deleteProperty(bir özelliği silmek için), Reflect.preventExtensions(bir nesneyi genişletilemez hale getirmek için) ve Reflect.setPrototypeOf(bir nesnenin prototip bağlantısını güncellemek için).


Birinci sınıf işlemler

ES5'te, bir nesnenin objbelirli bir özellik adını tanımlayıp tanımlamadığını veya miras aldığını tespit etmenin yolu yazmaktır (name in obj). Benzer şekilde, bir özelliği silmek için kullanılır delete obj[name]. Adanmış sözdizimi güzel ve kısa olsa da, aynı zamanda işlemi birinci sınıf bir değer olarak iletmek istediğinizde bu işlemleri işlevlere açıkça sarmanız gerektiği anlamına gelir.

İle Reflect, bu işlemler birinci sınıf işlevler olarak kolayca tanımlanır:
Reflect.has(obj, name)işlevsel eşdeğeridir (name in obj)ve Reflect.deleteProperty(obj, name)aynı şeyi yapan bir işlevdirdelete obj[name].


Daha güvenilir fonksiyon uygulaması

ES5'te, fbir dizi olarak paketlenmiş değişken sayıda argüman içeren argsve thisdeğeri bağlayan bir işlevi çağırmak istendiğinde obj, şöyle yazılabilir:

f.apply(obj, args)

Ancak, fkasıtlı veya kasıtsız olarak kendi applyyöntemini tanımlayan bir nesne olabilir . Yerleşik applyişlevin çağrıldığından gerçekten emin olmak istediğinizde , genellikle şöyle yazar:

Function.prototype.apply.call(f, obj, args)

Bu sadece ayrıntılı değil, anlaşılması da hızla zorlaşıyor. İle Reflectartık daha kısa ve anlaşılması daha kolay bir şekilde güvenilir bir işlev çağrısı yapabilirsiniz:

Reflect.apply(f, obj, args)


Değişken bağımsız değişken yapıcıları

Değişken sayıda argüman içeren bir yapıcı işlevi çağırmak istediğinizi düşünün. ES6'da, yeni yayılma sözdizimi sayesinde, aşağıdaki gibi kod yazmak mümkün olacaktır:

var obj = new F(...args)

ES5, bir tek kullanabilirsiniz çünkü bu, zor yazma etmektir F.applyveya F.callbağımsız değişken bir sayı ile bir işlevi çağırmak için, ama hiç yoktur F.constructişlev newbağımsız değişken bir sayı ile fonksiyonu. İle Reflectartık ES5'te yazılabilir:

var obj = Reflect.construct(F, args)


Proxy tuzakları için varsayılan yönlendirme davranışı

Kullanırken Proxymevcut nesneleri sarmak için nesneleri, bir şeyler yapma ve sonra sarılmış nesneye dinlenen operasyonu uygulamak genellikle "varsayılan şey yapmak" na, bir operasyon yolunu kesmek için çok yaygındır. Örneğin, bir nesneye tüm özellik erişimlerini kaydetmek istediğimi varsayalım obj:

var loggedObj = new Proxy(obj, {
  get: function(target, name) {
    console.log("get", target, name);
    // now do the default thing
  }
});

ReflectVe ProxyAPI'ler tandem tasarlanan her biri için öyle ki, Proxyüzerine tuzak, karşılık gelen bir yöntem vardır Reflecto "varsayılan şeyi yapar". Bu nedenle, bir Proxy işleyicisi içinde "varsayılanı yapmak" istediğiniz her zaman, yapılacak doğru şey, her zaman Reflectnesnede karşılık gelen yöntemi çağırmaktır :

var loggedObj = new Proxy(obj, {
  get: function(target, name) {
    console.log("get", target, name);
    return Reflect.get(target, name);
  }
});

Dönüş türü Reflectyöntemleri dönüş türü ile uyumlu olması sağlanır Proxytuzaklar.


Erişimcilerin bu bağlamasını kontrol edin

ES5'te genel bir mülk erişimi veya mülk güncellemesi yapmak oldukça kolaydır. Örneğin:

var name = ... // get property name as a string
obj[name] // generic property lookup
obj[name] = value // generic property update

Reflect.getVe Reflect.setyöntemleri aynı şeyi, ama ayrıca bir son isteğe bağlı argüman olarak bir kabul etmesine izin receiveraçıkça ayarlamak için olanak sağlar parametresini thisözelliği almak zaman -bağlayıcı / set bir erişimci geçerli:

var name = ... // get property name as a string
Reflect.get(obj, name, wrapper) // if obj[name] is an accessor, it gets run with `this === wrapper`
Reflect.set(obj, name, value, wrapper)

Bu, bazen sarmaladığınızda objve erişimcideki herhangi bir kendi kendine göndermenin sarmalayıcınıza yeniden yönlendirilmesini istediğinizde yararlıdır , örneğin obj:

var obj = {
  get foo() { return this.bar(); },
  bar: function() { ... }
}

Arama Reflect.get(obj, "foo", wrapper), this.bar()aramanın adresine yeniden yönlendirilmesine neden olur wrapper.


Mirastan kaçının __proto__

Bazı tarayıcılarda, __proto__bir nesnenin prototipine erişim sağlayan özel bir özellik olarak tanımlanır. ES5 Object.getPrototypeOf(obj), prototipi sorgulamak için yeni bir yöntemi standartlaştırdı . Reflect.getPrototypeOf(obj)tam olarak aynı şeyi yapar, ancak bu Reflectaynı zamanda Reflect.setPrototypeOf(obj, newProto)nesnenin prototipini ayarlamak için bir karşılık gelen tanımlar . Bu, bir nesnenin prototipini güncellemenin ES6 uyumlu yeni yoludur.
: O Not setPrototypeOf ayrıca üzerinde varObject (doğru tarafından işaret edildiği gibi KNU 'ın comment )!


DÜZENLEME:
Yan not ( S'ye yapılan yorumları ele alır) : AçıklayanRealms ve Loadernesneleri açıklayan 'S: ES6 Modülleri ve HTML İçe Aktarmaları' üzerine kısa ve basit bir cevap var .

Bu bağlantıda başka bir açıklama sunulmaktadır :

Bir bölge nesnesi, kendi küresel nesnesi, standart kitaplığın kopyası ve "içsel" (Object.prototype'nin başlangıç ​​değeri gibi küresel değişkenlere bağlı olmayan standart nesneler) ile ayrı bir küresel ortam kavramını özetler.

Genişletilebilir web : Bu, <iframe>DOM olmadan aynı orijinin dinamik eşdeğeridir .

Yine de bahsetmeye değer: tüm bunlar hala taslak halinde, bu taşa kazınmış bir özellik değil! ES6, bu nedenle tarayıcı uyumluluğunu aklınızda bulundurun!

Bu yardımcı olur umarım!


@Spencer Killen: Eh .. bu cevap doğru yönde düşüncelerinizi işaret ve bu arasındaki fark nasıl ilişkili açıklama yapmayan Reflect.applyve target.apply? Ya da ödül bitmeden ne eklemeliyim?
GitaarLAB

2
setPrototypeOf da var Object.
Knu

1
Reflect.getPrototip özelliklerine sahip bir nesneye proxy kullanıyorsanız , proxy get için varsayılan uygulama olarak kullanmanın iyi çalışmadığını unutmayın. Sadece işe yaramadığından şikayet ediyor. Ancak, yerine Reflect.get(target, property)geçmeden kullanırsanız receiver, o zaman işe yarar .
CMCDragonkai

Özelliklere her zaman proxy aracılığıyla eriştiğiniz testlerim , proxy'nin kendisiyken targetproxy'nin sarmaladığı orijinal hedef olduğu bir durumla sonuçlanır receiver. Ancak, mülklere farklı şekilde erişmeyi başarırsanız, yine bu farklı olabilir.
CMCDragonkai

Bu harika bir cevap! Teşekkürler
rpivovar

5

Wiki'de bulunan taslak belgeye göre,

http://wiki.ecmascript.org/doku.php?id=harmony:specification_drafts

Taslakta açıklığa kavuşturduğu "tek sıradan nesne" dizisini alıyoruz. Aynı zamanda fonksiyon tanımlarına da sahiptir.

Emcascript web sitesinden bir bağlantı bulabileceğiniz için wiki güvenilir olmalıdır.

http://www.ecmascript.org/dev.php

Yine de ilk bağlantıyı google tarafından buldum ve doğrudan wiki'de arama yaparak bulma şansım olmadı.


Teşekkürler, resmi şartnamede listelenen her yöntem çağrıldığında atılan adımlar, bağlantımdakilerle hemen hemen aynı görünüyor, ancak yine de her yöntemin, örneğin Reflect altında çağrıldığında ne yaptığını anlayamıyorum. Listelenen adımları uygulayın 4. PrepareForTailCall özet işlemini gerçekleştirin. 5. thisArgument argümanlarıyla [[Call]] dahili hedef yöntemini çağırmanın sonucunu ve args ------- bu ne anlama geliyor?
Jim Jones

Baktığımdan en iyi tahminim, 4. adımdaki kuyruk özyinelemesine referans olduğu ve 5. adımın prototip fonksiyonuna bir referans olduğu. Görünüşe göre genel fikir, uygulama yönteminin uygulandığı (adım 1-2), hata tutamacı (adım 3) üzerinde çalışıp çalışmadığını doğrulamak ve ardından uygulama işlevinin çalıştırıldığını doğrulamaktır (adım 4-5). Belgeleri taramaktan en iyi tahminim, Reflect modülünün amacının, nesnenin bir tür iç gözlemini gerektiren işlevselliği yaptığınız zamandır. Çağrının kullanılması da muhtemelen neden "[[Call]] dahili yöntemine sahip olmadığıdır".
Blue
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.