2012-02-08 3 views
2

페이지에 일부 기능을 수행하는 북마크릿을 작성 중입니다. 이 기능의 일부로 getElementsByClassName을 사용해야합니다. 그러나 테스트 중에 여러 웹 사이트가 사용자 정의 방법으로 getElementsByClassName을 재정의했음을 발견했습니다. 아마도 이것은 모든 브라우저에서 getElementsByClassName을 지원하기 위해 수행되었습니다.재정의 된 함수의 원래 정의 얻기

사용자 정의 getElementsByClassName의 구현이 다소 엉성하고 일부 사용 사례에서 실패합니다. getElementsByClassName의 원래 정의를 얻을 수있는 방법이 있습니까?

크롬 자바 스크립트 콘솔에서 : getElementsByClassName은 기본 기능을 가리 킵니다. getElementsByClassName가 재정의되었으므로이 원시 함수에 액세스 할 수 있습니까?

+0

미리 캐시 할 수 있습니다. 또는 네이티브 지원이없는 경우에만 스크립트를 변경하여 지원을 추가 할 수 있습니다 (대다수가이를 수행해야합니다). 그러나 일단 재정의하면 되돌릴 수 없습니다. – davin

+0

@davin 불행히도, 나는 페이지 또는 스크립트를 소유/통제하지 않습니다. – asleepysamurai

+1

내가 말했듯이, 북마크릿을 작성 중이며 페이지에 삽입 된 스크립트가 아닙니다. 그래서 나는 getElementsByClassName을 redine하는 함수를 수정할 수 없다. 그래서 다른 접근 방법을 찾고있다. – asleepysamurai

답변

3

해결 방법이 있지만 강력한 것은 아닙니다. 하단의 면책 조항을 참조하십시오.

새 창을 열면 수정되지 않은 방법에 액세스 할 수 있습니다. 새 창을 여는 두 가지 방법, 즉 window.open을 사용하여 iframe에서 생각할 수 있습니다. iframe은 새로운 브라우저 창을 열거 나 팝업 차단기를 트리거하여 사용자를 혼란스럽게하지 않으므로 눈에 띄지 않습니다.

// Runs fn with a clean window reference 
function getCleanReferences(fn) { 
    var iframe = document.createElement('iframe'); 
    iframe.style.display = 'none'; 
    document.body.appendChild(iframe); 
    var newWindow = iframe.contentWindow; 
    iframe.parentNode.removeChild(iframe); 
    return fn(newWindow); 
} 

일부 브라우저는 iframe을 제거하지 않을 것입니다. Safari 또는 Firefox에서이 기능을 사용하려면 removeChild 행을 삭제하십시오. 그런 다음 새 창에서 getElementsByClassName 메소드를 가져 오려고 할 것입니다. IE는 쿼크 모드 또는 (당신이 북마크에 약간의 통제권이) 버전 9 전에 getElementsByClassName을 좋아하지 않는 것을 제외하고

var nativeGetElementsByClassName = getCleanReferences(function(newWindow) { 
    var getElementsByClassName = newWindow.document.getElementsByClassName; 
    return function(className) { 
     return getElementsByClassName.call(window.document, className); 
    }; 
}); 

이, 거의 크로스 브라우저입니다.http://jsfiddle.net/theazureshadow/vdqYG/

을 그리고 당신은 다른 방법을 가져 내 실험에 대한 호기심이 있다면,이 jsfiddle을 살펴 : 여기 jsfiddle입니다 http://jsfiddle.net/theazureshadow/ccFG3/

면책 조항 : 현재의 맥락에서 다른 창에서 사용 방법 하나는 위험하고 정의되지 않은 영역입니다. 이 취약한 접근 방식을 사용하려면 브라우저 간 호환성을 테스트하십시오. 테스트 결과 다른 브라우저가이 접근 방식을 어떻게 처리하는지에 큰 차이가있었습니다. 프로덕션 사이트에서는 사용하지 말아야하지만 개인 북마크릿에서는 괜찮습니다. 사용할 방법이 무엇이든 자신 만의 버전을 포함하는 것이 훨씬 안전합니다.

2

나는 생각하지 않습니다. 이것이 바로 Monkeypatching이 나쁜 이유입니다. 호스트 객체를 재정의해서는 안됩니다.

0

사용자 지정 방법 정의 방법에 따라 다릅니다. 메서드를 Element.prototype.getElementsByClassName으로 액세스 할 수 있지만이 프로토 타입 메서드를 페이지가 덮어 쓰면 다시 가져올 방법이 없다고 생각합니다.

1

일부 사이트에서는 프로토 타입을 사용합니다. DOM의 document.getElementsByClassName()NodeList을 반환하지만 Prototype의 document.getElementsByClassName()Array을 반환하지만 NodeList은 JS 스크립트로 만들 수 없기 때문에 반환합니다.

파이어 폭스에서 당신은 원래의 방법을 얻을 수

var node = document; 
Components.lookupMethod(node, 'getElementsByClassName').call(node, /* className */); 

를 사용할 수 있습니다. 어쩌면 Google 크롬은 비슷한 점을 구현합니다. 그렇지 않으면 운이 없어집니다. 나는 아무것도 (2 분 인터넷 검색) 찾을 수 없었다. 이 같은 것을 사용할 수 있습니다이 경우

:

function getElementsByClassName(node, className) { 
    var rv = new Array(); 
    var nodeList = node.getElementsByTagName('*'); 
    className = className.replace(/([\.\\\\\+\*\?\[\^\]\$\(\)\{\}\=\!\<\>\|\:\-])/, '\\$1'); 
    var regex = new RegExp('(?:^|[\\n\\r ])' + className + '(?:[\\n\\r ]|$)'); 
    for(var length = nodeList.length, i = 0; i < length; ++i) { 
     if(regex.test(nodeList[ i ].className)) { 
      rv.push(nodeList[ i ]); 
     } 
    } 
    return rv; 
} 

당신은 소름 정규식 사용하지 않는 다음과 같은 기능을 사용할 수 있습니다 node.classList Google 크롬 구현하는 경우 :

function getElementsByClassName(node, className) { 
    var rv = new Array(); 
    var nodeList = node.getElementsByTagName('*'); 
    for(var length = nodeList.length, i = 0; i < length; ++i) { 
     if(nodeList[ i ].classList.contains(className)) { 
      rv.push(nodeList[ i ]); 
     } 
    } 
    return rv; 
} 

이 기능을 지정된 노드 내부의 모든 요소를 ​​반복합니다. Prototype과 같은 Array를 반환하고 동일한 단점을 공유합니다. 배열은 NodeList과 같이 "라이브"가 아닙니다.

+0

두 번째 해결 방법과 비슷한 일을했습니다. NodeList가 필요하기 때문에 세 번째 솔루션은 실제로 작동하지 않습니다. 현재 파이어 폭스의 lookupMethod와 비슷한 웹킷이 있는지를 찾으려고 노력 중이다. 감사! – asleepysamurai

관련 문제