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
และProxy
APIs ได้รับการออกแบบควบคู่เช่นว่าสำหรับแต่ละ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
วัตถุ แต่ฉันไม่รู้ว่าสิ่งหลังทำเช่นกัน