Javascript có phải là ngôn ngữ lập trình chức năng không


34
  • Javascript có phải là ngôn ngữ chức năng không? Tôi biết nó có các đối tượng và bạn cũng có thể thực hiện OOP với nó, nhưng nó cũng là một ngôn ngữ chức năng, nó có thể được sử dụng theo cách đó không?
  • Bạn biết làm thế nào OOP trở thành / có vẻ giống như sự tiến hóa tiếp theo trong lập trình, điều đó có nghĩa là 'Lập trình chức năng' là sự tiến hóa tiếp theo (Lưu ý: đây KHÔNG phải là lời nhắc cho ý kiến ​​NHƯNG một lời nhắc cho câu trả lời dựa trên bằng chứng thực tế nhiều hơn cho người điều hành hơn là người đóng góp;)).
  • Tôi học tốt nhất qua các ví dụ, có thể ai đó có thể hiển thị thực hiện cùng một nhiệm vụ theo cách OOP và sau đó theo cách Lập trình chức năng để bản thân tôi hiểu và so sánh những gì lập trình chức năng thực hiện / là gì.

Tôi thực sự không hiểu hoàn toàn 'Lập trình chức năng': P Vì vậy, so sánh Javascript với lập trình chức năng có thể hoàn toàn không chính xác.

Để đặt lập trình hàm theo thuật ngữ laymans: nó chỉ đơn giản là lợi ích của việc trừu tượng hóa thông qua các hàm ẩn danh?

Hay cách đó quá đơn giản? Nói một cách đơn giản, OOP là lợi ích của sự trừu tượng hóa thông qua các đối tượng, nhưng tôi tin rằng đó là một chút quá đơn giản để mô tả OOP.

Đây có phải là một ví dụ tốt về lập trình chức năng? ...

Ví dụ OOP Javascript:

// sum some numbers
function Number( v )
{ 
  this.val = v;
}

Number.prototype.add( /*Number*/ n2 )
{
    this.val += n2.val;
}

Ví dụ lập trình hàm:

function forEach(array, action) 
{
   for (var i = 0; i < array.length; i++)
       action(array[i]);
}  

function add(array)
{
    var i=0;
    forEach(array, function(n)
    {
        i += n;
    });
    return i;
}

var res = add([1,9]);

Nó phụ thuộc vào định nghĩa của "ngôn ngữ lập trình chức năng". Theo nghĩa rộng, có thể hiểu là khả năng xây dựng các giá trị chức năng với các giá trị đóng, nghĩa là có cấu trúc "lambda" (theo nghĩa của lambda-compus), và sau đó Javascript phù hợp với dự luật.
Stilenkevitch Basile

2
Or is that way too simple?Yeap, nó là. Các hàm ẩn danh đôi khi được liên kết với các ngôn ngữ chức năng và các ngôn ngữ đa mô hình ủng hộ lập trình chức năng, nhưng chúng không phải là một đặc tính duy nhất của các ngôn ngữ chức năng. Nhưng nếu bạn thấy chúng là một triển khai của calcul-tính toán, thì chúng là một phần cốt lõi của lập trình chức năng, điểm chính là nó không đơn giản như vậy :)
yannis

Thiết kế của Javascript ngăn chặn việc triển khai có thể thực hiện tối ưu hóa cuộc gọi đuôi. Trong sách của tôi, một mình ngăn chặn nó được dán nhãn là chức năng.
dan_waterworth

I know it has objects & you can do OOP with it alsoKhông, bạn không thể. Đó là lập trình dựa trên nguyên mẫu giúp loại bỏ sự phân biệt giữa lớp và đối tượng. Cá nhân tôi coi lập trình dựa trên nguyên mẫu là thiếu sót ở cấp độ cơ bản này.
RokL

Javascript không phải là một ngôn ngữ chức năng, chắc chắn nó có các tính năng chức năng, nhưng C bắt buộc cũ cũng vậy, trên thực tế mọi ngôn ngữ đều có các tính năng chức năng cơ bản. Một ngôn ngữ chức năng thuần túy, chẳng hạn như Haskell, ML, v.v., là một ngôn ngữ khai báo, không bắt buộc.
ALXGTV

Câu trả lời:


72

Javascript có phải là ngôn ngữ chức năng không? Tôi biết nó có các đối tượng và bạn cũng có thể thực hiện OOP với nó, nhưng nó cũng là một ngôn ngữ chức năng, nó có thể được sử dụng theo cách đó không?

Đôi khi, mọi người sẽ nói lập trình chức năng, khi ý nghĩa của chúng là lập trình bắt buộc hoặc lập trình thủ tục . Nói đúng ra, lập trình chức năng là:

Trong khoa học máy tính, lập trình chức năng là một mô hình lập trình coi việc tính toán như là sự đánh giá các hàm toán học và tránh trạng thái và dữ liệu đột biến . Nó nhấn mạnh việc áp dụng các chức năng, trái ngược với phong cách lập trình mệnh lệnh, trong đó nhấn mạnh đến những thay đổi về trạng thái. Lập trình hàm có nguồn gốc từ phép tính lambda, một hệ thống chính thức được phát triển vào những năm 1930 để nghiên cứu định nghĩa hàm, ứng dụng hàm và đệ quy. Nhiều ngôn ngữ lập trình chức năng có thể được xem như là công phu trên phép tính lambda.

Mặc dù Javascript không được biết đến rộng rãi hoặc được sử dụng như một ngôn ngữ chức năng, nhưng nó có một số yếu tố chức năng :

JavaScript có nhiều điểm chung với Scheme. Đó là một ngôn ngữ năng động. Nó có một kiểu dữ liệu linh hoạt (mảng) có thể dễ dàng mô phỏng các biểu thức s. Và quan trọng nhất, chức năng là lambdas.

Scheme là một phương ngữ của Lisp , và có lẽ là một trong những ngôn ngữ mà hầu hết các lập trình viên nghĩ đến khi họ thảo luận về lập trình chức năng. Khi nói đến hướng đối tượng , Javascript là ngôn ngữ hướng đối tượng. Nhưng định hướng đối tượng của nó là nguyên mẫu dựa trên :

Lập trình dựa trên nguyên mẫu là một kiểu lập trình hướng đối tượng, trong đó các lớp không có mặt và việc tái sử dụng hành vi (được gọi là kế thừa trong các ngôn ngữ dựa trên lớp) được thực hiện thông qua quá trình nhân bản các đối tượng hiện có làm nguyên mẫu. Mô hình này cũng có thể được gọi là lập trình không phân lớp, hướng mẫu hoặc dựa trên cá thể. Delegation là tính năng ngôn ngữ hỗ trợ lập trình dựa trên nguyên mẫu.

Vì vậy, mặc dù Javascript hướng đối tượng, nhưng nó không tuân theo mô hình dựa trên lớp phổ biến hơn , cũng như các ngôn ngữ như C ++, C #, Java và PHP (và khá nhiều ngôn ngữ khác). Và tất nhiên đó cũng là một ngôn ngữ bắt buộc, dẫn đến sự nhầm lẫn với lập trình chức năng mà tôi đã mô tả ở trên.

Bạn biết làm thế nào OOP trở thành / dường như là sự phát triển tiếp theo trong lập trình, điều đó có nghĩa là 'Lập trình chức năng' là sự tiến hóa tiếp theo

Định hướng đối tượng và lập trình chức năng chỉ là hai trong số nhiều mô hình lập trình khác nhau , chúng là các phong cách lập trình khác nhau với các khái niệm và trừu tượng khác nhau. Từ khóa là "khác nhau". Không có một mô hình nào tốt hơn các mô hình khác hoặc phát triển hơn các mô hình khác, mỗi mô hình đều phù hợp với một số tình huống tốt hơn các kịch bản khác. Một số có thể khá già về nguồn gốc so với những người khác, nhưng về mặt tiến hóa làm cho chúng tốt hơn, vì chúng đã tồn tại lâu hơn. Nhưng đó không phải là một cách nhìn rất thông minh.

Javascript, như tôi đã mô tả ở trên và cũng như một vài ngôn ngữ khác, là đa mô hình. Nó cho phép bạn viết mã theo kiểu bắt buộc, dựa trên nguyên mẫu và hướng đối tượng. Tùy thuộc vào bạn để chọn cái nào phù hợp nhất với bất cứ thứ gì bạn đang xây dựng. Ngoài ra còn có một số ngôn ngữ mô hình duy nhất, ví dụ kinh điển là Java, chỉ cho phép lập trình hướng đối tượng dựa trên lớp 1 .

Bạn nên thực sự chống lại bất kỳ sự thôi thúc nào để coi ngôn ngữ & mô thức là tuyên bố thời trang. Có một sự dè bỉu ngoài kia, chủ yếu được viết bởi các fanboys / fangirl hoặc những người tiếp thị, với rất ít kiến ​​thức (nếu có) và hiểu biết về lập trình. Các thuật ngữ như "tốt hơn", "phát triển hơn", v.v., đơn giản là không áp dụng.

Tôi học tốt nhất qua các ví dụ, có thể ai đó có thể hiển thị thực hiện cùng một nhiệm vụ theo cách OOP và sau đó theo cách Lập trình chức năng để bản thân tôi hiểu và so sánh những gì lập trình chức năng thực hiện / là gì.

Đó sẽ là một cách khủng khiếp để học hỏi. Định hướng chức năng và đối tượng là các phong cách khá khác nhau, và bất kỳ ví dụ nào ngoài những kiểu đơn giản khủng khiếp sẽ không phù hợp với một hoặc một phong cách khác.

1 Nhưng gần đây cố gắng mở rộng phạm vi của nó sang lập trình chung, hãy xem điều đó diễn ra như thế nào.


Cuối cùng:

  • Tập trung vào việc học Javascript, đây là một ngôn ngữ hữu ích và cực kỳ hữu ích. Học ngôn ngữ, không cường điệu.
  • Khá nhiều mô hình khác nhau, tất cả đều hữu ích như nhau. Tùy thuộc vào bạn để chọn cái nào bạn thích và cái nào phù hợp nhất với bất cứ thứ gì bạn đang xây dựng.
  • Nếu bạn muốn học lập trình chức năng, hãy chọn một ngôn ngữ phù hợp hơn, như Scheme hoặc Clojure . Nhưng trước tiên bạn sẽ cần hiểu các khái niệm toán học liên quan.
  • Làm một số nghiên cứu trước khi bạn yêu cầu. Hầu hết các câu hỏi của bạn được trả lời bởi các bài viết Wikipedia có liên quan. Biết cách nghiên cứu và cách hỏi là một kỹ năng cực kỳ quan trọng đối với bất kỳ lập trình viên nào.

5
+1 Phản ứng tuyệt vời. Do cách thức cấu trúc giáo dục lập trình, các lập trình viên mới dường như nghĩ rằng các mô hình là độc quyền và rời rạc, nhưng họ thì không. Cố gắng viết mã OOP tận dụng các khái niệm chức năng khi có ý nghĩa để làm như vậy. Lập trình hướng sự kiện là một mô hình, nhưng các khía cạnh của EDP ảnh hưởng chắc chắn đến mọi chương trình gui và web. Đa hình , một tính năng cốt lõi của OOP, là chương trình thực sự chung chung. Đặt tên cho những ý tưởng này giúp chúng tôi khái niệm hóa lập trình tốt, nhưng bạn không nên sử dụng một ý tưởng để loại trừ những người khác.
kojiro

Mặc dù câu hỏi ban đầu và câu trả lời của bạn đang mô tả Javascript và nó liên quan đến lập trình chức năng, tôi nghĩ rằng câu trả lời của bạn là một trong những so sánh tốt hơn giữa OO và lập trình chức năng mà tôi đã thấy. Làm tốt.
AnotherDeveloper

Đây là một cách học kinh khủng. Tôi vừa đọc xong cuốn sách này đưa ra một vấn đề và giải quyết nó với một loạt các mô hình, bao gồm các kiểu OOP và FP: github.com/crista/exercises-in-programming-style . Tôi đã học nhiều điều từ nó!
Nick

@nick Đó chỉ có thể mô tả cho bạn những gì mô hình trông giống như và như thế nào nó hoạt động, nhưng nó không cho bạn biết lý do tại sao , mà cho là là khía cạnh quan trọng nhất. Nhưng bạn cần tìm hiểu làm thế nào trước khi bạn có thể tìm hiểu lý do tại sao :) đôi khi chúng ta quên rằng những điều này là một quá trình.
Matthew Brent

8

Javascript có thể được sử dụng như một ngôn ngữ chức năng, trên thực tế, nó hoạt động khá tốt. Có thể thực hiện monads đã hỗ trợ cho một cấu trúc lambda vv Nó không phải là độc quyền một ngôn ngữ chức năng ở chỗ nó cũng có rất nhiều tính năng hướng đối tượng nhưng nó có thể được sử dụng theo cách đó. Trên thực tế tôi thấy rằng sử dụng Javascript như một ngôn ngữ chức năng là một cách tuyệt vời để sử dụng nó. (Ví dụ jQuery và underscore.js)


tốt & súc tích! Đồng ý rằng lập trình chức năng thường là cách dễ nhất để hoàn thành công việc trong js.
bunglestink

Thậm chí thú vị hơn các đơn nguyên, bạn có thể triển khai các mũi tên là JS ( cs.umd.edu/projects/PL/arrowlets ). Bây giờ, về lý do tại sao bất cứ ai cũng muốn mũi tên trong JavaScript, đó là một câu hỏi mở. Nhưng nó có thể được thực hiện.
rtperson

Tôi sẽ thừa nhận rằng tôi không hiểu đủ về mũi tên để biết liệu chúng có hữu ích không. Nhưng tôi đang làm việc trên một cuốn sách về Monads trong Javascript và có thể thêm một chương về Mũi tên ( shop.oreilly.com/product/0636920023890.do )
Zachary K

6

Sự tiến hóa thông thường có nghĩa là một sự thay đổi gia tăng . OOP không phải là một bổ sung gia tăng cho lập trình thủ tục - trên thực tế, nó hoàn toàn trực giao với một mô hình lập trình cơ bản và có thể được kết hợp với bất kỳ trong số chúng. Lập trình hàm không phải là sự bổ sung gia tăng cho thủ tục, OOP hay bất cứ điều gì - nó là một cơ sở thay thế để thể hiện các nguyên tắc tính toán cơ bản, và nó thực sự là lần đầu tiên cơ sở được hình thành từ lâu trước khi các máy tính đầu tiên xuất hiện. Điều quan trọng là phải hiểu rằng tất cả các hệ thống cơ bản như vậy là tương đương (nghĩa là, một hệ thống có thể được thể hiện dưới dạng khác).

Để hiểu cách tiếp cận chức năng, trước tiên bạn cần có được phép toán cơ bản . Nếu bạn muốn cảm nhận về ý nghĩa của việc viết mã theo kiểu chức năng trong Javascript, hãy bắt đầu sử dụng jQuery .


2

Không.

JavaScript là ngôn ngữ hướng đối tượng trước hết.

Điều đó không có nghĩa là bạn không thể viết các chương trình JavaScript theo kiểu chức năng, vì bạn có thể áp dụng một kiểu chức năng trong bất kỳ ngôn ngữ hoàn chỉnh Turing nào nếu bạn cố gắng hết sức. Bạn có thể làm lập trình chức năng trong trình biên dịch chương trình nếu bạn muốn. Nhưng điều này không làm cho mọi ngôn ngữ hoạt động. Bạn cũng có thể gọi Haskell là bắt buộc hoặc Java là ngôn ngữ lập trình logic - nếu bạn thực hiện phương pháp này, các thuật ngữ sẽ sớm trở nên vô nghĩa.

IMO cách phân loại ngôn ngữ thành mô hình phù hợp là xem xét:

  • Kiểu thống trị được kích hoạt bởi các cấu trúc ngôn ngữ (rõ ràng là OOP cho JavaScript, ngôn ngữ chức năng thay vì nhấn mạnh các chức năng và giá trị dữ liệu không thay đổi)
  • Mô hình nào được hỗ trợ trong các thư viện cốt lõi của ngôn ngữ (rõ ràng là OOP cho JavaScript)
  • Những tính năng nào bị vô hiệu hóa hoặc không được khuyến khích trong ngôn ngữ (ngôn ngữ chức năng không khuyến khích hoặc cấm các biến có thể thay đổi, đây không phải là trường hợp của JavaScript)
  • Phong cách phát triển nào phổ biến trong cộng đồng các nhà phát triển sử dụng ngôn ngữ (một lần nữa, OOP rõ ràng là phổ biến trong thế giới JavaScript)

Cá nhân tôi thấy khá thú vị khi nhiều người thích khẳng định một ngôn ngữ là "chức năng" chỉ vì đó là một thuật ngữ hợp thời tại thời điểm này :-)

Nếu bạn muốn có một viễn cảnh hơi dài nhưng thú vị về mô hình lập trình qua nhiều năm, thì đáng để xem video "Ngôn ngữ lập trình cuối cùng" của chú Bob Martin . Đối với tôi, cái nhìn sâu sắc từ cuộc nói chuyện này là các mô hình lập trình được xác định bởi những tính năng họ lấy đi , chứ không phải những tính năng họ đưa vào ......


What is the dominant style enabled by the language constructsTôi dám cho bạn thử và áp dụng điều đó cho Perl ... Hoặc bất kỳ điểm nào khác của bạn, thực sự :)
yannis

2
Perl? Thử thách tốt! Nó giống như ngôn ngữ lắp ráp theo nghĩa bạn có thể hack gần như bất kỳ mô hình nào bạn muốn cùng nhau, nhưng theo cách sử dụng phổ biến mà tôi đã thấy (kịch bản), nó được sử dụng chủ yếu như một ngôn ngữ bắt buộc / thủ tục.
mikera

Vâng, oop cũng khá phổ biến. Trong một cách tất nhiên. Và, chức năng cũng vậy , mặc dù không phổ biến. perl chỉ là perl, không có ý nghĩa trong việc cố gắng hiểu ý nghĩa của nó :)
yannis

JavaScript có nhiều chức năng hơn Java một chút vì ít nhất nó có các hàm đóng và lớp đầu tiên. Nhưng quyền của bạn, JavaScript cũng có chức năng như C #.
Raynos

2

Javascript là nguyên mẫu đầu tiên, với các khả năng chức năng - được cấp bởi nó sử dụng các chức năng như các đối tượng hạng nhất.

Điều này có nghĩa là bạn có thể sử dụng các hàm làm dữ liệu, có tác dụng gây tò mò trong việc giảm nhu cầu về các biến duy trì trạng thái. Nếu bạn thấy rằng mình đang tìm kiếm câu lệnh var hoặc đang sử dụng một hoặc nhiều câu lệnh "if", thì bạn đang đi lạc từ một kiểu chức năng.

Một đặc điểm riêng đáng chú ý khác của phong cách chức năng là các hàm CHỈ nên trả về kết quả đánh giá của chúng và không có tác dụng phụ đối với trạng thái bên ngoài phạm vi của chúng:

// oops, this is producing a side effect
function sideEffecter(){//theres no input...        
    window.thingy = 'foo';
    // hey, this isn't returning anything!!!
} 

Các ngôn ngữ chức năng là không phá hủy - có nghĩa là chúng không làm thay đổi đầu vào, mà là trả về dữ liệu hoàn toàn mới dựa trên đầu vào. Xem chủ đề này: https://stackoverflow.com/questions/749084/jquery-map-vs-each

Các ngôn ngữ chức năng cũng có rất nhiều phương thức chung - với các tên như "bản đồ", "gấp", "giảm" danh sách quy trình / bộ sưu tập. Trong JS, không giống như các ngôn ngữ khác, chúng ta phải xử lý các ngôn ngữ này thành hiện thực - xem các thư viện như underscore.js để biết một số ví dụ, mặc dù cách triển khai mới nhất của JS có một số trong số này.

Điều quan trọng cần ghi nhớ (IMO) là trong khi JS có thể sử dụng một số mẫu chức năng, thì nó không phải lúc nào cũng được trang bị tốt để thực thi sau đó.

Lấy vòng lặp trên một mảng, ví dụ. Bạn có thể làm điều này bằng cách sử dụng một kiểu chức năng hoặc các cấu trúc vòng lặp gốc - và nói chung, vòng lặp có hiệu suất cao hơn. Lấy ví dụ này - đánh nó với các vòng có kích thước tăng dần và ghi lại thời gian thực hiện trong các trình duyệt khác nhau (tôi đã làm điều này rồi, nhưng tôi đã mất điểm chuẩn - xin lỗi!):

var test = ['foo', 'bar', 'baz'], removeFunc, removeLoop;

//(semi)functional style...
// to be really functional each condition in the ternary would be another function
removeFunc = function(src, trg) {
    return src.length === 0 ? 
        src : 
            src[0] === trg ? 
                src.slice(1) : 
                    [src[0]].concat(removeFunc(src.slice(1), trg));
};

//but this is faster
removeLoop = function(src, trg){
    var len = src.length, // using variables to represent state...
        i=0, 
        result = [];        
    while(i < n){
       if(src[i] !== trg){
          result.push(src[i]);
       }
       i = i+1;
    }
}

Ngoài ra, nếu bạn sử dụng cấu trúc chức năng để đánh các vòng có kích thước đáng kể và không sử dụng một số hình thức quản lý ngăn xếp đặc biệt, bạn có thể làm ngập ngăn xếp (mặc dù, để công bằng, bạn cần có một danh sách LỚN để điều này xảy ra. ..). Bạn cũng phải tính đến sự pha trộn các tối ưu hóa biến thể trong mỗi trình duyệt - mặc dù nếu bạn đang làm việc trong môi trường Node.js thì đây rõ ràng là một mục tiêu cố định.

Điều đó không có nghĩa là bạn không nên sử dụng các cấu trúc chức năng trong Javascript - chỉ cần lưu ý về những hạn chế trong quá trình triển khai so với môi trường của nó.

Dưới đây là một số liên kết có thể bạn quan tâm:

Một chương hay về Lập trình chức năng trong Javascript từ "Javascript xuất sắc"

Tiểu thư

một người bạn của tôi đã viết một thư viện JS dựa trên Little Schemer

Một hướng dẫn tốt về Đề án có thể giúp bạn hiểu rõ hơn về FP

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.