프로그래밍 방식으로 자바 스크립트 함수에 코드 추가


114

원래 JS 코드를 수정하지 않고 기존 JS 라이브러리를 사용자 지정하려고합니다. 이 코드는 내가 액세스 할 수있는 몇 개의 외부 JS 파일에로드되며, 내가 원하는 것은 전체를 두 번째 JS 파일에 복사하여 붙여 넣지 않고 원본 파일에 포함 된 함수 중 하나를 변경하는 것입니다.
예를 들어, 제한 해제 JS에는 다음과 같은 기능이있을 수 있습니다.

var someFunction = function(){
    alert("done");
}

어떻게 든 해당 함수에 JS 코드를 추가하거나 앞에 추가 할 수 있기를 바랍니다. 그 이유는 주로 원래의 untouchable JS에서 함수가 꽤 방대하고 JS가 업데이트되면 내가 덮어 쓰는 함수가 오래되기 때문입니다.

이것이 가능한지 완전히 확신하지는 못하지만 확인해야한다고 생각했습니다.


3
의 첫 번째 대답 당신을 도움이 될 것입니다
DarkAjax

콜백 함수와 같은 것을 원하십니까?
sinemetu1

답변:


220

someFunction전역 적으로 사용 가능한 경우 함수를 캐시하고 직접 만들고 호출하도록 할 수 있습니다.

그래서 이것이 원본이라면 ...

someFunction = function() {
    alert("done");
}

당신은 이것을 할 것입니다 ...

someFunction = (function() {
    var cached_function = someFunction;

    return function() {
        // your code

        var result = cached_function.apply(this, arguments); // use .apply() to call it

        // more of your code

        return result;
    };
})();

여기 바이올린이 있습니다


.apply캐시 된 함수를 호출하는 데 사용 합니다. 이를 통해의 예상 값을 유지하고 this얼마나 많은 인수가 있었는지에 관계없이 개별 인수로 전달 된 인수를 전달할 수 있습니다.


10
이 답변은 정말 최고가되어야합니다. 문제가되는 기능의 기능을 유지합니다 ... +1.
Reid

17
+1 for using apply: 이것이 문제 를 실제로 해결하는 유일한 답변입니다 .
lonesomeday

2
@minitech : 뭐 ... 당신은 JavaScript의 funciton키워드에 익숙하지 않습니까? ;) 편집 주셔서 감사합니다

1
@gdoron : 방금 댓글을 추가했습니다. 지금 당장 혼란스러워하지 않는 한, 실제 Arguments 객체를 .NET의 두 번째 인수로 받아들이지 않는 브라우저를 알지 못합니다 .apply(). 그러나 예를 들어 jQuery 객체와 같은 Array와 같은 객체라면 예, 일부 브라우저는 오류를 발생시킬 것입니다

2
이 답변은 인스턴스 개체를 사용하여 YouTube Iframe API를 통해 삽입 된 개별 YouTube 동영상을 제어하는 ​​문제를 해결합니다. API가 각 동영상의 데이터를 고유 한 모듈 방식으로 처리하는 클래스를 만들려고 할 때 단일 전역 함수가 되려면 콜백이 필요하다는 사실을 얼마나 오랫동안 해결하려고 노력했는지 알 수 없습니다. 당신은 오늘의 나의 영웅입니다.
Carnix

31

먼저 실제 함수를 변수에 저장합니다.

var oldFunction = someFunction;

그런 다음 자신을 정의하십시오.

someFunction = function(){
  // do something before
  oldFunction();
  // do something after
};

9
함수가 메서드 인 경우 apply이를 호출하는 데 사용해야 합니다. am의 대답을 참조하십시오.
hugomg

그것은 나를 위해 일했지만 위의 코드에서 대체 someFunction해야 window.someFunction했습니다. 그 이유는 내 함수가 jquery $(document).ready()핸들러 내부에서 선언 되었기 때문입니다 .
넬슨

10

코드를 호출하는 함수를 만든 다음 해당 함수를 호출 할 수 있습니다.

var old_someFunction = someFunction;
someFunction = function(){
    alert('Hello');
    old_someFunction();
    alert('Goodbye');
}

6

함수를 업데이트 할 수 있는지는 모르겠지만 참조 방법에 따라 그 자리에 새 함수를 만들 수 있습니다.

var the_old_function = someFunction;
someFunction = function () {
    /* ..My new code... */
    the_old_function();
    /* ..More of my new code.. */
}

5

또한. 로컬 컨텍스트를 변경하려면 함수를 다시 만들어야합니다. 예를 들면 :

var t = function() {
    var a = 1;
};

var z = function() {
    console.log(a);
};

지금

z() // => log: undefined

그때

var ts = t.toString(),
    zs = z.toString();

ts = ts.slice(ts.indexOf("{") + 1, ts.lastIndexOf("}"));
zs = zs.slice(zs.indexOf("{") + 1, zs.lastIndexOf("}"));

var z = new Function(ts + "\n" + zs);

z() // => log: 1

그러나 이것은 가장 간단한 예일뿐입니다. 인수, 주석 및 반환 값을 처리하려면 여전히 많은 작업이 필요합니다. 또한 여전히 많은 함정이 있습니다.
toString | 슬라이스 | indexOf | lastIndexOf | 새로운 기능


1

프록시 패턴 (user1106925에서 사용됨)은 함수 안에 넣을 수 있습니다. 아래에 작성한 것은 전역 범위에 있지 않은 함수와 프로토 타입에서도 작동합니다. 다음과 같이 사용합니다.

extender(
  objectContainingFunction,
  nameOfFunctionToExtend,
  parameterlessFunctionOfCodeToPrepend,
  parameterlessFunctionOfCodeToAppend
)

아래 스 니펫에서 test.prototype.doIt ()을 확장하는 함수를 사용하는 것을 볼 수 있습니다.

// allows you to prepend or append code to an existing function
function extender (container, funcName, prepend, append) {

    (function() {

        let proxied = container[funcName];

        container[funcName] = function() {
            if (prepend) prepend.apply( this );
            let result = proxied.apply( this, arguments );
            if (append) append.apply( this );
            return result;
        };

    })();

}

// class we're going to want to test our extender on
class test {
    constructor() {
        this.x = 'instance val';
    }
    doIt (message) {
        console.log(`logged: ${message}`);
        return `returned: ${message}`;
    }
}

// extends test.prototype.doIt()
// (you could also just extend the instance below if desired)
extender(
    test.prototype, 
    'doIt', 
    function () { console.log(`prepended: ${this.x}`) },
    function () { console.log(`appended: ${this.x}`) }
);

// See if the prepended and appended code runs
let tval = new test().doIt('log this');
console.log(tval);

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.