Tại sao tính bất biến rất quan trọng (hoặc cần thiết) trong JavaScript?


206

Tôi hiện đang làm việc trên các khung công tác React JSReact Native . Trên con đường nửa đường, tôi đã bắt gặp Thư viện bất biến hoặc thư viện bất biến-JS , khi tôi đang đọc về triển khai Flux và Redux của Facebook.

Câu hỏi là, tại sao sự bất biến rất quan trọng? Điều gì là sai trong việc đột biến các đối tượng? Nó không làm cho mọi thứ đơn giản?

Đưa ra một ví dụ, chúng ta hãy xem xét một ứng dụng đọc Tin tức đơn giản với màn hình mở là chế độ xem danh sách các tiêu đề tin tức.

Nếu tôi đặt nói một mảng các đối tượng có giá trị ban đầu, tôi không thể thao tác nó. Đó là những gì nguyên tắc bất biến nói, phải không? (Sửa lỗi cho tôi nếu tôi sai.) Nhưng, nếu tôi có một đối tượng Tin tức mới phải cập nhật thì sao? Trong trường hợp thông thường, tôi có thể vừa thêm đối tượng vào mảng. Làm thế nào để tôi đạt được trong trường hợp này? Xóa cửa hàng và tạo lại nó? Không thêm một đối tượng vào mảng là một hoạt động ít tốn kém hơn?



2
Cấu trúc dữ liệu bất biến và chức năng thuần túy dẫn đến tính minh bạch tham chiếu, giúp dễ dàng hơn rất nhiều để suy luận về hành vi của chương trình của bạn. Bạn cũng có thể quay lại miễn phí khi sử dụng cấu trúc dữ liệu chức năng.
WorBlux

Tôi đã cung cấp một quan điểm Redux @bozzmob.
prosti

1
Nói chung, có thể hữu ích khi tìm hiểu về tính bất biến nói chung như là một khái niệm về mô hình chức năng thay vì cố gắng nghĩ rằng JS có một số thứ để làm với nó. React được viết bởi những người hâm mộ lập trình chức năng. Bạn phải biết những gì họ biết để hiểu họ.
Gherman

Nó không cần thiết, nhưng nó cung cấp một số sự đánh đổi tốt đẹp. Trạng thái có thể thay đổi là phần mềm khi các bộ phận chuyển sang phần cứng
Kristian Dupont

Câu trả lời:


196

Gần đây tôi đã nghiên cứu cùng một chủ đề. Tôi sẽ làm hết sức mình để trả lời (các) câu hỏi của bạn và cố gắng chia sẻ những gì tôi đã học được cho đến nay.

Câu hỏi là, tại sao sự bất biến rất quan trọng? Điều gì là sai trong việc đột biến các đối tượng? Nó không làm cho mọi thứ đơn giản?

Về cơ bản, nó đi đến thực tế là tính bất biến làm tăng khả năng dự đoán, hiệu suất (gián tiếp) và cho phép theo dõi đột biến.

Dự đoán

Đột biến che giấu sự thay đổi, tạo ra tác dụng phụ (không mong muốn), có thể gây ra các lỗi khó chịu. Khi bạn thực thi tính bất biến, bạn có thể giữ kiến ​​trúc ứng dụng và mô hình tinh thần của mình đơn giản, điều này giúp bạn dễ dàng suy luận về ứng dụng của mình hơn.

Hiệu suất

Mặc dù việc thêm các giá trị vào một Đối tượng bất biến có nghĩa là cần tạo một thể hiện mới trong đó các giá trị hiện tại cần được sao chép và các giá trị mới cần được thêm vào Đối tượng mới có chi phí bộ nhớ, Các đối tượng bất biến có thể sử dụng chia sẻ cấu trúc để giảm bộ nhớ trên không.

Tất cả các bản cập nhật trả về các giá trị mới, nhưng các cấu trúc bên trong được chia sẻ để giảm đáng kể việc sử dụng bộ nhớ (và đập mạnh). Điều này có nghĩa là nếu bạn nối vào một vectơ có 1000 phần tử, thì nó không thực sự tạo ra một vectơ mới 1001 phần tử. Nhiều khả năng, trong nội bộ chỉ có một vài đối tượng nhỏ được phân bổ.

Bạn có thể đọc thêm về điều này ở đây .

Theo dõi đột biến

Bên cạnh việc giảm mức sử dụng bộ nhớ, tính không thay đổi cho phép bạn tối ưu hóa ứng dụng của mình bằng cách sử dụng công bằng giá trị tham chiếu và giá trị. Điều này làm cho nó thực sự dễ dàng để xem nếu có bất cứ điều gì đã thay đổi. Ví dụ một sự thay đổi trạng thái trong một thành phần phản ứng. Bạn có thể sử dụng shouldComponentUpdateđể kiểm tra xem trạng thái có giống nhau hay không bằng cách so sánh các Đối tượng trạng thái và ngăn kết xuất không cần thiết. Bạn có thể đọc thêm về điều này ở đây .

Tài nguyên bổ sung:

Nếu tôi đặt nói một mảng các đối tượng có giá trị ban đầu. Tôi không thể thao túng nó. Đó là những gì nguyên tắc bất biến nói, phải không? (Đúng tôi nếu tôi sai). Nhưng, nếu tôi có một đối tượng Tin tức mới phải cập nhật thì sao? Trong trường hợp thông thường, tôi có thể vừa thêm đối tượng vào mảng. Làm thế nào để tôi đạt được trong trường hợp này? Xóa cửa hàng & tạo lại nó? Không thêm một đối tượng vào mảng là một hoạt động ít tốn kém hơn?

Vâng cái này đúng rồi. Nếu bạn bối rối về cách thực hiện điều này trong ứng dụng của mình, tôi sẽ khuyên bạn nên xem cách redux thực hiện điều này để làm quen với các khái niệm cốt lõi, nó đã giúp tôi rất nhiều.

Tôi thích sử dụng Redux làm ví dụ vì nó bao hàm sự bất biến. Nó có một cây trạng thái bất biến duy nhất (được gọi là store) trong đó tất cả các thay đổi trạng thái được thể hiện rõ ràng bằng cách gửi các hành động được xử lý bởi một bộ giảm chấp nhận trạng thái trước đó cùng với các hành động đã nói (một lần) và trả về trạng thái tiếp theo của ứng dụng của bạn . Bạn có thể đọc thêm về các nguyên tắc cốt lõi của nó ở đây .

Có một khóa học redux tuyệt vời trên egghead.io trong đó Dan Abramov , tác giả của redux, giải thích các nguyên tắc này như sau (Tôi đã sửa đổi mã một chút để phù hợp hơn với kịch bản):

import React from 'react';
import ReactDOM from 'react-dom';

// Reducer.
const news = (state=[], action) => {
  switch(action.type) {
    case 'ADD_NEWS_ITEM': {
      return [ ...state, action.newsItem ];
    }
    default: {
        return state;
    }
  }
};

// Store.
const createStore = (reducer) => {
  let state;
  let listeners = [];

  const subscribe = (listener) => {
    listeners.push(listener);

    return () => {
      listeners = listeners.filter(cb => cb !== listener);
    };
  };

  const getState = () => state;

  const dispatch = (action) => {
    state = reducer(state, action);
    listeners.forEach( cb => cb() );
  };

  dispatch({});

  return { subscribe, getState, dispatch };
};

// Initialize store with reducer.
const store = createStore(news);

// Component.
const News = React.createClass({
  onAddNewsItem() {
    const { newsTitle } = this.refs;

    store.dispatch({
      type: 'ADD_NEWS_ITEM',
      newsItem: { title: newsTitle.value }
    });
  },

  render() {
    const { news } = this.props;

    return (
      <div>
        <input ref="newsTitle" />
        <button onClick={ this.onAddNewsItem }>add</button>
        <ul>
          { news.map( ({ title }) => <li>{ title }</li>) }
        </ul>
      </div>
    );
  }
});

// Handler that will execute when the store dispatches.
const render = () => {
  ReactDOM.render(
    <News news={ store.getState() } />,
    document.getElementById('news')
  );
};

// Entry point.
store.subscribe(render);
render();

Ngoài ra, các video này còn trình bày chi tiết hơn về cách đạt được tính bất biến cho:


1
@naomik cảm ơn đã phản hồi! Ý định của tôi là minh họa khái niệm và cho thấy rõ ràng rằng các Đối tượng không bị đột biến và không nhất thiết phải chỉ ra cách thực hiện nó theo mọi cách. Tuy nhiên, ví dụ của tôi có thể hơi khó hiểu, tôi sẽ cập nhật nó một chút.
danillouz

2
@bozzmob bạn được chào đón! Không, điều đó không chính xác, bạn cần phải thực thi tính bất biến trong bộ giảm tốc. Điều này có nghĩa là bạn có thể làm theo các chiến lược như được trình bày trong video hoặc sử dụng thư viện như bất biến. Bạn có thể tìm thêm thông tin ở đâyở đây .
danillouz

1
@naomik ES6 constkhông phải là về sự bất biến. Mathias Bynens đã viết một bài viết blog tuyệt vời về nó.
Lea Rosema

1
@terabaud cảm ơn vì đã chia sẻ liên kết. Tôi đồng ý đó là một sự khác biệt quan trọng. ^ _ ^
Cảm ơn bạn

4
Vui lòng giải thích điều này "Đột biến che giấu sự thay đổi, tạo ra các tác dụng phụ (không mong muốn), có thể gây ra các lỗi khó chịu. Khi bạn thực thi tính bất biến, bạn có thể giữ kiến ​​trúc ứng dụng và mô hình tinh thần của mình đơn giản, giúp bạn dễ dàng suy luận về ứng dụng của mình hơn." Bởi vì điều này hoàn toàn không đúng trong bối cảnh của JavaScript.
Pavle Lekic

143

Một cái nhìn trái ngược về sự bất biến

TL / DR: Tính không thay đổi là xu hướng thời trang hơn là sự cần thiết trong JavaScript. Nếu bạn đang sử dụng React, nó sẽ cung cấp một cách giải quyết gọn gàng cho một số lựa chọn thiết kế khó hiểu trong quản lý nhà nước. Tuy nhiên, trong hầu hết các tình huống khác, nó sẽ không thêm đủ giá trị so với độ phức tạp mà nó giới thiệu, phục vụ nhiều hơn để đệm một bản lý lịch hơn là để đáp ứng nhu cầu thực tế của khách hàng.

Câu trả lời dài: đọc bên dưới.

Tại sao tính bất biến rất quan trọng (hoặc cần thiết) trong javascript?

Vâng, tôi rất vui vì bạn đã hỏi!

Cách đây một thời gian, một anh chàng rất tài năng tên là Dan Abramov đã viết một thư viện quản lý nhà nước javascript có tên Redux , sử dụng các hàm thuần túy và bất biến. Ông cũng thực hiện một số video thực sự thú vị khiến ý tưởng thực sự dễ hiểu (và bán).

Thời điểm là hoàn hảo. Sự mới lạ của Angular đang mờ dần và thế giới JavaScript đã sẵn sàng khắc phục điều mới nhất có mức độ tuyệt vời và thư viện này không chỉ đổi mới mà còn hoàn hảo với React đang được bán bởi một cường quốc khác ở Thung lũng Silicon .

Đáng buồn thay, có thể là thời trang quy tắc trong thế giới của JavaScript. Bây giờ Abramov đang được ca ngợi như một vị á thần và tất cả chúng ta chỉ là những người phàm trần phải tự chịu đựng Đạo bất biến ... Điều đó có ý nghĩa hay không.

Điều gì là sai trong việc đột biến các đối tượng?

Không có gì!

Trong thực tế, các lập trình viên đã và đang biến đổi các đối tượng trong chừng mực ... miễn là có các đối tượng bị đột biến. Hơn 50 năm phát triển ứng dụng nói cách khác.

Và tại sao lại phức tạp hóa mọi thứ? Khi bạn có đối tượng catvà nó chết, bạn có thực sự cần một giây catđể theo dõi sự thay đổi không? Hầu hết mọi người sẽ chỉ nói cat.isDead = truevà được thực hiện với nó.

Không (biến đổi đối tượng) làm cho mọi thứ đơn giản?

ĐÚNG! .. Tất nhiên là thế!

Đặc biệt trong JavaScript, trong thực tế là hữu ích nhất được sử dụng để hiển thị chế độ xem của một số trạng thái được duy trì ở nơi khác (như trong cơ sở dữ liệu).

Điều gì xảy ra nếu tôi có một đối tượng Tin tức mới phải được cập nhật? ... Làm thế nào để tôi đạt được trong trường hợp này? Xóa cửa hàng & tạo lại nó? Không thêm một đối tượng vào mảng là một hoạt động ít tốn kém hơn?

Chà, bạn có thể đi theo cách tiếp cận truyền thống và cập nhật Newsđối tượng, do đó biểu diễn trong bộ nhớ của đối tượng đó sẽ thay đổi (và chế độ xem được hiển thị cho người dùng, hoặc người ta sẽ hy vọng) ...

Hay cách khác...

Bạn có thể thử cách tiếp cận FP / Bất biến gợi cảm và thêm các thay đổi của bạn vào Newsđối tượng vào một mảng theo dõi mọi thay đổi lịch sử để sau đó bạn có thể lặp lại qua mảng và tìm ra cách biểu diễn trạng thái chính xác (phew!).

Tôi đang cố gắng học những gì ngay tại đây. Xin hãy soi sáng cho tôi :)

Thời trang đến và đi bạn thân. Có nhiều cách để da mèo.

Tôi xin lỗi vì bạn phải chịu sự nhầm lẫn của một tập hợp các mô hình lập trình liên tục thay đổi. Nhưng này, CHÀO MỪNG BẠN ĐẾN CÂU LẠC BỘ !!

Bây giờ có một vài điểm quan trọng cần nhớ liên quan đến Tính bất biến, và bạn sẽ bị những thứ này ném vào bạn với cường độ sốt mà chỉ có sự ngây thơ mới có thể tập hợp được.

1) Tính không thay đổi là tuyệt vời để tránh các điều kiện chủng tộc trong môi trường đa luồng .

Các môi trường đa luồng (như C ++, Java và C #) có tội trong việc thực hành khóa các đối tượng khi có nhiều hơn một luồng muốn thay đổi chúng. Điều này là xấu cho hiệu suất, nhưng tốt hơn so với thay thế tham nhũng dữ liệu. Nhưng vẫn không tốt bằng làm cho mọi thứ trở nên bất biến (Chúa khen ngợi Haskell!).

NHƯNG! Trong JavaScript, bạn luôn hoạt động trên một luồng . Ngay cả nhân viên web (mỗi người chạy trong một bối cảnh riêng biệt ). Vì vậy, vì bạn không thể có một điều kiện cuộc đua liên quan đến chủ đề trong bối cảnh thực thi của mình (tất cả các biến và đóng toàn cầu đáng yêu đó), điểm chính có lợi cho tính không thay đổi sẽ xuất hiện ngoài cửa sổ.

(Có nói rằng, có một lợi thế để sử dụng chức năng thuần túy trong công nhân trang web, mà là bạn sẽ không có kỳ vọng về loay hoay với các đối tượng trên chủ đề chính.)

2) Tính không thay đổi có thể (bằng cách nào đó) tránh các điều kiện chủng tộc trong trạng thái ứng dụng của bạn.

Và đây là mấu chốt thực sự của vấn đề, hầu hết các nhà phát triển (React) sẽ nói với bạn rằng Tính bất biến và FP bằng cách nào đó có thể thực hiện phép thuật này cho phép trạng thái ứng dụng của bạn trở nên dễ đoán.

Tất nhiên, điều này không có nghĩa là bạn có thể tránh các điều kiện chạy đua trong cơ sở dữ liệu , để loại bỏ điều đó, bạn phải điều phối tất cả người dùng trong tất cả các trình duyệt và vì thế bạn cần một công nghệ đẩy lùi như WebSockets ( nhiều hơn về điều này dưới đây) sẽ phát sóng thay đổi cho tất cả mọi người chạy ứng dụng.

Điều đó cũng không có nghĩa là có một số vấn đề cố hữu trong JavaScript khi trạng thái ứng dụng của bạn cần tính bất biến để có thể dự đoán được, bất kỳ nhà phát triển nào đã mã hóa các ứng dụng front-end trước khi React nói với bạn điều này.

Yêu cầu khá khó hiểu này chỉ đơn giản có nghĩa là với React, trạng thái ứng dụng của bạn sẽ trở nên dễ bị điều kiện chủng tộc hơn , nhưng sự bất biến đó cho phép bạn loại bỏ nỗi đau đó. Tại sao? Bởi vì React rất đặc biệt .. nó được thiết kế như một thư viện kết xuất được tối ưu hóa cao với quản lý trạng thái mạch lạc chiếm vị trí thứ hai và do đó trạng thái thành phần được quản lý thông qua chuỗi sự kiện không đồng bộ (còn gọi là "liên kết dữ liệu một chiều") mà bạn không kiểm soát được hơn và dựa vào bạn nhớ không biến đổi trạng thái trực tiếp ...

Với bối cảnh này, thật dễ dàng để thấy rằng nhu cầu về tính bất biến ít liên quan đến JavaScript và rất nhiều điều phải làm với điều kiện chủng tộc trong React: nếu có một loạt các thay đổi phụ thuộc lẫn nhau trong ứng dụng của bạn và không có cách nào dễ dàng để tìm ra điều gì trạng thái của bạn hiện đang ở, bạn sẽ bị lẫn lộn , và do đó nó hoàn toàn hợp lý để sử dụng tính bất biến để theo dõi mọi thay đổi lịch sử .

3) Điều kiện chủng tộc là xấu về thể loại.

Chà, chúng có thể là nếu bạn đang sử dụng React. Nhưng chúng rất hiếm nếu bạn chọn một khung khác.

Bên cạnh đó, thông thường bạn có những vấn đề lớn hơn rất nhiều để đối phó với các vấn đề về vấn đề như địa ngục phụ thuộc. Giống như một cơ sở mã cồng kềnh. Giống như CSS của bạn không được tải. Giống như một quá trình xây dựng chậm hoặc bị mắc kẹt vào một back-end nguyên khối làm cho việc lặp lại gần như không thể. Giống như các nhà phát triển thiếu kinh nghiệm không hiểu chuyện gì đang xảy ra và làm cho mọi thứ trở nên lộn xộn.

Bạn biết. Thực tế. Nhưng này, ai quan tâm đến điều đó?

4) Tính không thay đổi sử dụng các loại tham chiếu để giảm tác động hiệu suất của việc theo dõi mọi thay đổi trạng thái.

Bởi vì nghiêm túc, nếu bạn định sao chép mọi thứ mỗi khi trạng thái của bạn thay đổi, tốt hơn bạn nên chắc chắn rằng bạn thông minh về nó.

5) Tính không thay đổi cho phép bạn sử dụng công cụ UNDO .

Bởi vì er .. đây là tính năng số một mà người quản lý dự án của bạn sẽ yêu cầu, phải không?

6) Trạng thái bất biến có rất nhiều tiềm năng thú vị khi kết hợp với WebSockets

Cuối cùng nhưng không kém phần quan trọng, sự tích lũy của các trạng thái deltas tạo nên một trường hợp khá hấp dẫn kết hợp với WebSockets, cho phép tiêu thụ trạng thái dễ dàng như một dòng chảy của các sự kiện bất biến ...

Một khi đồng xu rơi vào khái niệm này (trạng thái là một dòng sự kiện - chứ không phải là một bộ hồ sơ thô sơ đại diện cho quan điểm mới nhất), thế giới bất biến trở thành một nơi kỳ diệu để sinh sống. Một vùng đất của sự ngạc nhiên có nguồn gốc và khả năng vượt qua chính thời gian . Và khi thực hiện quyền này chắc chắn có thể làm cho thời gian thực các ứng dụng EASI er để thực hiện, bạn chỉ cần phát sóng dòng chảy của sự kiện để tất cả mọi người quan tâm để họ có thể xây dựng đại diện của mình trong hiện tại và viết lại những thay đổi của mình vào dòng chảy xã.

Nhưng đến một lúc nào đó bạn thức dậy và nhận ra rằng tất cả những điều kỳ diệu và ma thuật đó không đến miễn phí. Không giống như các đồng nghiệp háo hức, các bên liên quan của bạn (yea, những người trả tiền cho bạn) quan tâm rất ít đến triết lý hoặc thời trang và rất nhiều về số tiền họ trả để xây dựng một sản phẩm họ có thể bán. Và điểm mấu chốt là việc viết mã bất biến khó hơn và dễ phá mã hơn, cộng với việc có một mặt trước bất biến nếu bạn không có back-end để hỗ trợ. Khi nào (và nếu!) Cuối cùng bạn thuyết phục được các bên liên quan của mình rằng bạn nên xuất bản và tiêu thụ các sự kiện thông qua một công nghệ đẩy như WebSockets, bạn sẽ tìm ra sự đau đớn khi mở rộng quy mô sản xuất .


Bây giờ cho một số lời khuyên, bạn nên chọn chấp nhận nó.

Một lựa chọn để viết JavaScript bằng cách sử dụng FP / Tính không thay đổi cũng là một lựa chọn để làm cho cơ sở mã ứng dụng của bạn lớn hơn, phức tạp hơn và khó quản lý hơn. Tôi chắc chắn sẽ tranh luận về việc giới hạn cách tiếp cận này với các bộ giảm Redux của bạn, trừ khi bạn biết bạn đang làm gì ... Và NẾU bạn sẽ tiếp tục và sử dụng tính bất biến, sau đó áp dụng trạng thái bất biến cho toàn bộ ngăn xếp ứng dụng của bạn , và không chỉ phía khách hàng, vì bạn đang thiếu giá trị thực của nó.

Bây giờ, nếu bạn đủ may mắn để có thể đưa ra lựa chọn trong công việc của mình, thì hãy thử và sử dụng trí tuệ của bạn (hoặc không) và làm những gì đúng bởi người trả tiền cho bạn . Bạn có thể dựa trên kinh nghiệm của bạn, về ruột của bạn hoặc những gì đang diễn ra xung quanh bạn (phải thừa nhận rằng nếu mọi người đang sử dụng React / Redux thì có một lập luận hợp lệ rằng việc tìm tài nguyên để tiếp tục công việc của bạn sẽ dễ dàng hơn) .. Hoặc, bạn có thể thử các phương pháp tiếp tục phát triển theo hướng hoặc phát triển theo hướng Hype . Họ có thể là nhiều thứ của bạn.

Nói tóm lại, điều cần nói về sự bất biến là nó sẽ giúp bạn trở nên thời trang hơn với các đồng nghiệp của mình, ít nhất là cho đến khi cơn sốt tiếp theo xuất hiện, đến lúc đó bạn sẽ vui mừng bước tiếp.


Bây giờ sau phiên tự trị liệu này, tôi muốn chỉ ra rằng tôi đã thêm bài viết này dưới dạng một bài viết trong blog của mình => Tính bất biến trong JavaScript: Một quan điểm trái ngược . Vui lòng trả lời trong đó nếu bạn có cảm xúc mạnh mẽ mà bạn muốn rời khỏi ngực của bạn quá;).


10
Xin chào Steven, vâng. Tôi đã có tất cả những nghi ngờ này khi tôi xem xét bất biến.js và redux. Nhưng, câu trả lời của bạn thật tuyệt vời! Nó bổ sung rất nhiều giá trị và cảm ơn vì đã giải quyết từng điểm mà tôi nghi ngờ. Bây giờ rõ ràng hơn / tốt hơn ngay cả sau khi làm việc trong nhiều tháng trên các vật thể bất biến.
bozzmob

5
Tôi đã sử dụng React với Flux / Redux trong hơn hai năm và tôi không thể đồng ý nhiều hơn với bạn, phản hồi tuyệt vời!
Pavle Lekic

6
Tôi rất nghi ngờ rằng các quan điểm về tính bất biến tương quan khá gọn gàng với kích thước nhóm và cơ sở mã hóa, và tôi không nghĩ rằng bất kỳ sự trùng hợp nào mà người đề xuất chính là một người khổng lồ ở thung lũng silicon. Điều đó đang được nói, tôi tôn trọng không đồng ý: bất biến là một môn học hữu ích như không sử dụng goto là một môn học hữu ích. Hoặc thử nghiệm đơn vị. Hoặc TDD. Hoặc phân tích kiểu tĩnh. Không có nghĩa là bạn làm chúng mọi lúc, mọi nơi (mặc dù một số người làm). Tôi cũng sẽ nói rằng tiện ích là trực giao với sự cường điệu: trong một ma trận hữu ích / thừa thãi và gợi cảm / nhàm chán, có rất nhiều ví dụ về mỗi ví dụ. "hyped" !== "bad"
Jared Smith

4
Xin chào @ftor, điểm tốt, đưa mọi thứ đi quá xa theo hướng khác. Tuy nhiên, vì có rất nhiều thông tin về "sự bất biến trong các bài viết và lập luận của javascript", tôi cảm thấy mình cần phải cân bằng mọi thứ. Vì vậy, những người mới có một quan điểm trái ngược để giúp họ đưa ra đánh giá.
Steven de Salas

4
Thông tin, và tiêu đề rực rỡ. Cho đến khi tôi tìm thấy câu trả lời này, tôi nghĩ tôi là người duy nhất có quan điểm tương tự. Tôi nhận ra giá trị của tính bất biến, nhưng điều làm tôi bực mình là nó trở thành một giáo điều áp bức tất cả các kỹ thuật khác (ví dụ như sự bất lợi của ràng buộc 2 chiều rất hữu ích cho định dạng đầu vào như được thực hiện trong KnockoutJS chẳng hạn).
Tyblitz

53

Câu hỏi là, tại sao sự bất biến rất quan trọng? Điều gì là sai trong việc đột biến các đối tượng? Nó không làm cho mọi thứ đơn giản?

Trên thực tế, điều ngược lại là đúng: tính đột biến làm cho mọi thứ phức tạp hơn, ít nhất là về lâu dài. Vâng, nó làm cho mã hóa ban đầu của bạn dễ dàng hơn bởi vì bạn có thể thay đổi mọi thứ ở bất cứ đâu bạn muốn, nhưng khi chương trình của bạn lớn hơn, nó trở thành một vấn đề - nếu một giá trị thay đổi, điều gì đã thay đổi?

Khi bạn biến mọi thứ thành bất biến, điều đó có nghĩa là dữ liệu không thể bị thay đổi do bất ngờ nữa. Bạn biết chắc chắn rằng nếu bạn chuyển một giá trị vào hàm, nó không thể thay đổi trong hàm đó.

Nói một cách đơn giản: nếu bạn sử dụng các giá trị bất biến, điều đó giúp bạn dễ dàng suy luận về mã của mình: mọi người đều có một bản sao * duy nhất của dữ liệu của bạn, vì vậy nó không thể làm hỏng nó và phá vỡ các phần khác của mã. Hãy tưởng tượng điều này dễ dàng hơn nhiều làm việc trong một môi trường đa luồng!

Lưu ý 1: Có một chi phí hiệu suất tiềm năng cho tính bất biến tùy thuộc vào những gì bạn đang làm, nhưng những thứ như Immutable.js tối ưu hóa tốt nhất có thể.

Lưu ý 2: Trong trường hợp không chắc bạn không chắc chắn, Immutable.js và ES6 constcó nghĩa là những thứ rất khác nhau.

Trong trường hợp thông thường, tôi có thể vừa thêm đối tượng vào mảng. Làm thế nào để tôi đạt được trong trường hợp này? Xóa cửa hàng & tạo lại nó? Không thêm một đối tượng vào mảng là một hoạt động ít tốn kém hơn? Tái bút: Nếu ví dụ không phải là cách đúng để giải thích sự bất biến, xin vui lòng cho tôi biết ví dụ thực tế đúng là gì.

Có, ví dụ tin tức của bạn là hoàn toàn tốt và lý luận của bạn hoàn toàn chính xác: bạn không thể sửa đổi danh sách hiện tại của mình, vì vậy bạn cần tạo một danh sách mới:

var originalItems = Immutable.List.of(1, 2, 3);
var newItems = originalItems.push(4, 5, 6);

1
Tôi không đồng ý với câu trả lời này nhưng nó không đề cập đến phần "Tôi muốn học hỏi từ một ví dụ thực tế" của câu hỏi. Người ta có thể lập luận rằng một tài liệu tham khảo duy nhất cho danh sách các tiêu đề tin tức đang được sử dụng trong nhiều lĩnh vực là một điều tốt. "Tôi chỉ phải cập nhật danh sách một lần và mọi thứ tham khảo danh sách tin tức đều được cập nhật miễn phí" - Tôi nghĩ rằng một câu trả lời tốt hơn sẽ có một vấn đề phổ biến như anh ấy trình bày, và hiển thị một giải pháp thay thế có giá trị sử dụng tính bất biến.
Cảm ơn bạn

1
Tôi rất vui vì câu trả lời là hữu ích! Về câu hỏi mới của bạn: đừng cố gắng đoán hệ thống :) Trong trường hợp chính xác này, một cái gì đó gọi là "chia sẻ cấu trúc" làm giảm đáng kể sự phá hủy của GC - nếu bạn có 10.000 mục trong danh sách và thêm 10 mục nữa, tôi tin là Bất biến. js sẽ cố gắng sử dụng lại cấu trúc trước đó tốt nhất có thể. Hãy để Immutable.js lo lắng về bộ nhớ và rất có thể bạn sẽ thấy nó xuất hiện tốt hơn.
TwoStraws

6
Imagine how much easier this makes working in a multi-threaded environment!-> Ok đối với các ngôn ngữ khác nhưng đây không phải là một lợi thế trong JavaScript đơn luồng.
Steven de Salas

1
@StevendeSalas lưu ý rằng JavaScript chủ yếu không đồng bộ và hướng sự kiện. Nó hoàn toàn không miễn dịch với điều kiện chủng tộc.
Jared Smith

1
@JaredSmith vẫn còn quan điểm của tôi. FP và tính không thay đổi là các mô hình hữu ích mạnh mẽ để tránh hỏng dữ liệu và / hoặc khóa tài nguyên trong các môi trường đa luồng nhưng không phải như vậy trong JavaScript vì nó đơn luồng. Trừ khi tôi thiếu một chút khôn ngoan thần thánh, sự đánh đổi chính ở đây là liệu bạn có sẵn sàng làm cho mã của bạn phức tạp hơn (và chậm hơn) trong một nhiệm vụ để tránh các điều kiện chủng tộc ... vấn đề ít hơn nhiều so với hầu hết mọi người suy nghĩ
Steven de Salas

37

Mặc dù các câu trả lời khác đều ổn, nhưng để giải quyết câu hỏi của bạn về trường hợp sử dụng thực tế (từ các nhận xét về các câu trả lời khác), hãy bước ra ngoài mã chạy của bạn trong một phút và xem câu trả lời phổ biến ngay dưới mũi của bạn: git . Điều gì sẽ xảy ra nếu mỗi lần bạn thực hiện một cam kết, bạn sẽ ghi đè lên dữ liệu trong kho lưu trữ?

Bây giờ chúng ta đang gặp phải một trong những vấn đề mà các bộ sưu tập bất biến gặp phải: sự phình to bộ nhớ. Git đủ thông minh để không chỉ đơn giản tạo các bản sao mới của các tệp mỗi khi bạn thực hiện thay đổi, nó chỉ đơn giản là theo dõi các khác biệt .

Mặc dù tôi không biết nhiều về hoạt động bên trong của git, tôi chỉ có thể giả sử nó sử dụng một chiến lược tương tự như của các thư viện mà bạn tham khảo: chia sẻ cấu trúc. Dưới mui xe các thư viện sử dụng thử hoặc các cây khác để chỉ theo dõi các nút khác nhau.

Chiến lược này cũng có hiệu quả hợp lý cho các cấu trúc dữ liệu trong bộ nhớ vì có các thuật toán vận hành cây nổi tiếng hoạt động trong thời gian logarit.

Một trường hợp sử dụng khác: giả sử bạn muốn có một nút hoàn tác trên ứng dụng web của mình. Với các biểu diễn bất biến của dữ liệu của bạn, việc thực hiện như vậy là tương đối tầm thường. Nhưng nếu bạn dựa vào đột biến, điều đó có nghĩa là bạn phải lo lắng về việc lưu trữ trạng thái của thế giới và thực hiện cập nhật nguyên tử.

Nói tóm lại, có một cái giá phải trả cho sự bất biến trong hiệu năng thời gian chạy và đường cong học tập. Nhưng bất kỳ lập trình viên có kinh nghiệm nào cũng sẽ nói với bạn rằng thời gian gỡ lỗi vượt xa thời gian viết mã bằng một mức độ lớn. Và cú đánh nhẹ vào hiệu năng thời gian chạy có thể lớn hơn các lỗi liên quan đến trạng thái mà người dùng của bạn không phải chịu đựng.


1
Một ví dụ tuyệt vời tôi nói. Sự hiểu biết của tôi về sự bất biến là rõ ràng hơn bây giờ. Cảm ơn Jared. Trên thực tế, một trong những triển khai là nút UNDO: D Và bạn đã làm mọi thứ khá đơn giản đối với tôi.
bozzmob

3
Chỉ vì một mô hình có ý nghĩa trong git không có nghĩa là điều tương tự có ý nghĩa ở mọi nơi. Trong git bạn thực sự quan tâm đến tất cả lịch sử được lưu trữ và bạn muốn có thể hợp nhất các nhánh khác nhau. Ở phía trước, bạn không quan tâm đến hầu hết lịch sử tiểu bang và bạn không cần tất cả sự phức tạp này.
Trượt tuyết

2
@Ski nó chỉ phức tạp vì nó không phải là mặc định. Tôi thường không sử dụng mori hoặc bất biến.js trong các dự án của mình: Tôi luôn do dự khi tiếp nhận các bên thứ ba. Nhưng nếu đó là mặc định (a la clojurescript) hoặc ít nhất là có tùy chọn gốc chọn tham gia, tôi sẽ sử dụng nó mọi lúc, bởi vì khi tôi ví dụ như chương trình trong clojure, tôi không ngay lập tức nhét mọi thứ vào nguyên tử.
Jared Smith

Joe Armstrong sẽ nói đừng lo lắng về hiệu suất, chỉ cần chờ vài năm và luật của Moore sẽ lo việc đó cho bạn.
ximo

1
@JaredSmith Bạn nói đúng, mọi thứ chỉ trở nên nhỏ hơn và hạn chế hơn về tài nguyên. Tôi không chắc liệu đó có phải là yếu tố giới hạn cho JavaScript hay không. Chúng tôi tiếp tục tìm những cách mới để cải thiện hiệu suất (ví dụ Svelte). Nhân tiện, tôi hoàn toàn đồng ý với nhận xét khác của bạn. Sự phức tạp hoặc khó khăn trong việc sử dụng các cấu trúc dữ liệu bất biến thường xuất phát từ ngôn ngữ không có hỗ trợ tích hợp cho khái niệm này. Clojure làm cho tính bất biến trở nên đơn giản vì nó được đưa vào ngôn ngữ, toàn bộ ngôn ngữ được thiết kế xung quanh ý tưởng.
ximo

8

Câu hỏi là, tại sao sự bất biến rất quan trọng? Điều gì là sai trong việc đột biến các đối tượng? Nó không làm cho mọi thứ đơn giản?

Về khả năng biến đổi

Không có gì là sai trong khả năng biến đổi từ quan điểm kỹ thuật. Nó là nhanh, nó đang sử dụng lại bộ nhớ. Các nhà phát triển đã sử dụng nó ngay từ đầu (như tôi nhớ). Vấn đề tồn tại trong việc sử dụng khả năng biến đổi và rắc rối mà việc sử dụng này có thể mang lại.

Nếu đối tượng không được chia sẻ với bất cứ điều gì, ví dụ như tồn tại trong phạm vi của hàm và không được tiếp xúc với bên ngoài, thì thật khó để thấy lợi ích trong tính bất biến. Thực sự trong trường hợp này không có nghĩa là bất biến. Cảm giác bất biến bắt đầu khi một cái gì đó được chia sẻ.

Nhức đầu

Cấu trúc chia sẻ có thể dễ dàng tạo ra nhiều cạm bẫy. Mọi thay đổi trong bất kỳ phần nào của mã có quyền truy cập vào tham chiếu đều có tác động đến các phần khác với khả năng hiển thị của tham chiếu này. Tác động như vậy kết nối tất cả các bộ phận với nhau, ngay cả khi họ không nên nhận thức được các mô-đun khác nhau. Đột biến trong một chức năng có thể làm sập một phần hoàn toàn khác của ứng dụng. Điều đó là một tác dụng phụ xấu.

Tiếp theo thường gặp vấn đề với đột biến là trạng thái bị hỏng. Trạng thái bị hỏng có thể xảy ra khi quy trình đột biến thất bại ở giữa và một số trường đã được sửa đổi và một số thì không.

Hơn nữa, với đột biến, thật khó để theo dõi sự thay đổi. Kiểm tra tham chiếu đơn giản sẽ không cho thấy sự khác biệt, để biết những gì đã thay đổi một số kiểm tra sâu cần phải được thực hiện. Ngoài ra để theo dõi sự thay đổi một số mẫu quan sát cần phải được giới thiệu.

Cuối cùng, đột biến là lý do của thâm hụt niềm tin. Làm thế nào bạn có thể chắc chắn rằng một số cấu trúc có giá trị mong muốn, nếu nó có thể bị đột biến.

const car = { brand: 'Ferrari' };
doSomething(car);
console.log(car); // { brand: 'Fiat' }

Như ví dụ trên cho thấy, việc vượt qua cấu trúc có thể thay đổi luôn có thể kết thúc bằng cách có cấu trúc khác nhau. Hàm doS Something đang biến đổi thuộc tính được cung cấp từ bên ngoài. Không tin tưởng vào mã, bạn thực sự không biết bạn có gì và bạn sẽ có gì. Tất cả những vấn đề này diễn ra bởi vì: Các cấu trúc có thể thay đổi được biểu thị các con trỏ tới bộ nhớ.

Bất biến là về giá trị

Tính không thay đổi có nghĩa là thay đổi không được thực hiện trên cùng một đối tượng, cấu trúc, nhưng thay đổi được thể hiện trong cái mới. Và điều này là do tham chiếu đại diện cho giá trị không chỉ con trỏ bộ nhớ. Mỗi thay đổi tạo ra giá trị mới và không chạm vào giá trị cũ. Các quy tắc rõ ràng như vậy mang lại sự tin tưởng và dự đoán mã. Các chức năng được sử dụng an toàn vì thay vì đột biến, chúng xử lý các phiên bản riêng với các giá trị riêng.

Sử dụng các giá trị thay cho các bộ nhớ chứa chắc chắn rằng mọi đối tượng đại diện cho giá trị không thể thay đổi cụ thể và an toàn khi sử dụng nó.

Cấu trúc bất biến là đại diện cho các giá trị.

Tôi đang lặn sâu hơn vào chủ đề trong bài viết trung bình - https://medium.com/@macsikora/the-state-of-immutability-169d2cd11310


6

Tại sao tính bất biến rất quan trọng (hoặc cần thiết) trong JavaScript?

Tính không thay đổi có thể được theo dõi trong các bối cảnh khác nhau, nhưng quan trọng nhất là theo dõi nó theo trạng thái ứng dụng và chống lại UI của ứng dụng.

Tôi sẽ coi mẫu JavaScript Redux là cách tiếp cận rất hợp thời trang và hiện đại và bởi vì bạn đã đề cập đến điều đó.

Đối với UI chúng ta cần làm cho nó có thể dự đoán được . Nó sẽ được dự đoán nếuUI = f(application state) .

Các ứng dụng (bằng JavaScript) thay đổi trạng thái thông qua các hành động được triển khai bằng hàm giảm tốc .

Hàm giảm tốc chỉ đơn giản là thực hiện hành động và trạng thái cũ và trả về trạng thái mới, giữ nguyên trạng thái cũ.

new state  = r(current state, action)

nhập mô tả hình ảnh ở đây

Lợi ích là: bạn du hành thời gian các trạng thái vì tất cả các đối tượng trạng thái được lưu và bạn có thể kết xuất ứng dụng ở bất kỳ trạng thái nào kể từ khi UI = f(state)

Vì vậy, bạn có thể hoàn tác / làm lại dễ dàng.


Xảy ra việc tạo ra tất cả các trạng thái này vẫn có thể hiệu quả về bộ nhớ, sự tương tự với Git là rất tốt và chúng ta có sự tương tự tương tự trong HĐH Linux với các liên kết tượng trưng (dựa trên các nút).


5

Một lợi ích khác của tính không thay đổi trong Javascript là nó làm giảm khớp nối tạm thời, có lợi ích đáng kể cho thiết kế nói chung. Hãy xem xét giao diện của một đối tượng với hai phương thức:

class Foo {

      baz() {
          // .... 
      }

      bar() {
          // ....
      }

}

const f = new Foo();

Nó có thể là trường hợp một cuộc gọi đến baz()được yêu cầu để đưa đối tượng ở trạng thái hợp lệ để một cuộc gọi bar()hoạt động chính xác. Nhưng làm thế nào để bạn biết điều này?

f.baz();
f.bar(); // this is ok

f.bar();
f.baz(); // this blows up

Để tìm ra nó, bạn cần xem xét kỹ lưỡng các lớp bên trong bởi vì nó không rõ ràng ngay lập tức từ việc kiểm tra giao diện công cộng. Vấn đề này có thể bùng nổ trong một cơ sở mã lớn với nhiều trạng thái và lớp có thể thay đổi.

Nếu Foolà bất biến thì đây không còn là vấn đề nữa. Sẽ an toàn khi cho rằng chúng ta có thể gọi bazhoặc bartheo bất kỳ thứ tự nào vì trạng thái bên trong của lớp không thể thay đổi.


4

Ngày xửa ngày xưa, có một vấn đề về đồng bộ hóa dữ liệu giữa các luồng. Vấn đề này là một nỗi đau lớn, đã có hơn 10 giải pháp. Một số người đã cố gắng giải quyết nó triệt để. Đó là một nơi mà lập trình chức năng được sinh ra. Nó cũng giống như chủ nghĩa Mác. Tôi không thể hiểu làm thế nào Dan Abramov bán ý tưởng này vào JS, bởi vì nó là một luồng đơn. Anh ấy là một thiên tài.

Tôi có thể đưa ra một ví dụ nhỏ. Có một thuộc tính __attribute__((pure))trong gcc. Trình biên dịch cố gắng giải quyết xem hàm của bạn có thuần túy hay không nếu bạn không khai báo đặc biệt. Chức năng của bạn có thể là tinh khiết ngay cả trạng thái của bạn là có thể thay đổi. Bất biến chỉ là một trong hơn 100 cách để đảm bảo rằng chức năng của bạn sẽ thuần túy. Trên thực tế 95% các chức năng của bạn sẽ là thuần túy.

Bạn không nên sử dụng bất kỳ giới hạn nào (như bất biến) nếu bạn thực sự không có lý do nghiêm trọng. Nếu bạn muốn "Hoàn tác" một số trạng thái, bạn có thể tạo giao dịch. Nếu bạn muốn đơn giản hóa việc liên lạc, bạn có thể gửi các sự kiện với dữ liệu không thay đổi. Điều đó phụ thuộc vào bạn.

Tôi đang viết thông điệp này từ nước cộng hòa chủ nghĩa bài. Tôi chắc chắn rằng triệt để của bất kỳ ý tưởng là một cách sai.


Đoạn thứ 3 có ý nghĩa rất lớn. Cảm ơn vì điều đó. 'Nếu bạn muốn "Hoàn tác" một số trạng thái, bạn có thể tạo giao dịch' !!
bozzmob

Nhân tiện, việc so sánh với chủ nghĩa Mác cũng có thể được thực hiện cho OOP. Ghi nhớ Java? Heck, các bit lẻ của Java trong JavaScript? Sự cường điệu không bao giờ tốt, nó gây ra sự cực đoan và phân cực. Trong lịch sử, OOP được thổi phồng hơn nhiều so với sự thổi phồng Redux của Facebook. Mặc dù họ chắc chắn đã cố gắng hết sức.
ximo

4

Một cách khác ...

Câu trả lời khác của tôi giải quyết câu hỏi từ quan điểm rất thực tế, và tôi vẫn thích nó. Tôi đã quyết định thêm câu này như một câu trả lời khác thay vì một phụ lục cho câu trả lời đó bởi vì nó là một câu nói triết học nhàm chán, hy vọng cũng trả lời được câu hỏi, nhưng không thực sự phù hợp với câu trả lời hiện có của tôi.

TL; DR

Ngay cả trong các dự án nhỏ, tính bất biến có thể hữu ích, nhưng đừng cho rằng vì nó tồn tại nên nó có ý nghĩa với bạn.

Câu trả lời dài hơn nhiều

LƯU Ý: cho mục đích của câu trả lời này, tôi đang sử dụng từ 'kỷ luật' để có nghĩa là tự từ chối vì một số lợi ích.

Đây là dạng tương tự với một câu hỏi khác: "Tôi có nên sử dụng Bản mô tả không? Tại sao các loại rất quan trọng trong JavaScript?". Nó có một câu trả lời tương tự quá. Hãy xem xét kịch bản sau đây:

Bạn là tác giả và người duy trì duy nhất của một cơ sở mã JavaScript / CSS / HTML gồm khoảng 5000 dòng. Sếp bán kỹ thuật của bạn đọc một cái gì đó về sự nóng bỏng của Bản mô tả và gợi ý rằng chúng tôi có thể muốn chuyển sang nó nhưng để lại quyết định cho bạn. Vì vậy, bạn đọc về nó, chơi với nó, vv

Vì vậy, bây giờ bạn có một sự lựa chọn để thực hiện, bạn có chuyển sang Bản mô tả không?

Bản mô tả có một số lợi thế hấp dẫn: intellisense, bắt lỗi sớm, chỉ định API của bạn trả trước, dễ sửa chữa mọi thứ khi tái cấu trúc phá vỡ chúng, ít kiểm tra hơn. Bản mô tả cũng có một số chi phí: một số thành ngữ JavaScript rất tự nhiên và chính xác có thể khó mô hình hóa trong hệ thống loại không đặc biệt mạnh mẽ của nó, các chú thích phát triển LoC, thời gian và nỗ lực viết lại cơ sở mã hiện tại, bước bổ sung trong đường dẫn xây dựng, v.v. Về cơ bản hơn, nó khắc ra một tập hợp con các chương trình JavaScript chính xác có thể để đổi lấy lời hứa rằng mã của bạn có nhiều khả năng đúng. Đó là tùy tiện hạn chế. Đó là toàn bộ vấn đề: bạn áp đặt một số kỷ luật giới hạn bạn (hy vọng là tự bắn vào chân mình).

Quay lại câu hỏi, đọc lại trong bối cảnh của đoạn văn trên: nó có đáng không?

Trong kịch bản được mô tả, tôi sẽ khẳng định rằng nếu bạn rất quen thuộc với một cơ sở mã JS nhỏ đến trung bình, thì lựa chọn sử dụng Bản mô tả là thẩm mỹ hơn là thực tế. Và điều đó tốt , không có gì sai với thẩm mỹ, họ không nhất thiết phải hấp dẫn.

Kịch bản B:

Bạn thay đổi công việc và hiện là lập trình viên kinh doanh trực tuyến tại Foo Corp Bạn đang làm việc với một nhóm 10 người trên một cơ sở mã JavaScript / HTML / CSS 90000 LoC với một đường dẫn xây dựng khá phức tạp liên quan đến babel, webpack , một bộ polyfill, phản ứng với các plugin khác nhau, hệ thống quản lý nhà nước, ~ 20 thư viện của bên thứ ba, ~ 10 thư viện nội bộ, plugin biên tập như một kẻ nói dối với các quy tắc cho hướng dẫn kiểu trong nhà, v.v.

Quay lại khi bạn là chàng trai / cô gái 5k LoC, điều đó không quan trọng lắm. Ngay cả tài liệu không phải một vấn đề lớn, thậm chí trở lại một phần cụ thể của mã sau 6 tháng, bạn có thể tìm ra nó đủ dễ dàng. Nhưng bây giờ kỷ luật không chỉ là tốt đẹp nhưng cần thiết . Kỷ luật có thể không liên quan đến nguyên cảo, nhưng sẽ có khả năng liên quan đến một số hình thức phân tích tĩnh cũng như tất cả các hình thức khác của kỷ luật mã hóa (tài liệu, phong cách hướng dẫn, xây dựng kịch bản, kiểm tra hồi quy, CI). Kỷ luật không còn là một điều xa xỉ , nó là một điều cần thiết .

Tất cả những điều này được áp dụng GOTOvào năm 1978: trò chơi blackjack nhỏ xíu của bạn trong C có thể sử dụng GOTOlogic s và spaghetti và nó không phải là vấn đề lớn để lựa chọn cuộc phiêu lưu của riêng bạn theo cách của bạn, nhưng khi các chương trình lớn hơn và tham vọng hơn, tốt, sử dụng vô kỷ luậtGOTO không thể được duy trì. Và tất cả điều này áp dụng cho sự bất biến ngày nay.

Cũng giống như các loại tĩnh, nếu bạn không làm việc trên một cơ sở mã lớn với đội ngũ kỹ sư duy trì / mở rộng nó, lựa chọn sử dụng tính bất biến sẽ mang tính thẩm mỹ hơn thực tế: lợi ích vẫn còn nhưng vẫn chưa thể vượt quá chi phí.

Nhưng như với tất cả các ngành học hữu ích, có một điểm mà nó không còn là tùy chọn. Nếu tôi muốn duy trì cân nặng khỏe mạnh, thì kỷ luật liên quan đến kem có thể là tùy chọn. Nhưng nếu tôi muốn trở thành một vận động viên thi đấu, sự lựa chọn của tôi về việc có nên ăn kem hay không được thay thế bởi sự lựa chọn mục tiêu của tôi. Nếu bạn muốn thay đổi thế giới bằng phần mềm, tính bất biến có thể là một phần của những gì bạn cần để tránh nó sụp đổ dưới sức nặng của chính nó.


1
+1 tôi thích nó Nhiều hơn về điểm Jared. Nhưng sự bất biến sẽ không cứu một đội khỏi sự thiếu kỷ luật của chính nó. 😉
Steven de Salas

@StevendeSalas là một hình thức kỷ luật. Và như vậy, tôi nghĩ rằng nó tương quan với (nhưng không thay thế) các hình thức kỷ luật công nghệ phần mềm khác. Nó bổ sung, thay vì thay thế. Nhưng như tôi đã nói trong một nhận xét về câu trả lời của bạn, tôi không ngạc nhiên về việc nó bị một gã khổng lồ công nghệ đẩy mạnh với một nhóm kỹ sư đang nghiền ngẫm trên cùng một cơ sở mã lớn :) họ cần tất cả các kỷ luật họ có thể có. Tôi phần lớn không làm biến đổi các đối tượng nhưng cũng không sử dụng bất kỳ hình thức thực thi nào vì, đó chỉ là tôi.
Jared Smith

0

Tôi đã tạo một lib nguồn mở bất khả tri (MIT) cho trạng thái có thể thay đổi (hoặc không thay đổi) có thể thay thế tất cả các bộ lưu trữ bất biến như libs (redux, vuex, v.v.).

Các trạng thái bất biến đối với tôi là xấu vì có quá nhiều việc phải làm (rất nhiều hành động cho các thao tác đọc / ghi đơn giản), mã ít đọc và hiệu suất cho các bộ dữ liệu lớn không được chấp nhận (hiển thị lại toàn bộ thành phần: /).

Với trình quan sát trạng thái sâu, tôi chỉ có thể cập nhật một nút có ký hiệu dấu chấm và sử dụng ký tự đại diện. Tôi cũng có thể tạo lịch sử của trạng thái (hoàn tác / làm lại / du hành thời gian) chỉ giữ lại những giá trị cụ thể đã được thay đổi{path:value} = sử dụng ít bộ nhớ hơn.

Với người quan sát trạng thái sâu, tôi có thể tinh chỉnh mọi thứ và tôi có quyền kiểm soát hạt đối với hành vi thành phần để hiệu suất có thể được cải thiện mạnh mẽ. Mã dễ đọc hơn và tái cấu trúc dễ dàng hơn rất nhiều - chỉ cần tìm kiếm và thay thế các chuỗi đường dẫn (không cần thay đổi mã / logic).


-1

Tôi nghĩ rằng lý do chính pro đối tượng bất biến, là giữ trạng thái của đối tượng hợp lệ.

Giả sử chúng ta có một đối tượng được gọi arr. Đối tượng này là hợp lệ khi tất cả các mục là cùng một chữ cái.

// this function will change the letter in all the array
function fillWithZ(arr) {
    for (var i = 0; i < arr.length; ++i) {
        if (i === 4) // rare condition
            return arr; // some error here

        arr[i] = "Z";
    }

    return arr;
}

console.log(fillWithZ(["A","A","A"])) // ok, valid state
console.log(fillWithZ(["A","A","A","A","A","A"])) // bad, invalid state

nếu arrtrở thành một đối tượng bất biến, thì chúng ta sẽ chắc chắn rằng mảng luôn ở trạng thái hợp lệ.


Tôi nghĩ arrbị đột biến mỗi khi bạn gọifillWithZ
Rodrigo-silveira

nếu bạn sử dụng tệp bất biến, bạn sẽ nhận được một bản sao mới của đối tượng mỗi khi bạn thay đổi nó. vì vậy đối tượng ban đầu không bị ảnh hưởng
bedorlan
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.