2015-06-02 16 views
14

Tôi nhận thấy một điều kỳ lạ trong javascript. Hãy xem xét bên dưới:Ngữ cảnh chức năng JavaScript Không chính xác

var fn = ''.toUpperCase.call 
console.log(typeof fn); // "function" 
fn(); // Uncaught TypeError: `fn` is not a function 

Ở trên đã được thực hiện trên Bảng điều khiển dành cho nhà phát triển của Chrome. Phiên bản là 43.0.2357.81 m.

Toán tử typeof cho thấy rõ ràng rằng fn là một hàm, nhưng lỗi đề xuất khác.

Tôi nhận thấy rằng Function.apply hiển thị ít nhất một số thông báo lỗi có ý nghĩa.

Vì vậy, khi nào là hàm, không phải là hàm?

+0

Hãy thể hiện * cách * chính xác bạn đang gọi điện thoại 'fn'. – deceze

+5

Tôi nhận được 'undefined không phải là một hàm' khi gọi' fn', * not * 'fn không phải là một hàm'. – Darkhogg

+0

@ lừa dối đây không phải là một mã sản xuất .. Tôi chỉ tình cờ nhìn thấy một câu hỏi, suy nghĩ về điều đó, tôi bắt gặp những thứ kì lạ này. –

Trả lời

19

Bối cảnh trong Javascript luôn được thiết lập theo cách bạn gọi một chức năng.

var fn = ''.toUpperCase.call 

Điều này chỉ định thực hiện nguyên mẫu chức năng call cho fn. Nếu bây giờ bạn gọi fn(), không có ngữ cảnh nào cho cuộc gọi. call sẽ cố gắng gọi đối tượng hàm được liên kết với. Tuy nhiên, bối cảnh đó được thiết lập vào thời gian gọi. Vì bạn không đưa ra bất kỳ ngữ cảnh nào vào thời gian gọi, một số thành phần bên trong của call đang ném một lỗi.

Bạn sẽ phải làm điều này:

fn.call(''.toUpperCase) 

Đúng vậy, bạn call các call chức năng, thiết lập một bối cảnh, cụ thể là chức năng toUpperCase chuỗi. Trong trường hợp cụ thể này, điều này sẽ dẫn đến một lỗi khác bên trong toUpperCase, vì không bị ràng buộc vào một ngữ cảnh cụ thể. Bạn sẽ cần phải thiết lập bối cảnh đó một cách rõ ràng cũng như:

var fn = ''.toUpperCase.call 
fn.call(''.toUpperCase.bind('')) 

Xem thêm How does the "this" keyword work?

+0

do đó, bạn nghĩ, [câu trả lời của tôi] (http://stackoverflow.com/questions/30594471/array-prototype-map-is-not-a-function-when-passing-a-function-generated-by-funct/30594762 # 30594762) là câu trả lời cho câu hỏi được liên kết? –

+0

@Amit Yeah, về cơ bản bạn đang nói điều tương tự ở đó. – deceze

1

So, when is a function, not a function?

Chức năng là một chức năng, nhưng bạn không thực hiện nó một cách chính xác, như được giải thích trong ý kiến ​​và câu trả lời by @deceze

I noticed a weird thing in javascript.

Bạn có vẻ bối rối bởi thông điệp bạn đang nhận được trong môi trường bạn đã kiểm tra, thông báo không chính xác.

Uncaught TypeError: fn is not a function

Phiên bản ổn định hiện tại của crom (40.0.2214.91 trên linux của tôi cài đặt, chrome không chạy trên phần cứng của tôi mà không làm cho các thiết lập thay đổi), crôm là môi trường mà bạn đã thử nghiệm, đưa ra một lỗi có vẻ chính xác hơn thông điệp có ý nghĩa hơn.

Uncaught TypeError: undefined is not a function 

Vì vậy, bạn đang hỏi/muốn hỏi một câu hỏi nghiêm túc hoặc bạn chỉ chọc một chút vui vẻ với một lỗi trong phiên bản chrome?

+2

'40.0.2214.91' không phải là phiên bản ổn định hiện tại của Chrome; ['43.0.2357.81' là] (http://googlechromereleases.blogspot.com/2015/06/stable-update-for-chrome-os.html). Nguồn gói bạn nhận được từ Chrome không được cập nhật.Ngoài ra, tôi chỉ muốn làm cho điểm phân biệt (ngay cả khi OP biết câu trả lời cho câu hỏi này trước khi hỏi), muốn tạo một kho thông tin về lỗi rất khó hiểu này còn xa vời "chọc cười". – apsillers

+1

Tôi đã có rất nhiều công việc khác để làm thay vì chọc một chút vui vẻ tại chrome. Và FYI, tôi đã xem qua nội dung này khi trả lời [ở đây] (http://stackoverflow.com/questions/30594471/array-prototype-map-is-not-a-function-when-passing-a-function-generated- by-funct/30594762 # 30594762) và không phải ai cũng sử dụng phiên bản chrome bạn sử dụng (và tôi không cập nhật chrome theo cách thủ công, tự động diễn ra) và cảm ơn câu trả lời của bạn. Cảm ơn cho bình luận ở trên của tôi quá. –

+0

Trên Fedora 19 nó là 40.0.2214.91, cập nhật tự động bằng cách sử dụng YUM từ kho lưu trữ gói, tôi không có ý định tự xây dựng nó (và tôi chỉ nhớ đây là chromium chứ không phải là chrome). Tôi hiểu rằng các hệ điều hành khác nhau có các phiên bản ổn định khác nhau và có sự khác biệt. Ok, bạn đã không bao gồm thông tin đó trong câu hỏi của bạn, vì vậy bạn đã thực sự cố gắng kiểm tra xem bạn đã trả lời một câu hỏi khác một cách chính xác chưa? Hoặc tôi vẫn không thực sự hiểu câu hỏi này là gì hoặc bạn đang mong đợi loại câu trả lời nào? – Xotic750

2

deceze's answer là chính xác, tôi chỉ muốn giải thích nó từ một quan điểm khác.

bạn fn là một tham chiếu đến Function.prototype.call mà cần phải được gọi với một chức năng như this tham chiếu của nó, trong trường hợp này, bối cảnh cho callString.prototype.toUpperCase, được thừa hưởng qua ''.toUpperCase

Ngày đầu đó, String.prototype.toUpperCase cũng phải được gọi với một ngữ cảnh cụ thể, chuỗi trên chữ hoa.

Dưới đây là một cách khác để mã hóa những gì bạn muốn mà có thể giúp bạn hiểu những gì đang xảy ra.

var str = 'aaa'; 
 
    var upper = ''.toUpperCase; 
 
    var fn = upper.call; 
 
    // Now we have to specify the context for both upper and fn 
 
    console.log(fn.call(function() { return upper.call(str)})); // AAA

Trong ví dụ của bạn, fn() đang cố gắng gọi call nhưng nó không chỉ rõ bối cảnh, thường mặc định là đối tượng window nhưng trong trường hợp này nó chỉ làm cho nó undefined, mà gây nên một lỗi lạ trong Chrome (như bạn phát hiện), nhưng Firefox là rõ ràng hơn về vấn đề này,

TypeError: Function.prototype.call called on incompatible undefined

+0

developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/call –

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