UPDATE 2015
ในฐานะที่เป็นแหลมออกโดย7 's คำตอบตอนนี้ที่ ES6 (ECMAScript 2015) ได้รับการสรุปเอกสารที่เหมาะสมมากขึ้นอยู่ในขณะนี้:
คำตอบเดิม (สำหรับความเข้าใจ (ประวัติศาสตร์) และตัวอย่างเพิ่มเติม) :
Reflection proposalดูเหมือนว่าจะมีความคืบหน้าไปยังร่าง ECMAScript 6 จำเพาะ ขณะนี้เอกสารนี้สรุปReflectวิธีการของ -object และระบุเฉพาะสิ่งต่อไปนี้เกี่ยวกับReflect-object เท่านั้น:
วัตถุสะท้อนแสงเป็นวัตถุธรรมดาชิ้นเดียว
ค่าของสล็อตภายใน [[Prototype]] ของวัตถุ Reflect คืออ็อบเจกต์ต้นแบบในตัวมาตรฐาน (19.1.3)
วัตถุสะท้อนไม่ใช่วัตถุฟังก์ชัน ไม่มี [[สร้าง]] วิธีการภายใน; ไม่สามารถใช้วัตถุ Reflect เป็นตัวสร้างร่วมกับตัวดำเนินการใหม่ได้ นอกจากนี้วัตถุ Reflect ยังไม่มีวิธีการภายใน [[Call]] ไม่สามารถเรียกใช้วัตถุสะท้อนเป็นฟังก์ชันได้
อย่างไรก็ตามมีคำอธิบายสั้น ๆ เกี่ยวกับวัตถุประสงค์ในES Harmony :
โมดูล“ @reflect” รองรับวัตถุประสงค์หลายประการ:
- ตอนนี้เรามีโมดูลแล้วโมดูล“ @reflect” เป็นสถานที่ที่เป็นธรรมชาติมากขึ้นสำหรับวิธีการสะท้อนหลายอย่างที่กำหนดไว้ก่อนหน้านี้ใน Object เพื่อวัตถุประสงค์ในการทำงานร่วมกันได้แบบย้อนกลับไม่น่าเป็นไปได้ที่วิธีการคงที่บน Object จะหายไป อย่างไรก็ตามควรเพิ่มเมธอดใหม่ในโมดูล“ @reflect” มากกว่าในตัวสร้างวัตถุ
- บ้านที่เป็นธรรมชาติสำหรับผู้รับมอบฉันทะโดยหลีกเลี่ยงความจำเป็นในการผูกพร็อกซีทั่วโลก
- วิธีการส่วนใหญ่ในโมดูลนี้จะแมปแบบหนึ่งต่อหนึ่งบนกับดักพร็อกซี ตัวจัดการพร็อกซีจำเป็นต้องใช้วิธีการเหล่านี้เพื่อส่งต่อการดำเนินการดังที่แสดงด้านล่าง
ดังนั้นReflectอ็อบเจ็กต์จึงจัดเตรียมฟังก์ชันยูทิลิตี้จำนวนหนึ่งซึ่งหลายฟังก์ชันดูเหมือนจะทับซ้อนกับเมธอด ES5 ที่กำหนดไว้บนโกลบอลอ็อบเจ็กต์
อย่างไรก็ตามนั่นไม่ได้อธิบายว่าปัญหาที่มีอยู่ซึ่งตั้งใจจะแก้ไขหรือเพิ่มฟังก์ชันอะไร ฉันสงสัยว่าสิ่งนี้อาจถูก shimmed และแท้จริงแล้วลิงก์ข้อกำหนดความสามัคคีข้างต้นไปยังไฟล์ 'ไม่ใช่กฎเกณฑ์การดำเนินงานโดยประมาณของวิธีการเหล่านี้'
การตรวจสอบรหัสนั้นสามารถให้แนวคิด (เพิ่มเติม) เกี่ยวกับการใช้งานได้ แต่โชคดีที่ยังมีวิกิที่อธิบายเหตุผลหลายประการว่าทำไมวัตถุ Reflect จึงมีประโยชน์ :
(ฉันได้คัดลอก (และจัดรูปแบบ) ข้อความต่อไปนี้เพื่อใช้อ้างอิงในอนาคตจากนั้น แหล่งที่มาเนื่องจากเป็นตัวอย่างเดียวที่ฉันสามารถหาได้นอกจากนั้นยังมีเหตุผลมีคำอธิบายที่ดีอยู่แล้วและสัมผัสกับapplyตัวอย่างของคำถาม)
ค่าส่งคืนที่มีประโยชน์มากขึ้น
การดำเนินงานจำนวนมากในการReflectมีความคล้ายคลึงกับการดำเนินงานที่กำหนดไว้ใน ES5 Objectเช่นและReflect.getOwnPropertyDescriptor Reflect.definePropertyอย่างไรก็ตามในขณะที่Object.defineProperty(obj, name, desc)จะส่งคืนobjเมื่อคุณสมบัติถูกกำหนดสำเร็จหรือโยนเป็นTypeErrorอย่างอื่นระบุReflect.defineProperty(obj, name, desc)เพียงแค่ส่งคืนบูลีนที่ระบุว่าคุณสมบัติถูกกำหนดสำเร็จหรือไม่ สิ่งนี้ช่วยให้คุณสามารถ refactor รหัสนี้:
try {
Object.defineProperty(obj, name, desc);
} catch (e) {
}
สำหรับสิ่งนี้:
if (Reflect.defineProperty(obj, name, desc)) {
} else {
}
วิธีอื่นที่ส่งคืนสถานะความสำเร็จของบูลีน ได้แก่Reflect.set(เพื่ออัพเดตคุณสมบัติ) Reflect.deleteProperty(เพื่อลบคุณสมบัติ) Reflect.preventExtensions(เพื่อทำให้อ็อบเจ็กต์ไม่สามารถขยายได้) และReflect.setPrototypeOf(เพื่ออัพเดตลิงก์ต้นแบบของอ็อบเจ็กต์)
การดำเนินงานชั้นหนึ่ง
ใน ES5 วิธีตรวจสอบว่าวัตถุobjกำหนดหรือสืบทอดชื่อคุณสมบัติบางอย่างคือการเขียน(name in obj)กำหนดหรือสืบทอดชื่อคุณสมบัติบางอย่างคือการเขียนdelete obj[name]ในทำนองเดียวกันการลบคุณสมบัติอย่างใดอย่างหนึ่งใช้ แม้ว่าไวยากรณ์เฉพาะจะดีและสั้น แต่ก็หมายความว่าคุณต้องรวมการดำเนินการเหล่านี้ไว้ในฟังก์ชันอย่างชัดเจนเมื่อคุณต้องการส่งผ่านการดำเนินการเป็นค่าชั้นหนึ่ง
ด้วยReflectการดำเนินการเหล่านี้จึงถูกกำหนดให้เป็นฟังก์ชันระดับเฟิร์สคลาส:
Reflect.has(obj, name)เทียบเท่ากับฟังก์ชัน(name in obj)และReflect.deleteProperty(obj, name)เป็นฟังก์ชันที่ทำเช่นเดียวกับdelete obj[name].
แอปพลิเคชั่นฟังก์ชั่นที่เชื่อถือได้มากขึ้น
ใน ES5 เมื่อต้องการเรียกใช้ฟังก์ชันที่fมีอาร์กิวเมนต์จำนวนตัวแปรที่บรรจุเป็นอาร์เรย์argsและผูกthisค่าเข้ากับobjเราสามารถเขียน:
f.apply(obj, args)
อย่างไรก็ตามfอาจเป็นวัตถุที่กำหนดapplyวิธีการของตัวเองโดยเจตนาหรือไม่ตั้งใจ เมื่อคุณต้องการให้แน่ใจว่าapplyมีการเรียกใช้ฟังก์ชันในตัวโดยทั่วไปจะเขียนว่า:
Function.prototype.apply.call(f, obj, args)
ไม่เพียง แต่เป็นรายละเอียดเท่านั้น แต่ยังยากที่จะเข้าใจอย่างรวดเร็ว ด้วยReflectตอนนี้คุณสามารถเรียกใช้ฟังก์ชันที่เชื่อถือได้ด้วยวิธีที่สั้นและเข้าใจง่ายขึ้น:
Reflect.apply(f, obj, args)
ตัวสร้างตัวแปร - อาร์กิวเมนต์
สมมติว่าคุณต้องการเรียกใช้ฟังก์ชันตัวสร้างด้วยอาร์กิวเมนต์ที่เป็นตัวแปร ใน ES6 ต้องขอบคุณไวยากรณ์การแพร่กระจายใหม่ทำให้สามารถเขียนโค้ดเช่น:
var obj = new F(...args)
ใน ES5 สิ่งนี้ยากกว่าที่จะเขียนเนื่องจากสามารถใช้F.applyหรือF.callเพื่อเรียกใช้ฟังก์ชันที่มีอาร์กิวเมนต์จำนวนตัวแปรเท่านั้น แต่ไม่มีF.constructฟังก์ชันสำหรับnewฟังก์ชันที่มีจำนวนอาร์กิวเมนต์ตัวแปร ด้วยReflectตอนนี้เราสามารถเขียนใน ES5:
var obj = Reflect.construct(F, args)
พฤติกรรมการส่งต่อเริ่มต้นสำหรับกับดักพร็อกซี
เมื่อใช้Proxyอ็อบเจกต์เพื่อห่ออ็อบเจ็กต์ที่มีอยู่เป็นเรื่องปกติมากที่จะขัดขวางการดำเนินการทำอะไรบางอย่างแล้ว "ทำสิ่งที่เป็นค่าเริ่มต้น" ซึ่งโดยทั่วไปแล้วจะใช้การดำเนินการที่ถูกดักจับกับวัตถุที่ถูกห่อ ตัวอย่างเช่นสมมติว่าฉันต้องการเพียงแค่บันทึกคุณสมบัติทั้งหมดที่เข้าถึงวัตถุobj:
var loggedObj = new Proxy(obj, {
get: function(target, name) {
console.log("get", target, name);
}
});
ReflectและProxyAPIs ได้รับการออกแบบควบคู่เช่นว่าสำหรับแต่ละProxyดักมีอยู่วิธีการที่สอดคล้องกันในการReflectที่ว่า "จะเป็นสิ่งเริ่มต้น" ดังนั้นเมื่อใดก็ตามที่คุณพบว่าตัวเองต้องการ "ทำค่าเริ่มต้น" ภายในตัวจัดการพร็อกซีสิ่งที่ต้องทำคือการเรียกใช้เมธอดที่เกี่ยวข้องในReflectวัตถุเสมอ:
var loggedObj = new Proxy(obj, {
get: function(target, name) {
console.log("get", target, name);
return Reflect.get(target, name);
}
});
Reflectรับประกันประเภทการส่งคืนของวิธีการที่เข้ากันได้กับประเภทการส่งคืนของProxyกับดัก
ควบคุมการเชื่อมโยงนี้ของ accessors
ใน ES5 การเข้าถึงคุณสมบัติทั่วไปหรือการอัปเดตคุณสมบัตินั้นค่อนข้างง่าย ตัวอย่างเช่น:
var name = ...
obj[name]
obj[name] = value
Reflect.getและReflect.setวิธีการช่วยให้คุณทำในสิ่งเดียวกัน แต่ยังยอมรับเป็นอาร์กิวเมนต์ตัวเลือกสุดท้ายreceiverพารามิเตอร์ที่ช่วยให้คุณสามารถตั้งค่าอย่างชัดเจนthis-binding เมื่อทรัพย์สินที่คุณได้รับ / ชุดเป็นเข้าถึง:
var name = ...
Reflect.get(obj, name, wrapper)
Reflect.set(obj, name, value, wrapper)
สิ่งนี้มีประโยชน์ในบางครั้งเมื่อคุณกำลังตัดobjและคุณต้องการให้การส่งด้วยตนเองใด ๆ ภายใน accessor ได้รับการกำหนดเส้นทางใหม่ไปยัง Wrapper ของคุณเช่นหากobjกำหนดเป็น:
var obj = {
get foo() { return this.bar(); },
bar: function() { ... }
}
Calling Reflect.get(obj, "foo", wrapper)จะทำให้เกิดการเรียกร้องให้ได้รับการเปลี่ยนเส้นทางไปยังthis.bar()wrapper
หลีกเลี่ยงมรดก __proto__
ในบางเบราว์เซอร์__proto__ถูกกำหนดให้เป็นคุณสมบัติพิเศษที่ให้การเข้าถึงต้นแบบของวัตถุ ES5 กำหนดวิธีการใหม่ในการObject.getPrototypeOf(obj)สืบค้นต้นแบบเป็นมาตรฐาน Reflect.getPrototypeOf(obj)ทำเหมือนกันทุกประการยกเว้นว่าจะReflectกำหนดสิ่งที่เกี่ยวข้องReflect.setPrototypeOf(obj, newProto)กับการตั้งค่าต้นแบบของวัตถุด้วย นี่เป็นวิธีใหม่ที่สอดคล้องกับ ES6 ในการอัปเดตต้นแบบของวัตถุ
โปรดทราบว่า: setPrototypeOf ยังมีอยู่Object (ตามที่ระบุไว้อย่างถูกต้องตามความคิดเห็นของKnu )!
แก้ไข:
หมายเหตุด้านข้าง (แสดงความคิดเห็นต่อ Q): มีคำตอบสั้น ๆ และเรียบง่ายเกี่ยวกับ 'Q: โมดูล ES6 เทียบกับการนำเข้า HTML'ที่อธิบายRealmsและLoaderวัตถุ
คำอธิบายอื่นมีให้โดยลิงค์นี้ :
วัตถุขอบเขตเป็นนามธรรมแนวคิดของสภาพแวดล้อมโลกที่แตกต่างกันโดยมีอ็อบเจ็กต์ส่วนกลางของตัวเองสำเนาของไลบรารีมาตรฐานและ "intrinsics" (อ็อบเจ็กต์มาตรฐานที่ไม่ถูกผูกไว้กับตัวแปรส่วนกลางเช่นค่าเริ่มต้นของ Object.prototype)
เว็บที่ขยายได้ : เทียบเท่าแบบไดนามิกของแหล่งกำเนิดเดียวกันที่
<iframe>ไม่มี DOM
ที่ควรค่าแก่การกล่าวขวัญ: ทั้งหมดนี้ยังอยู่ในร่างนี่ไม่ใช่คุณสมบัติที่สลักด้วยหิน มันคือ ES6 ดังนั้นโปรดคำนึงถึงความเข้ากันได้ของเบราว์เซอร์!
หวังว่านี่จะช่วยได้!
Reflectเป็นเพียงภาชนะสำหรับRealmและLoaderวัตถุ แต่ฉันไม่รู้ว่าสิ่งหลังทำเช่นกัน