คำเตือน: นี่เป็นเรื่องยาว
ขอให้มันง่าย ฉันต้องการหลีกเลี่ยงคำนำหน้าโอเปอเรเตอร์ใหม่ทุกครั้งที่ฉันเรียกนวกรรมิกใน JavaScript นี่เป็นเพราะฉันมักจะลืมมันและรหัสของฉันก็แย่มาก
วิธีง่ายๆในการนี้คือ ...
function Make(x) {
if ( !(this instanceof arguments.callee) )
return new arguments.callee(x);
// do your stuff...
}
แต่ฉันต้องการสิ่งนี้เพื่อยอมรับตัวแปร ของการโต้แย้งเช่นนี้ ...
m1 = Make();
m2 = Make(1,2,3);
m3 = Make('apple', 'banana');
ทางออกแรกทันทีน่าจะเป็นวิธี 'สมัคร' เช่นนี้ ...
function Make() {
if ( !(this instanceof arguments.callee) )
return new arguments.callee.apply(null, arguments);
// do your stuff
}
นี้เป็นธรรม แต่ - วัตถุใหม่จะถูกส่งผ่านไปยังวิธีการและไม่ให้คอนสตรัคของเราapply
arguments.callee
ตอนนี้ฉันได้คำตอบสามข้อ คำถามง่ายๆของฉันคือคำถามข้อใดที่ดูเหมือนดีที่สุด หรือถ้าคุณมีวิธีที่ดีกว่าบอกมัน
ก่อนอื่น - ใช้eval()
เพื่อสร้างรหัส JavaScript ที่เรียกใช้นวกรรมิก
function Make(/* ... */) {
if ( !(this instanceof arguments.callee) ) {
// collect all the arguments
var arr = [];
for ( var i = 0; arguments[i]; i++ )
arr.push( 'arguments[' + i + ']' );
// create code
var code = 'new arguments.callee(' + arr.join(',') + ');';
// call it
return eval( code );
}
// do your stuff with variable arguments...
}
สอง - วัตถุทุกชิ้นมี__proto__
คุณสมบัติซึ่งเป็นลิงค์ 'ความลับ' ไปยังวัตถุต้นแบบ โชคดีที่คุณสมบัตินี้สามารถเขียนได้
function Make(/* ... */) {
var obj = {};
// do your stuff on 'obj' just like you'd do on 'this'
// use the variable arguments here
// now do the __proto__ magic
// by 'mutating' obj to make it a different object
obj.__proto__ = arguments.callee.prototype;
// must return obj
return obj;
}
สาม - นี่คือสิ่งที่คล้ายกับโซลูชันที่สอง
function Make(/* ... */) {
// we'll set '_construct' outside
var obj = new arguments.callee._construct();
// now do your stuff on 'obj' just like you'd do on 'this'
// use the variable arguments here
// you have to return obj
return obj;
}
// now first set the _construct property to an empty function
Make._construct = function() {};
// and then mutate the prototype of _construct
Make._construct.prototype = Make.prototype;
eval
การแก้ปัญหาดูเหมือนเงอะงะและมาพร้อมกับปัญหาทั้งหมดของ "ความชั่วร้าย eval"__proto__
โซลูชันไม่ได้มาตรฐานและ "Great Browser of mIsERY" ไม่ให้เกียรติวิธีที่สามดูเหมือนซับซ้อนเกินไป
แต่ด้วยวิธีแก้ปัญหาทั้งสามข้อที่กล่าวมาข้างต้นเราสามารถทำสิ่งนี้ได้ซึ่งเราไม่สามารถทำได้ ...
m1 = Make();
m2 = Make(1,2,3);
m3 = Make('apple', 'banana');
m1 instanceof Make; // true
m2 instanceof Make; // true
m3 instanceof Make; // true
Make.prototype.fire = function() {
// ...
};
m1.fire();
m2.fire();
m3.fire();
วิธีแก้ปัญหาข้างต้นทำให้เรามีประสิทธิภาพ "ของจริง" คอนสตรัคเตอร์ที่รับหมายเลขตัวแปร new
ของการขัดแย้งและไม่จำเป็นต้อง คุณทำอะไรกับเรื่องนี้
- อัปเดต -
บางคนบอกว่า "เพิ่งโยนข้อผิดพลาด" คำตอบของฉันคือ: เรากำลังทำแอพหนักกับตัวสร้าง 10+ ตัวและฉันคิดว่ามันคงจะเป็นงานที่หนักหนากว่าถ้าตัวสร้างทุกตัวสามารถ "ฉลาด" จัดการกับข้อผิดพลาดนั้นได้โดยไม่ต้องทิ้งข้อความแสดงข้อผิดพลาดบนคอนโซล
Make()
โดยไม่ต้องnew
เพราะทำคือพิมพ์ใหญ่และดังนั้นจึงถือว่าเป็นผู้สร้าง
new
? เพราะถ้าเป็นอย่างหลังคุณอาจถามผิดเว็บไซต์ หากเป็นแบบเดิมคุณอาจไม่ต้องการยกเลิกข้อเสนอแนะเกี่ยวกับการใช้ข้อผิดพลาดใหม่และการตรวจจับอย่างรวดเร็ว ... หากแอปของคุณ "หนัก" อย่างแท้จริงสิ่งสุดท้ายที่คุณต้องการคือกลไกการก่อสร้างแบบ overwrought เพื่อทำให้ช้าลง new
สำหรับทุกอย่างที่ได้รับมันค่อนข้างเร็ว