2015-02-23 36 views
33

Tôi đang sử dụng JavaScript và nhận được một vấn đề với các tuyên bốTuyên bố này làm gì? console.log.bind (console)

console.log.bind(console) 

Hãy cho tôi biết những gì hiện tuyên bố này thực sự làm. Tôi đã áp dụng điều này nhiều lần nhưng nó không làm gì cả.

+4

https://developer.mozilla.org/ en-US/docs/Web/JavaScript/Tham chiếu/Global_Objects/Chức năng/liên kết – zerkms

+0

http://stackoverflow.com/questions/20723602/bind-event-handler-to-console-log-javascript-event –

+0

Function.bind () là thiếu từ IE8, nhưng nên làm việc tốt trong br thực owsers. đăng mã bị hỏng nếu nghi ngờ. – dandavis

Trả lời

59

Trong JavaScript, this trong một cuộc gọi chức năng được xác định bởi cách chức năng được gọi (đối với các chức năng bình thường, xem * bên dưới). Nếu được gọi là một phần của biểu thức truy xuất thuộc tính đối tượng (ví dụ: foo.bar() gọi bar() như một phần của hoạt động truy xuất thuộc tính nhận được từ foo), this được đặt thành đối tượng mà thuộc tính xuất phát trong khi gọi hàm.

Giả sử bạn muốn có dạng ngắn hơn là console.log, như f. Bạn có thể làm điều này:

var f = console.log; // <== Suspect! 

... nhưng nếu log chức năng dựa vào this đề cập đến đối tượng console trong suốt cuộc gọi, sau đó gọi f("Message here") sẽ không làm việc, bởi vì this sẽ không đề cập đến console.

Function#bind chỉ dành cho trường hợp đó: Nó cho phép bạn tạo một hàm mới, khi được gọi, sẽ gọi hàm gốc với this được đặt thành giá trị bạn cung cấp. Vì vậy,

var f = console.log.bind(console); // Still suspect, for a different reason 

... nên, về mặt lý thuyết, cung cấp cho bạn một chức năng, f, mà bạn có thể gọi để đăng nhập vào giao diện điều khiển.

Trừ: chức năng chủ cung cấp như console.log (và alertgetElementById) không phải là "thực" JavaScript chức năng (mặc dù trên các trình duyệt hiện đại họ có xu hướng, hoặc ít nhất là rất gần), và aren không bắt buộc phải có tất cả các tính năng của họ, inculding bind. Vì vậy, nếu bạn gặp lỗi trên dòng đó, có thể là công cụ bạn đang sử dụng dòng đó không hỗ trợ bind trên chức năng console.log.

Vậy "chức năng do máy chủ cung cấp" là gì? Bất kỳ hàm nào không được xác định rõ ràng trong đặc điểm kỹ thuật như là một phần của JavaScript, ngôn ngữ. Một lần nữa, trên trình duyệt có chức năng liên quan đến trình duyệt như alert hoặc console.log và các chức năng như vậy.

tôi có thể nghĩ ra hai lý do khiến dòng có thể đem lại cho bạn rắc rối:

  1. Trên đây: Bạn đang sử dụng một công cụ JavaScript mà không làm cho console.log một chức năng thực sự.

  2. Bạn đang sử dụng dòng ở trên trên IE với Công cụ tìm kiếm đã đóng. Trên IE khi các công cụ dev không mở, đối tượng console không được xác định và do đó dòng đó sẽ ném một số ReferenceError.

Nếu mục tiêu cuối cùng là để có được một chức năng bạn có thể gọi điện thoại, nói f("Message here"), cho console.log, dưới đây là cách bạn có thể làm điều đó đối phó với cả # 1 và # 2 ở trên:

function f(item) { 
    if (typeof console != "undefined" && console.log) { 
     console.log(item); 
    } 
} 

Đó chỉ cho phép bạn cung cấp một mục, trong khi console.log cho phép bạn cung cấp nhiều mục (console.log("this", "that", "and the other")), nhưng nếu console.log có thể không phải là hàm JavaScript thực, thì có thể không có Function#apply.

Bây giờ, nếu bạn không quan tâm về việc các cùng đầu ra bạn muốn nhận được từ console.log("this", "that", "and the other") chừng nào bạn có thể nhìn thấy những gì ở đó, chỉ cần sử dụng console.log(arguments); (arguments là được xây dựng trong nhận dạng cho tất cả các đối số được truyền vào một hàm). Nhưng nếu bạn muốn sao chép kết quả chính xác, bạn sẽ thực hiện một việc như sau:

function f() { 
    var a = arguments; 

    if (typeof console != "undefined" && console.log) { 
     if (console.log.apply) { 
      // It has Function#apply, use it 
      console.log.apply(console, arguments); 
     } else { 
      // Ugh, no Function#apply 
      switch (a.length) { 
       case 0: console.log(); break; 
       case 1: console.log(a[0]); break; 
       case 2: console.log(a[0], a[1]); break; 
       case 3: console.log(a[0], a[1], a[2]); break; 
       case 4: console.log(a[0], a[1], a[2], a[3]); break; 
       case 5: console.log(a[0], a[1], a[2], a[3], a[4]); break; 
       default: 
        throw "f() only supports up to 5 arguments"; 
      } 
     } 
    } 
} 

... và điều đó thật xấu xí.


* ES5 thêm ràng buộc chức năng, đó là chức năng mà có giá trị this của họ gắn liền với họ thông qua ràng buộc:

// Normal function 
function foo() { 
    console.log(this.name); 
} 

// Create a bound function: 
var f = foo.bind(someObject); 

Nó không quan trọng như thế nào bạn gọi f, nó sẽ gọi foo với this được đặt thành someObject.

* ES2015 (aka ES6) đã thêm chức năng mũi tên. Với các chức năng mũi tên, thiskhông được đặt theo cách gọi hàm; thay vào đó, chức năng thừa hưởng this từ bối cảnh trong đó nó đã được tạo ra:

// Whatever `this` is here... 
var f =() => {        // <== Creates an arrow function 
    // Is what `this` will be here 
}; 

chức năng mũi tên thực sự tiện dụng khi bạn đang làm một cái gì đó giống như Array#forEach trong vòng một phương pháp đối tượng:

this.counter = 0; 
this.someArray.forEach(entry => { 
    if (entry.has(/* some relevant something */)) { 
     ++this.counter; 
    } 
}); 
+0

Wow! Mọi người rõ ràng là thích câu trả lời này nhưng tôi không thể thấy nó trả lời câu hỏi OP như thế nào? Có lẽ tôi chỉ là ngu ngốc nhưng nó có vẻ là đập vào một loạt các công cụ ngoại vi cho câu hỏi thực tế (cũng như các câu trả lời khác). – geoidesic

+3

@geoidesic: Nó trực tiếp trả lời câu hỏi: * "Vì vậy,' var f = console.log.bind (console); 'nên, theo lý thuyết, cung cấp cho bạn một hàm,' f', mà bạn có thể gọi để đăng nhập vào giao diện điều khiển Nó cũng giải thích lý do tại sao nó làm điều đó, tại sao bạn cần phải làm điều đó thay vì chỉ 'var f = console.log' (đó là nơi' this' đi vào nó), và nó có thể hoạt động như thế nào hoặc có thể không hoạt động việc triển khai máy chủ. –

+0

@ T.J.Crowder Cảm ơn bạn đã trả lời. Tôi đang sử dụng 'console.log.bind' trong Typescript/Angular cho một logger, để in các công cụ trong giao diện điều khiển với liên kết đến lớp mà logger được gọi thay vì bên trong lớp Logger, giống như không có' bind'. Rất tiếc, tôi không thể chuyển một thông số thứ hai để ràng buộc, ví dụ: 'console.log.bind (console, 'background: # 222; color: # bada55');' sẽ chỉ in đối số thứ hai dưới dạng một chuỗi và không áp dụng nó cho giao diện điều khiển. Làm thế nào để sửa lỗi này? – Phil

4

T.J. Câu trả lời của Crowder đã giúp tôi giải thích và giải quyết một vấn đề mà tôi có với việc chuyển hướng đầu ra console.log, nhưng giải pháp của anh ta cho trường hợp "không có chức năng # áp dụng" dường như tùy ý hạn chế trong nhiều trường hợp sử dụng.

Tôi viết lại mã của mình như thế này là một trình dọn dẹp chút và thêm chức năng:

function f() { 
    var a = arguments; 

    if (typeof console != "undefined" && console.log) { 
     if (console.log.apply) { 
      // It has Function#apply, use it 
      console.log.apply(console, arguments); 
     } else { 
      // Ugh, no Function#apply 
      var output = ''; 
      for (i=0;i<arguments.length;i++) { 
       output += arguments[i] + ' '; 
      } 
      console.log(output); 
     } 
    } 
} 

console.log tách cãi nhau với một không gian, vì vậy tôi lặp lại rằng đây là tốt. Giới hạn chính cho điều này là nó không xử lý các đối số là các đối tượng. Bạn có thể xâu chuỗi nếu cần.

0

Tôi dám đoán, đây là những gì nhiều người có thể tìm kiếm:

Thông thường bạn có thể thấy điều này trong Promise lỗi xử lý (ví dụ, từ 2 quickstart góc):

System.import("unmarshaller/Unmarshaller.js").then(null, console.error.bind(console)); 

Như đã trình bày trong các câu trả lời khác, hàm này cung cấp hàm console.error làm trình xử lý lỗi và bind(console) làm cho nó sử dụng console làm giá trị của this bên trong phần thân của nó. Nếu không, this sẽ được đặt thành đối tượng chung (window trong trình duyệt) và cuộc gọi sẽ không thành công. Giải thích rõ ràng here.

Phần Offtopic:

Bạn có thể muốn tạo xử lý của riêng bạn để các lỗi trước quá trình. Trong ví dụ trên, console.error in xấu xí Error trong bảng điều khiển vì SystemJS chỉ cho biết "Lỗi khi tải Unmarshaller.js". Và lỗi khác bị ẩn trong originalErr.

Thực hiện một handler tùy chỉnh để unwrap:

function handleError(e) { 
    if (e.originalErr) 
     throw e.originalErr; 
    throw e; 
} 

System.import("unmarshaller/Unmarshaller.js").then(null, handleError); 

Không cần .bind(), và sẽ cung cấp cho bạn Error ban đầu ném, như:

Error: Given object doesn't specify "w:winduptype" and no target class given:
[{"w:winduptype":["FileResource","ArchiveModel:","WarArchiveModel"], ...

+2

Điều này dường như không phải là một nỗ lực để trả lời câu hỏi. Nó không mô tả những gì 'console.error.bind (console)' có nghĩa là, nó chỉ trình bày một thay thế (hoạt động khác nhau theo một số cách đáng kể) cho một usecase rất cụ thể (mà câu hỏi không đề cập đến ở tất cả) .. – Quentin

+0

Đó là nhận thức của bạn về câu hỏi, mà chính nó là khá mơ hồ. Không có điểm nào trong việc lặp lại các câu trả lời khác. Thay đổi để được tổng quát hơn, mặc dù. –

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