2009-04-25 41 views
12

EDIT: OK, tôi tin rằng các giải pháp sau là hợp lệ:chức năng Javascript móc

  1. Sử dụng các plugin jQuery AOP. Về cơ bản nó kết thúc tốt chức năng cũ cùng với móc vào một bánh sandwich chức năng và gán lại nó cho tên hàm cũ. Điều này gây ra các hàm lồng nhau với mỗi móc mới được thêm vào.
    Nếu jQuery không thể sử dụng được cho bạn, chỉ cần cướp bóc mã nguồn, có vẻ như không có bất kỳ phụ thuộc jQuery nào trong plugin và nguồn đơn giản và rất nhỏ.

  2. Có một đối tượng mô tả tất cả các móc và mục tiêu của chúng và một để lưu trữ hàm chưa sửa đổi ban đầu. Khi thêm một móc mới, gói sẽ được làm lại xung quanh chức năng ban đầu, thay vì quấn lại chức năng gói trước đó.
    Bạn thoát khỏi các hàm lồng nhau và thay vào đó, hãy xử lý hai đối tượng. Có khả năng, điều này cũng có thể có nghĩa là xử lý móc dễ dàng hơn, nếu bạn thêm/tháo móc thường xuyên và không hoạt động.

Tôi sẽ đi đầu tiên, vì nó đã được thực hiện và tôi không có hiệu suất phải lo lắng. Và kể từ khi các chức năng ban đầu không bị ảnh hưởng, ngay cả khi tôi chuyển đổi phương pháp hooking, tôi sẽ chỉ cần làm lại móc thêm, mà có thể chỉ là một số tìm kiếm đơn giản & thay thế hoạt động.


Hi,

Có thể tạo ra một cơ chế, trong đó có chức năng A có thể có một bộ móc (chức năng mà sẽ thực hiện trước/sau chức năng A)?

Lý tưởng nhất, hàm A sẽ không biết chức năng hooking, do đó tôi không phải sửa đổi mã nguồn của hàm A để gọi móc. Một cái gì đó như:

A = function(){ 
    alert("I'm a naive function"); 
}; 
B = function(){ 
    alert("I'm having a piggyback ride on function A!"+ 
      "And the fool doesn't even know it!"); 
}; 
addHook(B, A)//add hook B to function A 
A() 
//getting alerts "I'm a naive function"/"I'm having a 
//piggyback ride on function A! And the fool doesn't even know it!" 

Tôi đã cố gắng để hack cái gì đó trong một vài giờ, nhưng cho đến nay không có may mắn.

+0

đây là một câu hỏi tốt đẹp, mặc dù tôi nghi ngờ sẽ có một câu trả lời tích cực. Bạn chắc chắn có thể làm điều đó nhưng với một số loại workaround. Tôi đang đánh dấu trang này. –

Trả lời

10

Hãy xem jQuery's AOP plugin. Nói chung, "lập trình hướng khía cạnh javascript" của google.

+4

jQuery! = Javascript. Điều này quan trọng, ví dụ, nếu bạn đang lập trình trên nền tảng Facebook, và có lẽ là các môi trường "sandboxed" khác. –

+0

@George: các kỹ thuật được chứng minh vẫn áp dụng. Cho đến nay, Greg là người duy nhất đăng mã có thể sử dụng * tại đây *. – Shog9

+0

Cảm ơn bạn đã liên kết và đề cập đến AOP, tôi không quen với nó. Tôi có thể và sử dụng jQuery, vì vậy điều này có thể làm việc ra ngoài. Đang cố gắng tìm ra plugin ngay bây giờ. – Seyen

12

Có thể không được đẹp, nhưng nó dường như làm việc ...

<script> 

function A(x) { alert(x); return x; } 
function B() { alert(123); } 

function addHook(functionB, functionA, parent) 
{ 
    if (typeof parent == 'undefined') 
     parent = window; 

    for (var i in parent) 
    { 
     if (parent[i] === functionA) 
     { 
      parent[i] = function() 
      { 
       functionB(); 
       return functionA.apply(this, arguments) 
      } 

      break; 
     } 
    } 
} 

addHook(B, A); 

A(2); 

</script> 
+1

Xin cảm ơn! Tôi nghĩ về điều này, và nó hoạt động, nhưng bạn có được làm tổ với phương pháp này, vì mỗi móc mới kết thúc tốt đẹp tất cả các móc trước: hookC (hookB (hookA (functionA.apply (this, arguments))) I ' m không chắc chắn nếu điều này ảnh hưởng đến hiệu suất trong bất kỳ cách nào, nhưng nó không cảm thấy đúng/an toàn. Có phải 'cha mẹ' được sử dụng sao cho điều này từ' áp dụng (điều này, đối số) 'bị ràng buộc đúng không? – Seyen

2

Câu trả lời này không phải là dứt khoát, mà là minh chứng của một kỹ thuật khác so với những cung cấp cho đến nay. Điều này thúc đẩy thực tế là một hàm trong Javascript là một đối tượng hạng nhất, và như vậy, a) bạn có thể chuyển nó thành một giá trị cho một hàm khác và b) bạn có thể thêm các thuộc tính vào nó. Kết hợp những đặc điểm này với các phương thức "gọi" (hoặc "áp dụng") được tích hợp sẵn của hàm và bạn có một khởi đầu hướng tới một giải pháp.

var function_itself = function() { 
    alert('in function itself'); 
} 
function_itself.PRE_PROCESS = function() { 
    alert('in pre_process'); 
} 
function_itself.POST_PROCESS = function() { 
    alert('in post_process'); 
} 

var function_processor = function(func) { 
    if (func.PRE_PROCESS) { 
     func.PRE_PROCESS.call(); 
    } 
    func.call(); 
    if (func.POST_PROCESS) { 
     func.POST_PROCESS.call(); 
    }   
} 
+0

Điều này làm việc, nhưng sau đó bạn phải sử dụng function_processor để gọi function_itself ở tất cả các nơi mà nó sẽ được gọi, mà phần nào đánh bại mục đích. Mã này có thể nhanh chóng biến thành một khu rừng của các cuộc gọi function_processor. – Seyen

3

câu trả lời Rất đơn giản:

function someFunction() { alert("Bar!") } 
var placeholder=someFunction; 
someFunction=function() { 
    alert("Foo?"); 
    placeholder(); 
} 
1

Chức năng sau đây sẽ cung cấp cho bạn trước và sau khi móc có thể được xếp chồng lên nhau. Vì vậy, nếu bạn có một số chức năng tiềm năng cần chạy trước hàm đã cho hoặc sau hàm đã cho thì đây sẽ là giải pháp làm việc. Giải pháp này không yêu cầu jQuery và sử dụng các phương thức mảng gốc (không yêu cầu shims). Nó cũng nên bối cảnh nhạy cảm vì vậy nếu bạn đang gọi hàm ban đầu với một bối cảnh nếu nên chạy mỗi trước và sau hàm tương tự.

// usage: 
/* 
function test(x) { 
    alert(x); 
} 

var htest = hookable(test); 

htest.addHook("before", function (x) { 
    alert("Before " + x); 
}) 
htest.addHook("after", function (x) { 
    alert("After " + x); 
}) 

htest("test") // => Before test ... test ... After test 
*/ 
function hookable(fn) { 
    var ifn = fn, 
     hooks = { 
      before : [], 
      after : [] 
     }; 

    function hookableFunction() { 
     var args = [].slice.call(arguments, 0), 
      i = 0, 
      fn; 
     for (i = 0; !!hooks.before[i]; i += 1) { 
      fn = hooks.before[i]; 
      fn.apply(this, args); 
     } 
     ifn.apply(this, arguments); 
     for (i = 0; !!hooks.after[i]; i++) { 
      fn = hooks.after[i]; 
      fn.apply(this, args); 
     } 
    } 

    hookableFunction.addHook = function (type, fn) { 
     if (hooks[type] instanceof Array) { 
      hooks[type].push(fn); 
     } else { 
      throw (function() { 
       var e = new Error("Invalid hook type"); 
       e.expected = Object.keys(hooks); 
       e.got = type; 
       return e; 
      }()); 
     } 
    }; 

    return hookableFunction; 
} 
0

Đây là những gì tôi đã làm, có thể có ích trong các ứng dụng khác như thế này:

//Setup a hooking object 
a={ 
    hook:function(name,f){ 
     aion.hooks[name]=f; 
    } 
}a.hooks={ 
    //default hooks (also sets the object) 
}; 

//Add a hook 
a.hook('test',function(){ 
    alert('test'); 
}); 

//Apply each Hook (can be done with for) 
$.each(a.hooks,function(index,f){ 
    f(); 
}); 
0

Tôi không biết nếu điều này sẽ hữu ích. Bạn không cần phải sửa đổi các chức năng ban đầu nhưng chỉ một lần và bạn không cần phải tiếp tục chỉnh sửa nó để bắn móc