2011-07-06 21 views
21

Tôi đang cố gắng lặp qua tất cả các hình cầu được xác định trong một trang web, nhưng khi làm như vậy, tôi cũng nhận được các chức năng trình duyệt gốc.Phát hiện nếu chức năng có nguồn gốc từ trình duyệt

var numf=0; var nump=0; var numo=0; 
for(var p in this) { 
    if(typeof(this[p]) === "function"){ 
     numf+=1; 
     console.log(p+"()"); 
    } else if(typeof p != 'undefined'){ 
     nump+=1; 
     console.log(p); 
    } else { 
     numo+=1; 
     console.log(p); 
    } 
} 

Có cách nào để xác định xem chức năng có nguồn gốc từ trình duyệt hay được tạo trong tập lệnh không?

Trả lời

12

Bạn có thể gọi hàm được thừa kế .toString() trên các phương pháp và kiểm tra kết quả. Các phương thức gốc sẽ có một khối như [native code].

if(this[p].toString().indexOf('[native code]') > -1) { 
    // yep, native in the browser 
} 

Cập nhật vì có rất nhiều bình luận muốn có một số làm rõ và những người thực sự có một yêu cầu cho một phát hiện như vậy. Để thực hiện việc kiểm tra này thực sự tiết kiệm, chúng ta có lẽ nên sử dụng một dòng dòng này:

if(/\{\s+\[native code\]/.test(Function.prototype.toString.call(this[ p ]))) { 
    // yep, native 
} 

Bây giờ chúng ta đang sử dụng phương pháp .toString từ prototype của Function mà làm cho nó rất khó nếu không muốn nói là không thể một số kịch bản khác đã ghi đè các toString. Thứ hai, chúng tôi đang kiểm tra với một biểu thức chính quy để chúng tôi không thể bị lừa bởi các bình luận trong nội dung hàm.

+0

Điều này sẽ chỉ làm việc nếu toString đã không được ghi đè, không có? – joekarl

+2

@jAndy Điều này có thực sự không? Tôi nghĩ 'toString' không hoạt động trong tất cả các trình duyệt hiện đại hay gì đó. – William

+3

@joekit nếu 'toString' bị ghi đè, bạn sẽ có thể thực hiện' Function.prototype.toString.call (obj) .indexOf ('[native code]'); 'Ngoài ra, có lẽ nên sử dụng RegExp tốt hơn. Hãy thử gọi chức năng chống lại chính nó, và nó sẽ đi qua như ** native ** bởi vì nó xuất hiện trong chuỗi. – William

10
function isFuncNative(f) { 
     return !!f && (typeof f).toLowerCase() == 'function' 
     && (f === Function.prototype 
     || /^\s*function\s*(\b[a-z$_][a-z0-9$_]*\b)*\s*\((|([a-z$_][a-z0-9$_]*)(\s*,[a-z$_][a-z0-9$_]*)*)\)\s*{\s*\[native code\]\s*}\s*$/i.test(String(f))); 
} 

điều này phải đủ tốt. chức năng này thực hiện các thử nghiệm sau:

  1. null hoặc undefined;
  2. thông số thực sự là một hàm;
  3. các param là Function.prototype bản thân (đây là một trường hợp đặc biệt, nơi mang lại cho Function.prototype.toString function Empty(){})
  4. các cơ quan chức năng là chính xác function <valid_function_name> (<valid_param_list>) { [native code] }

regex là một chút phức tạp, nhưng nó thực sự chạy khá nhanh chóng trong chrome trên máy tính xách tay lenovo 4GB của tôi (bộ đôi lõi):

var n = (new Date).getTime(); 
for (var i = 0; i < 1000000; i++) { 
    i%2 ? isFuncNative(isFuncNative) : 
      isFuncNative(document.getElementById); 
}; 
(new Date).getTime() - n; 

3023ms. do đó, chức năng mất khoảng 3 micro-sec để chạy một khi tất cả là JIT'ed.

Nó hoạt động trong tất cả các trình duyệt. Trước đây, tôi đã sử dụng Function.prototype.toString.call, điều này làm hỏng IE, vì trong IE, các phương thức phần tử DOM và các phương thức cửa sổ là các hàm NOT, nhưng các đối tượng và chúng không có phương thức toString. String constructor giải quyết vấn đề một cách tao nhã.

-1

Tôi đã thử một cách tiếp cận khác. Điều này chỉ được thử nghiệm cho firefox và chrome.

function isNative(obj){ 
    //Is there a function? 
    //You may throw an exception instead if you want only functions to get in here. 

    if(typeof obj === 'function'){ 
     //Check does this prototype appear as an object? 
     //Most natives will not have a prototype of [object Object] 
     //If not an [object Object] just skip to true. 
     if(Object.prototype.toString.call(obj.prototype) === '[object Object]'){ 
      //Prototype was an object, but is the function Object? 
      //If it's not Object it is not native. 
      //This only fails if the Object function is assigned to prototype.constructor, or 
      //Object function is assigned to the prototype, but 
      //why you wanna do that? 
      if(String(obj.prototype.constructor) !== String(Object.prototype.constructor)){ 
       return false; 
      } 
     } 
    } 
    return true; 
} 

function bla(){} 

isNative(bla); //false 
isNative(Number); //true 
isNative(Object); //true 
isNative(Function); //true 
isNative(RegExp); //true 
+0

Trả về 'false' cho' Lời hứa' mặc dù trình duyệt của tôi hỗ trợ lời hứa tự nhiên. – mpen

+0

Có, tôi không biết tại sao. Promise.prototype.constructor không bằng Object.prototype.constructor. Tôi thường không kiểm tra nếu nó là bản địa anyway, và tìm phương pháp 'sau đó' đó là cách hứa hẹn bản địa giải quyết thư viện hứa hẹn bất kỳ cách nào. Nếu mọi thứ khác thất bại thì tôi sử dụng 'Promise.resolve (nonNative)' để bình thường hóa mọi lời hứa. –

+0

Chủ yếu hoạt động trong Chrome. Trả về false cho 'RegExp'. – trusktr

0

hầu hết trong số này sẽ thất bại, bởi vì:

function notNative(){ 
this.toString = "[native code]"; 
} 

thay vì:

Function.prototype.isNative = function(){ 
 
return Function.prototype.toString.call(this).slice(-14, -3) === "native code"; 
 
}; 
 

 
console.log(alert.isNative()); 
 
console.log(String.isNative()); 
 
function foo(){} 
 
console.log(foo.isNative());

+0

bạn có thể giải thích tại sao giải pháp của bạn tốt hơn không và cách thức hoạt động? – rene

Các vấn đề liên quan