Function 생성자로 Object.prototype 메서드를 재정의 할 때 범위 오류
Object.prototype.toString
추가 클래스 설명에 대한 기능을 추가하기 위해 입찰에서 재정의하려고합니다 .
다음은 초기 코드입니다.
(function(toString){
Object.prototype.toString = function(){
if(this instanceof TestClass)
{
return '[object TestClass]';
}
return toString.apply(this, arguments);
}
})(Object.prototype.toString);
function TestClass(){}
var instance_obj = new TestClass();
Object.prototype.toString.call(instance_obj);
콘솔에서 실행하면 다음과 같은 출력이 표시됩니다.
[object TestClass]
좋은 점은 Object.prototype.toString
작동 방식을 크게 수정하지 않는다는 것입니다 . 따라서 다른 유형 [즉, TestClass가 아님]을 사용하면 예상대로 작동합니다 (예 : Object.prototype.toString.call(12)
will output) [object Number]
.
이 구현은 지금까지 아무런 문제없이 작동합니다. 그러나 다음 코드로 다른 구현이 있습니다.
(function(toString){
var fn_code_str = `return function(){
if(this instanceof TestClass)
{
return '[object TestClass]';
}
return toString.apply(this, arguments);
}`;
var pre_fn = new Function(fn_code_str);
Object.prototype.toString = pre_fn();
})(Object.prototype.toString);
function TestClass(){}
var instance_obj = new TestClass();
Object.prototype.toString.call(instance_obj);
이것으로 TestClass에 대한 적절한 출력을 얻지 만, 같은 다른 것을 사용 12
하면 RangeError가 발생합니다.
VM527:5 Uncaught RangeError: Maximum call stack size exceeded
at Function.[Symbol.hasInstance] (<anonymous>)
at Number.eval (eval at <anonymous> (getElements.html:19), <anonymous>:5:21)
at Number.eval (eval at <anonymous> (getElements.html:19), <anonymous>:10:29)
at Number.eval (eval at <anonymous> (getElements.html:19), <anonymous>:10:29)
at Number.eval (eval at <anonymous> (getElements.html:19), <anonymous>:10:29)
at Number.eval (eval at <anonymous> (getElements.html:19), <anonymous>:10:29)
at Number.eval (eval at <anonymous> (getElements.html:19), <anonymous>:10:29)
at Number.eval (eval at <anonymous> (getElements.html:19), <anonymous>:10:29)
at Number.eval (eval at <anonymous> (getElements.html:19), <anonymous>:10:29)
at Number.eval (eval at <anonymous> (getElements.html:19), <anonymous>:10:29)
이것은 재귀의 문제인 것 같습니다 toString.apply
. 그러나 첫 번째 구현이 그렇지 않은 경우 두 번째 구현이 반복되는 이유를 알 수 없습니다.
참고 :이 두 번째 구현의 이유 if(this instanceof MyClassType){return '[object MyClassType]'}
는 배열의 클래스 이름 목록에서 동적으로 다른 클래스에 대한 유형 검사 코드를 추가하기 위한 것입니다. 즉, 내가 생각 해낸 각각의 새로운 클래스에 대한 코드를 수정하는 대신 배열에 클래스 이름을 추가하면 조건문이 자동으로 생성됩니다.
답변
문제는 toString
IIFE 의 매개 변수가 new Function
코드의 범위에 있지 않다는 것입니다 . 대신 global toString
= window.toString
=를 사용합니다 Object.prototype.toString
.
이 문제를 해결하려면 반환 된 클로저가 작동하도록의 코드 toString
내에서 변수 를 선언해야합니다 new Function
. 간단한 상수로 :
(function() {
var pre_fn = new Function(`
const toString = Object.prototype.toString;
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
return function(){
if(this instanceof TestClass) {
return '[object TestClass]';
}
return toString.apply(this, arguments);
}`);
Object.prototype.toString = pre_fn();
})();
또는 매개 변수로 :
(function() {
var pre_fn = new Function('toString', `
// ^^^^^^^^^^^
return function(){
if(this instanceof TestClass) {
return '[object TestClass]';
}
return toString.apply(this, arguments);
}`);
Object.prototype.toString = pre_fn(Object.prototype.toString);
// ^^^^^^^^^^^^^^^^^^^^^^^^^
})();