JavaScript có phải là ngôn ngữ không định kiểu không?


104

Tôi thấy rằng một số người gọi JavaScript là một ngôn ngữ "được gõ động, được gõ yếu", nhưng một số người thậm chí còn nói "chưa được gõ"? Nó thực sự là gì?

Câu trả lời:


133

JavaScript không được định kiểu:


(nguồn: no.gd )

Ngay cả Brendan Eich cũng nói như vậy. Trên Twitter, anh ấy đã trả lời một chủ đề liên quan đến câu hỏi này:

... các kiểu học thuật sử dụng "không định kiểu" có nghĩa là "không có kiểu tĩnh" ...

Vì vậy, vấn đề là có một vài định nghĩa khác nhau về không định kiểu .

Một định nghĩa đã được nói đến trong một trong các câu trả lời ở trên - thời gian chạy không gắn thẻ các giá trị và chỉ coi mỗi giá trị là các bit. JavaScript thực hiện các giá trị thẻ và có các hành vi khác nhau dựa trên các thẻ đó. Vì vậy, JavaScript rõ ràng không phù hợp với danh mục này.

Định nghĩa khác là từ Lý thuyết ngôn ngữ lập trình (thứ học thuật mà Brendan đang đề cập đến). Trong miền này, không định kiểu chỉ có nghĩa là mọi thứ thuộc về một kiểu duy nhất .

Tại sao? Bởi vì một ngôn ngữ sẽ chỉ tạo ra một chương trình khi nó có thể chứng minh rằng các kiểu phù hợp (hay còn gọi là tương ứng Curry-Howard ; kiểu là định lý, chương trình là chứng minh). Điều này có nghĩa là trong một ngôn ngữ không định kiểu:

  1. Một chương trình luôn được tạo
  2. Do đó các loại luôn khớp với nhau
  3. Do đó chỉ được có một loại

Ngược lại với ngôn ngữ đã nhập:

  1. Một chương trình có thể không được tạo
  2. Bởi vì các loại có thể không khớp
  3. Vì một chương trình có thể chứa nhiều loại

Vì vậy, bạn hiểu rồi đấy, trong PLT, không định kiểu chỉ có nghĩa là nhập động và đã chỉ có nghĩa là nhập tĩnh . JavaScript chắc chắn không được gõ trong danh mục này.

Xem thêm:


6
Và tất nhiên, "không có kiểu tĩnh" cũng không giống như "không có khai báo kiểu".
Andreas Rossberg

+1. Bạn có lẽ cũng nên liên kết điều này trong câu trả lời của bạn. Bs “đánh máy yếu” này tràn lan quá.
missfaktor

2
Lý thuyết ngôn ngữ lập trình là đúng. Ảnh chụp màn hình khổng lồ không chính xác.
Alex W

2
Tôi rất vui khi thấy câu trả lời này tham chiếu đến bài đăng trên blog của Harper nhưng sẽ thật tuyệt nếu cộng đồng PLT bỏ "chưa định hình" để chuyển sang "hợp nhất". Định nghĩa "chưa được định kiểu" có nghĩa là "chỉ là bit" thực sự có ý nghĩa. Sử dụng "không định kiểu" để mô tả một ngôn ngữ có đặc tả chính thức sử dụng từ "loại" và nói rằng nó có bảy kiểu (Không xác định, Null, Số, Chuỗi, Boolean, Biểu tượng và Đối tượng) thực sự khó hiểu. Hầu hết mọi người không muốn phân biệt khái niệm loại này với định nghĩa PLT.
Ray Toal

4
Của bạn 1. 2. 3.cho một ngôn ngữ chưa định kiểu không khớp với JavaScript. Không chỉ có một kiểu - có khoảng 4 - 5. Vậy làm thế nào để chứng minh JavaScript không có kiểu?
Don Cheadle

82

mạnh / yếu có thể được xem xét liên quan đến cách trình biên dịch, nếu có, xử lý việc nhập.

  • Nhập yếu có nghĩa là trình biên dịch, nếu có, không thực thi nhập chính xác. Nếu không có sự can thiệp của trình biên dịch ngầm định, lệnh sẽ bị lỗi trong thời gian chạy.

    "12345" * 1 === 12345  // string * number => number

    Được gõ mạnh có nghĩa là có một trình biên dịch và nó muốn bạn truyền từ chuỗi sang số nguyên một cách rõ ràng.

    (int) "12345" * 1 === 12345

    Trong cả hai trường hợp, một số tính năng của trình biên dịch có thể thay đổi hoàn toàn hướng dẫn trong thời gian biên dịch để thực hiện chuyển đổi cho bạn, nếu nó có thể xác định đó là điều đúng đắn cần làm.

    Cho đến nay, JavaScript có thể được phân loại là Không được đánh máy mạnh. Điều đó có nghĩa là nó được gõ yếu hoặc không được gõ.

động / tĩnh có thể được coi là liên quan đến cách các hướng dẫn ngôn ngữ thao tác các kiểu.

  • Được nhập động nghĩa là kiểu của giá trị được thực thi, nhưng biến chỉ đơn giản là đại diện cho bất kỳ giá trị nào thuộc bất kỳ kiểu nào.

    x = 12345;    // number
    x = "string"; // string
    x = { key: "value" }; // object
    y = 123 + x; // error or implicit conversion must take place.

    Được nhập tĩnh có nghĩa làkiểu biến được thực thi mạnh mẽ và kiểu giá trị ít được thực thi hơn.

    int x = 12345; // binds x to the type int
    x = "string";  // too late, x is an integer - error
    string y = 123; // error or implicit conversion must take place.

    Cho đến nay, JavaScript có thể được phân loại là Không tĩnh. Ngoài ra, nó dường như được gõ động, nếu được nhập. Vì vậy, chúng ta cần xem Typing có nghĩa là gì.

Đã nhập có nghĩa là ngôn ngữ phân biệt giữa các kiểu khác nhau như chuỗi , số , boolean , đối tượng , mảng , null , không xác định , v.v. Ngoài ra, mỗi hoạt động được ràng buộc với các loại cụ thể. Vì vậy, bạn không thể chia một số nguyên cho một chuỗi .

    2 / "blah"  // produces NaN

Không định kiểu có nghĩa là hoạt động chia số nguyên cho chuỗi sẽ dẫn đến việc coi bốn byte đầu tiên của chuỗi số nguyên . Điều này là do các hoạt động không định kiểu diễn ra trực tiếp trên các bit, không có kiểu nào để quan sát. Kết quả sẽ là một cái gì đó khá bất ngờ:

    2 / "blah"  // will be treated as  2 / 1500275048

Vì JavaScript hoạt động theo định nghĩa được gõ, nên nó phải như vậy. Và do đó, nó phải được gõ động, và gõ yếu.

Nếu ai đó tuyên bố JavaScript là Untyped, nó chỉ là lý thuyết hàn lâm, không phải ứng dụng thực tế.


1
Nhưng tôi nghĩ rằng có một sự mâu thuẫn trong tuyên bố cuối cùng. Trong JavaScript, kết quả của phép phân chia chuỗi số nguyên được xác định rõ ràng, cho bất kỳ giá trị nào của số nguyên hoặc chuỗi. Nó chỉ là không hữu ích cho lắm!
Deniz Dogan

Nếu bạn có định nghĩa / mô tả tốt hơn, vui lòng chỉnh sửa nó. Đó là lý do tại sao tôi đặt nó thành wiki cộng đồng.
Gumbo

@skurpur: Bạn đã hoán đổi hoàn toàn ý nghĩa của nhập Động và Nhập yếu - đã sửa điều đó.
Rene Saarsoo

Ồ, xin lỗi, bạn đã chỉnh sửa nó tại sao tôi cũng đang chỉnh sửa nó và tôi đã ghi đè các thay đổi của bạn.
Rene Saarsoo

3
-1. Bạn cần phải đọc cái này .
missfaktor

48

JavaScript được gõ yếu . Nó chắc chắn không phải là "không định kiểu" nhưng bản chất được đánh máy yếu của nó cho phép rất linh hoạt về chuyển đổi ngầm định.

Hãy nhớ rằng JavaScript cũng được nhập động. Phương pháp gõ này cho phép những gì được gọi là "gõ vịt" .

Để so sánh, hãy cân nhắc rằng JavaScript không được gõ mạnh cũng như không được gõ tĩnh. Đôi khi hiểu điều gì đó không có thể giúp bạn nhìn rõ hơn nó là gì.


2
-1. Bạn cần phải đọc cái này .
missfaktor

3
Câu trả lời này tốt hơn và chính xác hơn nhiều so với câu trả lời được bình chọn hàng đầu.
Alex W

3
@JimboJonny: Không đúng. Trừ khi có sự hiện diện của một nhà phát triển Assembly, sẽ không quá sai khi nói rằng mọi ngôn ngữ đều được nhập. Không định kiểu có nghĩa là các hoạt động duy nhất trực tiếp trên thao tác bit. Nhưng hãy xem xét rằng Javascript có các phương thức toString () và parseInt (). Đừng đánh máy nhiều hơn thế.
Suamere

2
@Suamere - Đây là trích dẫn từ “Javascript: The Definitive Guide” từ O'Reilly: “Một sự khác biệt quan trọng giữa JavaScript và các ngôn ngữ như Java và C là JavaScript không được định kiểu. Điều này một phần có nghĩa là biến JavaScript có thể chứa giá trị của bất kỳ kiểu dữ liệu nào, không giống như biến Java hoặc C, chỉ có thể chứa một loại dữ liệu cụ thể mà nó được khai báo. "
Jimbo Jonny

3
Vì vậy, nếu bạn mua BS mà một số anh chàng tuyên bố rằng những người học thuật cố tình sử dụng từ "chưa được định hình" có nghĩa là "được nhập động". Sau đó, có, JavaScript không được định kiểu bởi tất cả các bằng chứng của bạn. Nhưng nếu bạn biết rằng "chưa được định kiểu" được sử dụng không chính xác để đại diện cho các ngôn ngữ thực sự được "nhập động", thì chỉ cần gọi các ngôn ngữ dang là "được nhập động". tinyurl.com/czhcv54
Suamere

8

Theo quan điểm của tác giả, JavaScript cũng được phân loại là Kiểu gõ động . Wiki tuyên bố rằng các ngôn ngữ được gõ động được kiểm tra kiểu trong thời gian chạy thay vì trong trình biên dịch trong khi kiểu gõ yếu đề cập đến khả năng thay đổi kiểu ngay lập tức trong mã của bạn. Vì vậy, có, nó được gõ cả động và gõ yếu.


6

Vấn đề ở đây làm cho rất nhiều lập trình viên bối rối là các định nghĩa như thế này không được chuẩn hóa ở đâu đó. Thuật ngữ ngôn ngữ lập trình không định kiểu là mơ hồ. Điều đó đề cập đến một ngôn ngữ không có kiểu dữ liệu hoặc một ngôn ngữ là một biến thể không định kiểu của phép tính giải tích lambda ?

JavaScript / ECMAScript có một hệ thống kiểu và tất cả các miền của chức năng của nó sẽ chấp nhận bất kỳ kiểu đặc tả Tham chiếu nào. Vì vậy, điều đó có nghĩa là JavaScript có một kiểu dữ liệu duy nhất, trong thực tế. Đó là vấn đề triển khai quan trọng hơn đối với các lập trình viên JavaScript rất cao cấp. Các lập trình viên JavaScript trung bình chỉ quan tâm đến các kiểu dữ liệu ngôn ngữ trừu tượng đã được chỉ định bởi ECMAScript.

Trong bối cảnh của các lập trình viên hàng ngày, không phải là nhà nghiên cứu hay nhà khoa học máy tính lý thuyết, thuật ngữ không định kiểu là một từ nhầm lẫn vì hầu hết mọi người không làm phép tính lambda. Do đó, thuật ngữ này gây nhầm lẫn cho nhiều người và dường như tuyên bố rằng JavaScript không có bất kỳ kiểu dữ liệu nào đơn giản là không đúng. Bất kỳ ai đã từng sử dụng typeofđều biết rằng JavaScript có các kiểu dữ liệu ngôn ngữ riêng của nó:

var test = "this is text";
typeof(test);

hoa lợi

"chuỗi"

ECMAScript định nghĩa các loại sau đây cho ngôn ngữ: undefined, null, string, boolean, number,object

http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf

Một ký hiệu chính xác hơn cho JavaScript sẽ được nhập ngầm, nhập động, hoặc nhập yếu / lỏng lẻo (hoặc một số kết hợp của chúng), trong đó JavaScript sử dụng kiểu ép buộc trong một số trường hợp, điều này làm cho kiểu ẩn vì bạn không phải chỉ định rõ ràng loại biến của bạn. Nó được nhập yếu bởi vì, không giống như một số ngôn ngữ phân biệt giữa float và integer, v.v., nó chỉ sử dụng một numberkiểu để bao gồm tất cả các số và sử dụng kiểu ép buộc đã đề cập trước đây [Phần 9 của ECMAScript Spec] , trái ngược hẳn với ngôn ngữ được đánh máy mạnh sẽ có các kiểu dữ liệu rất cụ thể (tức là bạn sẽ phải chỉ định inthoặc float).

Các định nghĩa của ngôn ngữ gõ tĩnh và động không được chuẩn hóa, tuy nhiên kích thước của một byte cũng không phải là khi máy tính bắt đầu phát triển. Nhập tĩnh và nhập động thường đề cập đến sự hiện diện của các tính năng ngôn ngữ nhất định. Một trong số đó là kiểm tra kiểu trong thời gian chạy , hay còn gọi là kiểm tra kiểu động . Nếu bạn đã sử dụng JavaScript, bạn đã biết rằng nó chắc chắn sẽ đợi đến thời gian chạy để kiểm tra các loại, đó là lý do tại sao bạn nhận được TypeErrorngoại lệ trong quá trình thực thi mã của mình. Ví dụ ở đây

Tôi nghĩ rằng câu trả lời được bình chọn nhiều nhất đang gây nhầm lẫn giữa tính đa hình của các hàm JavaScript với các hàm sẽ chấp nhận mọi thứ theo nghĩa đen (như với các biến thể không định kiểu của Lambda Calculus) là một sai lầm của Hiệp hội .


Nó không phải là một từ nhầm lẫn, nhưng vấn đề ngữ cảnh, hãy xem stackoverflow.com/questions/9154388/…
Andreas Rossberg

@AndreasRossberg Nó hoàn toàn một từ nhầm lẫn. Những gì bạn đề cập đến, trong liên kết tự quảng cáo đáng xấu hổ của mình , là một hệ thống kiểu. Lý do thuật ngữ là một từ viết sai là vì nó không rõ ràng. Hầu hết các lập trình viên nghĩ rằng kiểu dữ liệu không phải kiểu hệ thống khi họ nghe về một ngôn ngữ không kiểu . Tôi nghĩ rằng bình luận của Konrad Rudoph thực sự đưa điểm này về nhà.
Alex W

Không rõ tại sao bạn lại thấy "trơ trẽn" khi tham khảo câu trả lời trước đây của tôi thay vì lặp lại nó ở đây. Ngoài ra, tôi đã nói rõ ràng các vấn đề bối cảnh. Ngược lại với lời phàn nàn của K. Rudolph, có những định nghĩa hoàn toàn nhất quán và được chấp nhận rộng rãi trong văn học, và tôi đã trích dẫn một định nghĩa. Tất nhiên, bạn có thể thoải mái tìm thấy chúng khó hiểu trong ngữ cảnh của mình, nhưng điều đó không khiến chúng trở thành "người nói nhầm".
Andreas Rossberg

@AndreasRossberg Ngữ cảnh rất quan trọng ở đây. Câu trả lời được bình chọn nhiều nhất cho biết "untyped = no type khai báo" rõ ràng là không chính xác. Những gì tôi đang nói là nó là một từ nhầm lẫn, trong bối cảnh này. Không ai đề cập đến phép tính lambda ở đây và để làm như vậy là hơi giả tạo trong trường hợp đơn giản này.
Alex W

1

Hãy nhớ rằng JavaScript cho phép bạn hỏi cái gì là typeof(your_variable)và so sánh các loại: 5==="5"trả về false. Vì vậy, tôi không nghĩ bạn có thể gọi nó là không định kiểu.

Nó được gõ động và (ước tính là) yếu. Bạn có thể muốn biết nó sử dụng kiểu gõ Duck (xem liên kết của andrew) và cung cấp OOP thông qua Prototyping thay vì các lớp và kế thừa.


Việc nhập một biến không liên quan gì đến việc ép kiểu các giá trị. Nó liên quan đến việc khai báo các kiểu cho các biến. Javascript hoàn toàn không có một cấu trúc nào cho việc này, đó là lý do tại sao rất ít javascripter thậm chí hiểu được khái niệm này và tại sao rất nhiều người trong số họ hiểu sai cách nhập biến như một cái gì đó liên quan đến việc so sánh hoặc ép kiểu biến. Trong JS, bạn không thể khai báo String a = "blah";hoặc var a:String = 'blah';(tức là các biến đã nhập). Đó là lý do tại sao nó không được định kiểu.
Jimbo Jonny

0

Trong khi nó được gõ (bạn có thể hỏi "typeof someVar" và tìm hiểu kiểu cụ thể của nó, nó rất yếu.

Được:

  var a = "5";

bạn có thể nói rằng a là một chuỗi. Tuy nhiên, nếu sau đó bạn viết:

  var b = a + 10;

b là một int bằng 15, vì vậy a hoạt động giống như một int. Tất nhiên, sau đó bạn có thể viết:

  var c = a + "Hello World";

và c sẽ bằng "5Hello World", vì vậy a lại hoạt động giống như một chuỗi.


1) Truyền một giá trị! = Nhập một biến 2) nó không yếu, nó không tồn tại. Bạn không thể nhập một biến trong javascript.
Jimbo Jonny

Tò mò tại sao câu trả lời này lại nhận được hai phiếu bầu. Định nghĩa tôi đã tìm thấy về tính năng gõ yếu nói chính xác điều này: Loại giá trị được xác định dựa trên cách nó được sử dụng.
aioobe

Điều này có chính xác không? Tôi nhận được bbằng 510: Ideone.com/BRcSW7
aioobe
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.