나는 이 질문을 읽고 있었고 함수 래퍼 방법이 아닌 별칭 방법을 시도하고 싶었지만 Firefox 3 또는 3.5beta4 또는 Google Chrome에서 디버그 창과 테스트 웹 페이지에서.
개똥 벌레:
>>> window.myAlias = document.getElementById
function()
>>> myAlias('item1')
>>> window.myAlias('item1')
>>> document.getElementById('item1')
<div id="item1">
웹 페이지에 넣으면 myAlias를 호출하면 다음 오류가 발생합니다.
uncaught exception: [Exception... "Illegal operation on WrappedNative prototype object" nsresult: "0x8057000c (NS_ERROR_XPC_BAD_OP_ON_WN_PROTO)" location: "JS frame :: file:///[...snip...]/test.html :: <TOP_LEVEL> :: line 7" data: no]
Chrome (명확성을 위해 >>>이 삽입 됨) :
>>> window.myAlias = document.getElementById
function getElementById() { [native code] }
>>> window.myAlias('item1')
TypeError: Illegal invocation
>>> document.getElementById('item1')
<div id=?"item1">?
그리고 테스트 페이지에서 동일한 “불법 호출”을 얻습니다.
내가 뭘 잘못하고 있니? 다른 사람이 이것을 재현 할 수 있습니까?
또한 이상하게도 IE8에서 작동합니다.
답변
해당 메서드를 문서 개체에 바인딩해야합니다. 보기:
>>> $ = document.getElementById
getElementById()
>>> $('bn_home')
[Exception... "Cannot modify properties of a WrappedNative" ... anonymous :: line 72 data: no]
>>> $.call(document, 'bn_home')
<body id="bn_home" onload="init();">
간단한 별칭을 수행 할 때 함수는 문서 개체가 아닌 전역 개체에서 호출됩니다. 이 문제를 해결하려면 클로저라는 기술을 사용하십시오.
function makeAlias(object, name) {
var fn = object ? object[name] : null;
if (typeof fn == 'undefined') return function () {}
return function () {
return fn.apply(object, arguments)
}
}
$ = makeAlias(document, 'getElementById');
>>> $('bn_home')
<body id="bn_home" onload="init();">
이렇게하면 원본 개체에 대한 참조가 손실되지 않습니다.
2012 년에는 bind
ES5 의 새로운 방법이 있습니다.이를 통해 더 멋진 방식으로이를 수행 할 수 있습니다.
>>> $ = document.getElementById.bind(document)
>>> $('bn_home')
<body id="bn_home" onload="init();">
답변
이 특정 행동을 이해하기 위해 깊이 파고 들었고 좋은 설명을 찾은 것 같습니다.
별칭을 사용할 수없는 이유를 알아보기 전에 document.getElementById
JavaScript 함수 / 객체의 작동 방식을 설명하려고합니다.
JavaScript 함수를 호출 할 때마다 JavaScript 인터프리터는 범위를 결정하고이를 함수에 전달합니다.
다음 기능을 고려하십시오.
function sum(a, b)
{
return a + b;
}
sum(10, 20); // returns 30;
이 함수는 Window 범위에서 선언되며이를 호출 this
하면 sum 함수 내부의 값이 전역 Window
개체가됩니다.
‘sum’함수의 경우 ‘this’가 사용하지 않기 때문에 값이 무엇인지는 중요하지 않습니다.
다음 기능을 고려하십시오.
function Person(birthDate)
{
this.birthDate = birthDate;
this.getAge = function() { return new Date().getFullYear() - this.birthDate.getFullYear(); };
}
var dave = new Person(new Date(1909, 1, 1));
dave.getAge(); //returns 100.
당신이 dave.getAge 함수를 호출 할 때, 자바 스크립트 인터프리터는 당신이에 getAge 함수를 호출하는 것을보고 dave
는 설정 때문에, 객체 this
로 dave
하고, 호출 getAge
기능. getAge()
올바르게 반환 100
됩니다.
JavaScript에서 apply
메서드를 사용하여 범위를 지정할 수 있음을 알 수 있습니다 . 시도해 봅시다.
var dave = new Person(new Date(1909, 1, 1)); //Age 100 in 2009
var bob = new Person(new Date(1809, 1, 1)); //Age 200 in 2009
dave.getAge.apply(bob); //returns 200.
위 줄에서 JavaScript가 범위를 결정하도록하는 대신 수동으로 범위를 bob
객체 로 전달 합니다. getAge
이제 개체 에 대해 200
‘생각’했음에도 불구하고 반환됩니다 .getAge
dave
위의 모든 것의 요점은 무엇입니까? 함수는 JavaScript 객체에 ‘느슨하게’연결됩니다. 예를 들어 할 수 있습니다.
var dave = new Person(new Date(1909, 1, 1));
var bob = new Person(new Date(1809, 1, 1));
bob.getAge = function() { return -1; };
bob.getAge(); //returns -1
dave.getAge(); //returns 100
다음 단계로 넘어 갑시다.
var dave = new Person(new Date(1909, 1, 1));
var ageMethod = dave.getAge;
dave.getAge(); //returns 100;
ageMethod(); //returns ?????
ageMethod
실행하면 오류가 발생합니다! 어떻게 된 거예요?
주의 깊게 내 위의 포인트를 읽는다면, 당신은주의 할 dave.getAge
메소드가 호출되었습니다 dave
로 this
자바 스크립트의 ‘범위’판별 할 수 없습니다 반면 개체를 ageMethod
실행합니다. 그래서 글로벌 ‘창’을 ‘this’로 전달했습니다. 이제 속성 window
이 없으므로 실행이 실패합니다.birthDate
ageMethod
이 문제를 해결하는 방법? 단순한,
ageMethod.apply(dave); //returns 100.
위의 모든 내용이 이해가 되었습니까? 그렇다면 별칭을 사용할 수없는 이유를 설명 할 수 있습니다 document.getElementById
.
var $ = document.getElementById;
$('someElement');
$
로 호출 window
로 this
하고있는 경우 getElementById
구현이 기대 this
될 document
, 그것은 실패합니다.
다시이 문제를 해결하려면 다음을 수행 할 수 있습니다.
$.apply(document, ['someElement']);
그렇다면 Internet Explorer에서 작동하는 이유는 무엇입니까?
getElementById
IE 의 내부 구현을 모르지만 jQuery 소스 ( inArray
메서드 구현) 의 주석은 IE에서 window == document
. 이 경우 앨리어싱 document.getElementById
은 IE에서 작동합니다.
이것을 더 설명하기 위해 나는 정교한 예를 만들었습니다. Person
아래 기능을 살펴보십시오 .
function Person(birthDate)
{
var self = this;
this.birthDate = birthDate;
this.getAge = function()
{
//Let's make sure that getAge method was invoked
//with an object which was constructed from our Person function.
if(this.constructor == Person)
return new Date().getFullYear() - this.birthDate.getFullYear();
else
return -1;
};
//Smarter version of getAge function, it will always refer to the object
//it was created with.
this.getAgeSmarter = function()
{
return self.getAge();
};
//Smartest version of getAge function.
//It will try to use the most appropriate scope.
this.getAgeSmartest = function()
{
var scope = this.constructor == Person ? this : self;
return scope.getAge();
};
}
Person
위 의 기능에 대해 다양한 getAge
메서드가 작동 하는 방식은 다음과 같습니다.
Person
함수를 사용하여 두 개의 객체를 만들어 보겠습니다 .
var yogi = new Person(new Date(1909, 1,1)); //Age is 100
var anotherYogi = new Person(new Date(1809, 1, 1)); //Age is 200
console.log(yogi.getAge()); //Output: 100.
곧바로 getAge 메소드는 yogi
객체를로 가져오고 this
출력 100
합니다.
var ageAlias = yogi.getAge;
console.log(ageAlias()); //Output: -1
자바 스크립트 인터프리터는 window
객체를로 설정 this
하고 getAge
메서드는 -1
.
console.log(ageAlias.apply(yogi)); //Output: 100
올바른 범위를 설정하면 ageAlias
방법 을 사용할 수 있습니다 .
console.log(ageAlias.apply(anotherYogi)); //Output: 200
다른 사람 개체를 전달해도 나이를 올바르게 계산합니다.
var ageSmarterAlias = yogi.getAgeSmarter;
console.log(ageSmarterAlias()); //Output: 100
이 ageSmarter
함수는 원래 this
객체를 캡처 하므로 이제 올바른 범위를 제공하는 것에 대해 걱정할 필요가 없습니다.
console.log(ageSmarterAlias.apply(anotherYogi)); //Output: 100 !!!
문제 ageSmarter
는 범위를 다른 개체로 설정할 수 없다는 것입니다.
var ageSmartestAlias = yogi.getAgeSmartest;
console.log(ageSmartestAlias()); //Output: 100
console.log(ageSmartestAlias.apply(document)); //Output: 100
ageSmartest
유효 범위가 공급되면 함수는 원래의 범위를 이용할 것이다.
console.log(ageSmartestAlias.apply(anotherYogi)); //Output: 200
여전히 다른 Person
개체를 에 전달할 수 있습니다 getAgeSmartest
. 🙂
답변
이것은 짧은 대답입니다.
다음은 함수의 복사본 (참조)을 만듭니다. 문제는 이제 window
객체에 살도록 설계되었을 때 기능이 객체에 있다는 document
것입니다.
window.myAlias = document.getElementById
대안은 다음과 같습니다.
- 포장지 사용 (이미 Fabien Ménager에 의해 언급 됨)
-
또는 두 개의 별칭을 사용할 수 있습니다.
window.d = document // A renamed reference to the object window.d.myAlias = window.d.getElementById
답변
래핑 / 앨리어싱 console.log
및 유사한 로깅 방법에 대한 또 다른 짧은 대답 입니다. 그들은 모두 console
맥락 에 있기를 기대합니다 .
이것은 (항상) 지원하지 않는 브라우저를 사용할 때 console.log
귀하 또는 귀하의 사용자가 문제를 겪는 경우 일부 폴백으로 래핑 할 때 사용할 수 있습니다 . 하지만 이것은 확장 된 수표와 폴 백이 필요하기 때문에 그 문제에 대한 완전한 해결책은 아닙니다. 마일리지는 다를 수 있습니다.
경고를 사용한 예
var warn = function(){ console.warn.apply(console, arguments); }
그런 다음 평소대로 사용하십시오.
warn("I need to debug a number and an object", 9999, { "user" : "Joel" });
당신이 배열에 싸여 로깅 인수를 참조하려는 경우 (내가 대부분의 시간), 대신 .apply(...)
에 .call(...)
.
작업을해야 console.log()
, console.debug()
, console.info()
, console.warn()
, console.error()
. console
MDN 도 참조하십시오 .
답변
다른 훌륭한 답변 외에도 간단한 jQuery 메서드 $ .proxy가 있습니다.
다음과 같이 별칭을 지정할 수 있습니다.
myAlias = $.proxy(document, 'getElementById');
또는
myAlias = $.proxy(document.getElementById, document);
답변
실제로 미리 정의 된 개체의 함수를 “순수한 별칭”으로 만들 수 없습니다 . 따라서 래핑하지 않고 얻을 수있는 앨리어싱에 가장 가까운 것은 동일한 객체 내에 머무르는 것입니다.
>>> document.s = document.getElementById;
>>> document.s('myid');
<div id="myid">