경고 : 이것은 긴 글입니다.
간단하게 유지합시다. 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
해결책은 서투른 것처럼 보이고 "악한 평가"의 모든 문제와 함께 제공됩니다.__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();
따라서 위의 솔루션은 변수 no를 허용하는 "true"생성자를 제공합니다. 의 인수 및 필요하지 않습니다 new
. 이것에 대한 당신의 취향은 무엇입니까?
-업데이트-
일부는 "그냥 오류를 던져"라고 말했다. 내 대답은 : 우리는 10 개 이상의 생성자로 무거운 앱을 만들고 있으며 모든 생성자가 콘솔에 오류 메시지를 던지지 않고 그 실수를 "똑똑하게"처리 할 수 있다면 훨씬 더 힘들 것이라고 생각합니다.
Make()
없이 new
만들기는 대문자 때문에, 따라서 그것은 생성자입니다 가정
new
있습니까? 아니면 코드를 줄 누군가를 찾고 있습니까? 후자 인 경우 잘못된 사이트를 묻는 것일 수 있습니다. 전자의 경우 새로운 것을 사용하고 오류를 너무 빨리 감지하는 것과 관련된 제안을 무시하고 싶지 않을 수 있습니다 ... 앱이 정말로 "무거운"경우, 마지막으로 원하는 것은 속도를 늦추기위한 과도하게 구축 된 메커니즘입니다. new
그것이 얻는 모든 측면에서 꽤 빠릅니다.