เหตุใดการเปลี่ยนแปลงไม่ได้จึงสำคัญ (หรือจำเป็น) ใน JavaScript


206

ฉันกำลังทำงานกับReact JSและReact Native framework ในช่วงครึ่งทางฉันพบว่า Immutability หรือห้องสมุด Immutable -JSเมื่อฉันอ่านเกี่ยวกับการใช้ Flux และ Redux ของ Facebook

คำถามคือทำไมการไม่เปลี่ยนรูปจึงสำคัญมาก? เกิดอะไรขึ้นในการกลายพันธุ์วัตถุ? มันไม่ได้ทำให้สิ่งต่าง ๆ ง่ายขึ้น?

ยกตัวอย่างให้เราพิจารณาแอพอ่านข่าวแบบง่ายโดยมีหน้าจอเปิดเป็นมุมมองรายการของหัวข้อข่าว

หากฉันตั้งค่าให้บอกว่าอาร์เรย์ของวัตถุที่มีค่าเริ่มต้นฉันไม่สามารถจัดการมันได้ นั่นคือสิ่งที่หลักการเปลี่ยนแปลงไม่ได้พูดว่าใช่มั้ย (แก้ไขให้ถูกต้องหากฉันทำผิด) แต่จะเกิดอะไรขึ้นถ้าฉันมีวัตถุข่าวใหม่ที่ต้องได้รับการปรับปรุง ในกรณีปกติฉันสามารถเพิ่มวัตถุลงในอาร์เรย์ได้ ฉันจะประสบความสำเร็จในกรณีนี้ได้อย่างไร ลบร้านค้าและสร้างใหม่หรือไม่ การเพิ่มวัตถุลงในอาร์เรย์เป็นการดำเนินการที่ไม่แพงหรือไม่


7
ที่เกี่ยวข้อง: programmers.stackexchange.com/questions/151733/…
ขอบคุณ

2
โครงสร้างข้อมูลที่ไม่เปลี่ยนรูปแบบและฟังก์ชั่นแท้นำไปสู่ความโปร่งใสในการอ้างอิงทำให้ง่ายขึ้นมากในการให้เหตุผลเกี่ยวกับพฤติกรรมของโปรแกรมของคุณ คุณยังได้รับการย้อนรอยได้ฟรีเมื่อใช้โครงสร้างข้อมูลที่ใช้งานได้
WorBlux

ฉันให้มุมมอง Redux @bozzmob
prosti

1
อาจเป็นประโยชน์ในการเรียนรู้เกี่ยวกับ immurability โดยทั่วไปเป็นแนวคิดของกระบวนทัศน์การทำงานแทนที่จะพยายามคิดว่า JS มีบางอย่างที่จะทำกับมัน ปฏิกิริยาจะถูกเขียนโดยแฟน ๆ ของการเขียนโปรแกรมการทำงาน คุณต้องรู้สิ่งที่พวกเขารู้ที่จะเข้าใจพวกเขา
Gherman

คำตอบ:


196

ฉันเพิ่งค้นคว้าหัวข้อเดียวกัน ฉันจะพยายามอย่างดีที่สุดเพื่อตอบคำถามของคุณและพยายามแบ่งปันสิ่งที่ฉันได้เรียนรู้ไปแล้ว

คำถามคือทำไมการไม่เปลี่ยนรูปจึงสำคัญมาก? เกิดอะไรขึ้นในการกลายพันธุ์วัตถุ? มันไม่ได้ทำให้สิ่งต่าง ๆ ง่ายขึ้น?

โดยพื้นฐานแล้วมากับความจริงที่ว่าการไม่เปลี่ยนรูปจะเพิ่มความสามารถในการคาดการณ์ประสิทธิภาพ (ทางอ้อม) และช่วยให้สามารถติดตามการกลายพันธุ์ได้

การคาดการณ์

การกลายพันธุ์ซ่อนการเปลี่ยนแปลงซึ่งสร้าง (ไม่คาดคิด) ผลข้างเคียงซึ่งอาจทำให้เกิดข้อบกพร่องที่น่ารังเกียจ เมื่อคุณบังคับใช้ความไม่สามารถเปลี่ยนแปลงได้คุณสามารถทำให้สถาปัตยกรรมแอปพลิเคชันของคุณและแบบจำลองทางจิตง่ายขึ้นซึ่งทำให้ง่ายขึ้นในการให้เหตุผลเกี่ยวกับแอปพลิเคชันของคุณ

ประสิทธิภาพ

แม้ว่าการเพิ่มค่าให้กับวัตถุที่ไม่เปลี่ยนรูปแบบหมายความว่าจะต้องสร้างอินสแตนซ์ใหม่โดยที่ค่าที่มีอยู่จะต้องมีการคัดลอกและค่าใหม่จะต้องเพิ่มไปยังวัตถุใหม่ซึ่งหน่วยความจำราคาวัตถุที่ไม่เปลี่ยนรูป เหนือศีรษะ

การอัปเดตทั้งหมดส่งคืนค่าใหม่ แต่โครงสร้างภายในจะถูกใช้ร่วมกันเพื่อลดการใช้หน่วยความจำอย่างมาก (และ GC thrashing) ซึ่งหมายความว่าหากคุณต่อท้ายเวกเตอร์ที่มี 1,000 อิลิเมนต์มันไม่ได้สร้างเวกเตอร์ใหม่ที่มีความยาว 1,001 องค์ประกอบ เป็นไปได้มากที่จะมีการจัดสรรวัตถุขนาดเล็กเพียงเล็กน้อยภายใน

คุณสามารถอ่านเพิ่มเติมเกี่ยวกับเรื่องนี้ที่นี่

การติดตามการกลายพันธุ์

นอกเหนือจากการลดการใช้หน่วยความจำการเปลี่ยนแปลงไม่ได้ช่วยให้คุณสามารถปรับแต่งแอปพลิเคชันของคุณโดยใช้ความเท่าเทียมกันของการอ้างอิงและคุณค่า สิ่งนี้ทำให้ง่ายต่อการดูว่ามีอะไรเปลี่ยนแปลงหรือไม่ ตัวอย่างเช่นการเปลี่ยนแปลงสถานะในองค์ประกอบการตอบสนอง คุณสามารถใช้shouldComponentUpdateเพื่อตรวจสอบว่าสถานะเหมือนกันหรือไม่โดยการเปรียบเทียบสถานะวัตถุและป้องกันการเรนเดอร์ที่ไม่จำเป็น คุณสามารถอ่านเพิ่มเติมเกี่ยวกับเรื่องนี้ที่นี่

แหล่งข้อมูลเพิ่มเติม:

ถ้าฉันตั้งว่าอาร์เรย์ของวัตถุที่มีค่าเริ่มต้น ฉันไม่สามารถจัดการได้ นั่นคือสิ่งที่หลักการเปลี่ยนแปลงไม่ได้พูดว่าใช่มั้ย (แก้ไขฉันถ้าฉันผิด) แต่ถ้าฉันมีวัตถุ News ใหม่ที่ต้องอัพเดท? ในกรณีปกติฉันสามารถเพิ่มวัตถุลงในอาร์เรย์ได้ ฉันจะประสบความสำเร็จในกรณีนี้ได้อย่างไร ลบร้านค้าและสร้างใหม่ไหม การเพิ่มวัตถุลงในอาร์เรย์เป็นการดำเนินการที่ไม่แพงหรือไม่

ใช่ถูกต้องแล้ว หากคุณสับสนเกี่ยวกับวิธีการใช้งานในแอปพลิเคชันของคุณฉันขอแนะนำให้คุณดูว่าReduxทำเช่นนี้เพื่อทำความคุ้นเคยกับแนวคิดหลักได้อย่างไรมันช่วยฉันได้มาก

ฉันชอบที่จะใช้ Redux เป็นตัวอย่างเพราะมันโอบกอดไม่เปลี่ยนรูป มันมีแผนผังของรัฐที่ไม่เปลี่ยนรูปแบบเดียว (เรียกว่าstore) ซึ่งการเปลี่ยนแปลงสถานะทั้งหมดจะชัดเจนโดยการส่งการกระทำที่ประมวลผลโดยตัวลดที่ยอมรับสถานะก่อนหน้านี้พร้อมกับการกระทำดังกล่าว (ทีละครั้ง) และส่งคืนสถานะถัดไปของแอปพลิเคชันของคุณ . คุณสามารถอ่านเพิ่มเติมเกี่ยวกับหลักการพื้นฐานของมันนี่

มีหลักสูตร redux ที่ยอดเยี่ยมในegghead.ioโดยที่Dan Abramovผู้เขียน redux อธิบายหลักการเหล่านี้ดังต่อไปนี้ (ฉันแก้ไขโค้ดเล็กน้อยเพื่อให้เหมาะกับสถานการณ์):

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();

นอกจากนี้วิดีโอเหล่านี้ยังแสดงให้เห็นถึงรายละเอียดเพิ่มเติมเกี่ยวกับวิธีทำให้ไม่สามารถใช้งานได้สำหรับ:


1
@naomik ขอบคุณสำหรับข้อเสนอแนะ! ความตั้งใจของฉันคือการแสดงแนวคิดและแสดงให้เห็นอย่างชัดเจนว่า Objects ไม่ได้ถูกเปลี่ยนแปลงและไม่จำเป็นต้องแสดงวิธีการนำไปใช้ให้เกิดประโยชน์สูงสุด อย่างไรก็ตามตัวอย่างของฉันอาจสับสนเล็กน้อยฉันจะอัปเดตในอีกสักครู่
danillouz

2
@bozzmob ยินดีต้อนรับคุณ! ไม่ที่ไม่ถูกต้องคุณต้องบังคับไม่เปลี่ยนรูปในตัวลด ซึ่งหมายความว่าคุณสามารถทำตามกลยุทธ์เช่นแสดงในวิดีโอหรือใช้ห้องสมุดอย่างไม่เปลี่ยนรูป คุณสามารถค้นหาข้อมูลเพิ่มเติมได้ที่นี่และที่นี่
danillouz

1
@naomik ES6 constไม่ได้เกี่ยวกับการเปลี่ยนแปลงไม่ได้ Mathias Bynens เขียนบทความบล็อกที่ยอดเยี่ยมเกี่ยวกับเรื่องนี้
Lea Rosema

1
@terabaud ขอบคุณที่แชร์ลิงก์ ฉันยอมรับว่ามันเป็นความแตกต่างที่สำคัญ ^ _ ^
ขอบคุณ

4
โปรดอธิบายว่า "Mutation hides change ซึ่งสร้าง (ไม่คาดคิด) ผลข้างเคียงซึ่งอาจทำให้เกิดข้อผิดพลาดที่น่ารังเกียจเมื่อคุณบังคับใช้ความไม่สามารถเปลี่ยนแปลงได้คุณสามารถทำให้สถาปัตยกรรมแอปพลิเคชันของคุณและแบบจำลองทางจิตง่ายขึ้น เพราะนี่ไม่เป็นความจริงเลยในบริบทของ JavaScript
Pavle Lekic

143

มุมมองที่แตกของความไม่สามารถใช้งานได้

TL / DR: การเปลี่ยนไม่ได้เป็นเทรนด์แฟชั่นมากกว่าความจำเป็นใน JavaScript หากคุณกำลังใช้ React มันจะช่วยให้คุณมีทางเลือกในการออกแบบที่สับสนในการจัดการของรัฐ อย่างไรก็ตามในสถานการณ์อื่น ๆ ส่วนใหญ่จะไม่เพิ่มมูลค่ามากเกินความซับซ้อนที่แนะนำให้บริการมากขึ้นในการทำประวัติย่อกว่าที่จะตอบสนองความต้องการของลูกค้าที่แท้จริง

คำตอบยาว: อ่านด้านล่าง

ทำไมการไม่เปลี่ยนรูปจึงสำคัญมาก (หรือจำเป็น) ในจาวาสคริปต์?

ฉันดีใจที่คุณถาม!

ก่อนหน้านี้มีชายผู้มีความสามารถมากคนหนึ่งชื่อDan Abramovเขียนไลบรารีการจัดการสถานะ javascript ชื่อว่าReduxซึ่งใช้ฟังก์ชั่นที่บริสุทธิ์และไม่สามารถเปลี่ยนแปลงได้ นอกจากนี้เขายังสร้างวิดีโอเจ๋ง ๆที่ทำให้ความคิดนั้นเข้าใจง่าย (และขาย)

ช่วงเวลานั้นสมบูรณ์แบบ ความแปลกใหม่ของเชิงมุมถูกซีดจางและโลก JavaScript ก็พร้อมที่จะ fixate ในสิ่งใหม่ล่าสุดที่มีการศึกษาระดับปริญญาขวาของเย็นและห้องสมุดนี้ไม่ได้เป็นนวัตกรรมใหม่เพียง แต่เสียบในอย่างสมบูรณ์แบบด้วยReactซึ่งถูกเร่ขายอีกโรงไฟฟ้า Silicon Valley

น่าเศร้าที่มันเป็นเช่นนั้นแฟชั่นต่างก็ปกครองโลกแห่ง JavaScript ตอนนี้อับรามอฟกำลังถูกยกย่องว่าเป็นเดมิโกดและพวกเราทุกคนก็ต้องอยู่ภายใต้Dao of Immutability ... ไม่ว่าจะเหมาะสมหรือไม่

เกิดอะไรขึ้นในการกลายพันธุ์วัตถุ?

ไม่มีอะไร!

ในความเป็นจริงโปรแกรมเมอร์ได้กลายพันธุ์วัตถุสำหรับเอ้อ ... ตราบเท่าที่มีวัตถุที่จะกลายพันธุ์ การพัฒนาแอพพลิเคชั่นมากกว่า50 ปี

แล้วทำไมมันซับซ้อนล่ะ? เมื่อคุณมีวัตถุcatและมันตายคุณต้องการวินาทีcatในการติดตามการเปลี่ยนแปลงหรือไม่? คนส่วนใหญ่จะพูดcat.isDead = trueและทำกับมัน

ไม่กลายพันธุ์ (วัตถุกลายพันธุ์) ทำให้สิ่งต่าง ๆ ง่ายขึ้นหรือไม่

ใช่! .. แน่นอน!

พิเศษใน JavaScript ซึ่งในทางปฏิบัติมีประโยชน์มากที่สุดที่ใช้สำหรับการแสดงผลมุมมองของบางสถานะที่ถูกเก็บรักษาไว้ที่อื่น (เช่นในฐานข้อมูล)

จะเกิดอะไรขึ้นถ้าฉันมีวัตถุ News ใหม่ที่ต้องได้รับการปรับปรุง ... ฉันจะบรรลุในกรณีนี้ได้อย่างไร? ลบร้านค้าและสร้างใหม่ไหม การเพิ่มวัตถุลงในอาร์เรย์เป็นการดำเนินการที่ไม่แพงหรือไม่

คุณสามารถใช้วิธีดั้งเดิมและอัปเดตNewsวัตถุเพื่อให้การแสดงในหน่วยความจำของวัตถุนั้นเปลี่ยนไป (และมุมมองที่แสดงให้กับผู้ใช้หรือหวังว่าจะได้)

หรือมิฉะนั้น ...

คุณสามารถลองเซ็กซี่ FP / วิธี Immutability และเพิ่มการเปลี่ยนแปลงของคุณไปยังNewsวัตถุไปยังอาร์เรย์ติดตามการเปลี่ยนแปลงทุกครั้งประวัติศาสตร์เพื่อให้คุณสามารถแล้วย้ำผ่านอาร์เรย์และคิดออกว่าการเป็นตัวแทนของรัฐที่ถูกต้องควรจะเป็น (วุ้ย!)

ฉันพยายามที่จะเรียนรู้สิ่งที่นี่ โปรดให้ความกระจ่างแก่ฉัน :)

แฟชั่นมาและไปเป็นเพื่อน มีหลายวิธีในการดูแลแมว

ฉันขอโทษที่คุณต้องแบกรับความสับสนของกระบวนทัศน์การเขียนโปรแกรมที่เปลี่ยนแปลงตลอดเวลา แต่เดี๋ยวก่อนยินดีต้อนรับสู่คลับ !!

ตอนนี้สองจุดสำคัญที่ต้องจำเกี่ยวกับ Immutability และคุณจะได้รับการโยนเหล่านี้ที่คุณด้วยความรุนแรงไข้ที่ไร้เดียงสาเท่านั้นที่สามารถรวบรวม

1) Immutability เป็นที่น่ากลัวสำหรับการหลีกเลี่ยงสภาพการแข่งขันในแบบมัลติเธรดสภาพแวดล้อม

สภาพแวดล้อมแบบมัลติเธรด (เช่น C ++, Java และ C #) เป็นความผิดของการฝึกการล็อกวัตถุเมื่อมีมากกว่าหนึ่งเธรดที่ต้องการเปลี่ยน สิ่งนี้ไม่ดีต่อประสิทธิภาพ แต่ดีกว่าทางเลือกของข้อมูลเสียหาย และยังไม่ดีเท่าที่ทำให้ทุกอย่างเปลี่ยนรูป (ลอร์ดสรรเสริญ Haskell!)

แต่อนิจจา! ในจาวาสคริปต์คุณทำงานในหัวข้อเดียวเสมอ แม้แต่คนทำงานเว็บ (แต่ละคนทำงานในบริบทที่แยกต่างหาก ) ดังนั้นตั้งแต่คุณไม่สามารถมีที่เกี่ยวข้องกับด้ายสภาพการแข่งขันภายในบริบทของการดำเนินการของคุณ (ทุกคนตัวแปรทั่วโลกที่น่ารักและปิด) จุดหลักในความโปรดปรานของ Immutability ออกไปข้างนอกหน้าต่าง

(ต้องบอกว่ามีเป็นข้อได้เปรียบจากการใช้ฟังก์ชั่นที่บริสุทธิ์ในคนงานเว็บซึ่งเป็นว่าคุณจะมีความคาดหวังเกี่ยวกับการเล่นซอกับวัตถุบนหัวข้อหลัก no.)

2) ความไม่สามารถเปลี่ยนแปลงได้ (อย่างใด) หลีกเลี่ยงสภาพการแข่งขันในสถานะแอปของคุณ

และนี่คือปมที่แท้จริงของเรื่องนี้นักพัฒนาส่วนใหญ่ (React) จะบอกคุณว่า Immutability และ FP นั้นสามารถใช้เวทย์มนตร์นี้ที่ช่วยให้สถานะแอปพลิเคชันของคุณสามารถคาดเดาได้

แน่นอนว่านี่ไม่ได้หมายความว่าคุณสามารถหลีกเลี่ยงสภาพการแข่งขันในฐานข้อมูลเพื่อดึงสิ่งนั้นออกคุณต้องประสานงานผู้ใช้ทั้งหมดในเบราว์เซอร์ทั้งหมดและเพื่อที่คุณจะต้องใช้เทคโนโลยีการกดแบ็คเอนด์เช่นWebSockets ( เพิ่มเติมเกี่ยวกับด้านล่าง) ที่จะออกอากาศการเปลี่ยนแปลงสำหรับทุกคนที่เรียกใช้แอป

ไม่ได้หมายความว่ามีปัญหาบางอย่างใน JavaScript ที่สถานะแอปพลิเคชันของคุณต้องการไม่สามารถเปลี่ยนแปลงได้เพื่อที่จะคาดเดาได้นักพัฒนาใด ๆ ที่ได้รับการเข้ารหัสแอปพลิเคชันส่วนหน้าก่อนที่ React จะบอกคุณ

การเรียกร้องที่ค่อนข้างสับสนนี้หมายถึงว่าด้วยการตอบโต้สถานะแอปพลิเคชันของคุณจะมีแนวโน้มที่จะมีสภาพการแข่งขันสูงขึ้น ทำไม? เพราะตอบสนองเป็นพิเศษ .. มันได้รับการออกแบบมาเป็นห้องสมุดการแสดงผลที่ดีที่สุดอย่างกับการจัดการของรัฐที่สอดคล้องกันที่เกิดขึ้นที่สองและทำให้รัฐเป็นส่วนประกอบจะมีการจัดการผ่านทางห่วงโซ่ของเหตุการณ์ที่ไม่ตรงกัน (aka "ข้อมูลทางเดียวที่มีผลผูกพัน") ที่คุณไม่มีการควบคุม มากกว่าและพึ่งพาคุณจำไม่ได้ที่จะกลายพันธุ์รัฐโดยตรง ...

ด้วยบริบทนี้มันง่ายที่จะเห็นว่าความจำเป็นในการเปลี่ยนแปลงไม่ได้มีส่วนเกี่ยวข้องกับ JavaScript และสิ่งที่เกี่ยวข้องกับเชื้อชาติใน React: ถ้ามีการเปลี่ยนแปลงหลายอย่างในแอพพลิเคชั่นของคุณ รัฐของคุณในขณะที่, คุณจะได้รับการสับสนและทำให้มันทำให้รู้สึกดีกับการใช้การไม่เปลี่ยนรูปเพื่อติดตามการเปลี่ยนแปลงทุกครั้งประวัติศาสตร์

3) สภาพการแข่งขันแย่มาก

พวกมันอาจจะเป็นถ้าคุณใช้ React แต่มันก็หายากถ้าคุณเลือกกรอบที่แตกต่าง

นอกจากนี้โดยปกติคุณมีปัญหาที่ใหญ่กว่ามากในการจัดการกับ ... ปัญหาเช่นนรกที่ต้องพึ่งพา เหมือนรหัสฐานป่อง เช่นเดียวกับ CSS ของคุณที่ไม่โหลด เช่นกระบวนการสร้างที่ช้าหรือติดอยู่กับส่วนหลังเสาหินซึ่งทำให้ไม่สามารถวนซ้ำได้ เช่นเดียวกับ devs ที่ไม่มีประสบการณ์ไม่เข้าใจว่าเกิดอะไรขึ้นและทำสิ่งที่ยุ่งเหยิง

คุณรู้. ความจริง แต่เฮ้ใครสนใจเรื่องนั้น

4) ความไม่สามารถเปลี่ยนแปลงได้ใช้ประเภทการอ้างอิงเพื่อลดผลกระทบด้านประสิทธิภาพของการติดตามการเปลี่ยนแปลงสถานะทุกครั้ง

เพราะอย่างจริงจังหากคุณกำลังจะคัดลอกข้อมูลทุกครั้งที่มีการเปลี่ยนแปลงสถานะของคุณคุณควรตรวจสอบให้แน่ใจว่าคุณฉลาดเกี่ยวกับเรื่องนี้

5) การเปลี่ยนไม่ได้ช่วยให้คุณสามารถเลิกทำสิ่งต่างๆได้

เพราะเอ่อ .. นี่คือฟีเจอร์อันดับหนึ่งที่ผู้จัดการโครงการของคุณกำลังจะถามใช่ไหม?

6) รัฐที่ไม่เปลี่ยนรูปนั้นมีศักยภาพที่น่าสนใจมากมายเมื่อรวมกับ WebSockets

สุดท้าย แต่ไม่ท้ายสุดการสะสมของ delta สถานะทำให้เป็นกรณีที่น่าสนใจร่วมกับ WebSockets ซึ่งช่วยให้การใช้งานง่ายของรัฐเป็นกระแสของเหตุการณ์ที่ไม่เปลี่ยนรูป ...

เมื่อเงินลดลงในแนวคิดนี้ (สถานะเป็นกระแสของเหตุการณ์ - แทนที่จะเป็นชุดของบันทึกที่แสดงถึงมุมมองล่าสุด) โลกที่ไม่เปลี่ยนรูปกลายเป็นสถานที่มหัศจรรย์ที่อาศัยอยู่ ที่ดินของเหตุการณ์ที่มาสงสัยและความเป็นไปได้ที่ฟันฝ่าเวลาตัวเอง และเมื่อทำถูกต้องนี้แน่นอนสามารถทำให้เวลาจริงปพลิเคชัน EASI เอ้อจะประสบความสำเร็จคุณก็ออกอากาศการไหลของเหตุการณ์ที่เกิดขึ้นกับทุกคนที่สนใจเพื่อให้พวกเขาสามารถสร้างตัวแทนของตัวเองในปัจจุบันและเขียนกลับการเปลี่ยนแปลงตัวเองของพวกเขาในการไหลของชุมชน

แต่ในบางจุดคุณตื่นขึ้นและตระหนักว่าสิ่งมหัศจรรย์และเวทมนตร์ไม่ได้มาฟรี แตกต่างจากเพื่อนร่วมงานที่กระตือรือร้นของคุณผู้มีส่วนได้เสียของคุณ (แท้จริงแล้วคนที่จ่ายเงินให้คุณ) สนใจเรื่องปรัชญาหรือแฟชั่นและเงินที่จ่ายเพื่อสร้างผลิตภัณฑ์ที่พวกเขาสามารถขายได้ และบรรทัดล่างคือมันยากที่จะเขียนโค้ดที่ไม่เปลี่ยนรูปแบบและทำลายมันได้ง่ายขึ้นรวมถึงมีจุดเล็ก ๆ ที่มี front-end ที่ไม่เปลี่ยนรูปถ้าคุณไม่มี back-end ที่จะสนับสนุนมัน เมื่อ (และถ้า!) คุณจนโน้มน้าวให้ผู้มีส่วนได้เสียของคุณที่คุณควรเผยแพร่และใช้เหตุการณ์ที่ผ่านTechology ผลักดันเช่น WebSockets คุณหาสิ่งที่เจ็บปวดก็คือการขนาดในการผลิต


ตอนนี้สำหรับคำแนะนำคุณควรเลือกที่จะยอมรับมัน

ทางเลือกในการเขียน JavaScript โดยใช้ FP / Immutability ยังเป็นตัวเลือกในการทำให้รหัสแอปพลิเคชันของคุณมีขนาดใหญ่ขึ้นซับซ้อนและจัดการได้ยากขึ้น ฉันจะขอเถียงสำหรับการ จำกัด วิธีการนี้จะ reducers Redux ของคุณจนกว่าคุณจะรู้ว่าคุณกำลังทำ ... และถ้าคุณกำลังจะไปข้างหน้าและการใช้งานโดยไม่คำนึงถึงการเปลี่ยนไม่ได้แล้วใช้รัฐไม่เปลี่ยนรูปไปยังกองใบสมัครของคุณทั้งหมดและไม่ได้เป็นเพียง ฝั่งไคลเอ็นต์เนื่องจากคุณขาดคุณค่าที่แท้จริงของมันเป็นอย่างอื่น

ตอนนี้ถ้าคุณโชคดีพอที่จะสามารถสร้างทางเลือกในการทำงานของคุณแล้วลองและใช้ภูมิปัญญาของคุณ (หรือไม่) และทำสิ่งที่ถูกต้องโดยผู้ที่จะจ่ายเงินให้คุณ คุณสามารถยึดสิ่งนี้จากประสบการณ์ของคุณในทางเดินอาหารหรือสิ่งที่เกิดขึ้นรอบตัวคุณ (ยอมรับได้ว่าทุกคนใช้ React / Redux ดังนั้นจึงมีข้อโต้แย้งที่ถูกต้องว่าจะหาทรัพยากรเพื่อทำงานของคุณได้ง่ายขึ้น) .. คุณสามารถลองทั้งResume ขับเคลื่อนการพัฒนาหรือHype ขับเคลื่อนการพัฒนาแนวทาง พวกเขาอาจเป็นประเภทของคุณมากขึ้น

ในระยะสั้นสิ่งที่จะกล่าวถึงการเปลี่ยนไม่ได้คือมันจะทำให้คุณทันสมัยกับเพื่อนของคุณอย่างน้อยก็จนกว่าความนิยมต่อไปมาถึงจุดที่คุณจะดีใจที่จะไป


ตอนนี้หลังจากการบำบัดด้วยตนเองในครั้งนี้ฉันต้องการจะชี้ให้เห็นว่าฉันได้เพิ่มสิ่งนี้เป็นบทความในบล็อกของฉัน => ความไม่สามารถใช้งานได้ใน JavaScript: มุมมองที่แตก รู้สึกอิสระที่จะตอบกลับไปที่นั่นหากคุณมีความรู้สึกที่แข็งแกร่งที่คุณต้องการออกจากอกด้วย;)


10
สวัสดีสตีเวนใช่ ฉันมีข้อสงสัยเหล่านี้ทั้งหมดเมื่อฉันพิจารณา immutable.js และ redux แต่คำตอบของคุณวิเศษมาก! มันเพิ่มคุณค่ามากมายและขอบคุณสำหรับการกล่าวถึงทุกจุดที่ฉันสงสัย มันชัดเจนมากขึ้น / ดีขึ้นมากในขณะนี้แม้หลังจากทำงานเป็นเวลาหลายเดือนสำหรับวัตถุที่ไม่เปลี่ยนรูป
bozzmob

5
ฉันใช้ React กับ Flux / Redux มานานกว่าสองปีแล้วและฉันก็ไม่เห็นด้วยกับคุณมากนักตอบเป็นเยี่ยม
Pavle Lekic

6
ฉันสงสัยอย่างมากว่ามุมมองเกี่ยวกับความไม่สามารถเปลี่ยนแปลงได้นั้นมีความสัมพันธ์กับขนาดของทีมและโค้ดเบสอย่างเป็นระเบียบและฉันไม่คิดว่ามันเป็นเรื่องบังเอิญที่ผู้เสนอหลักคือยักษ์ซิลิคอนแวลลีย์ ที่ถูกกล่าวว่าฉันไม่เห็นด้วยอย่างเคารพ: ความไม่สามารถเปลี่ยนแปลงได้เป็นวินัยที่มีประโยชน์อย่างที่ไม่ได้ใช้ goto เป็นวินัยที่มีประโยชน์ หรือทดสอบหน่วย หรือ TDD หรือการวิเคราะห์ชนิดคงที่ ไม่ได้หมายความว่าคุณทำมันตลอดเวลาทุกครั้ง (แม้ว่าบางคนทำ) ฉันก็จะบอกว่ายูทิลิตี้ที่เป็นมุมฉากเพื่อ hype: ในเมทริกซ์ของประโยชน์ / ฟุ่มเฟือยและเซ็กซี่ / น่าเบื่อมีตัวอย่างมากมายของแต่ละคน "hyped" !== "bad"
Jared Smith

4
สวัสดี @ftor จุดดีเอาสิ่งต่าง ๆ ไปไกลเกินไปในทิศทางอื่น อย่างไรก็ตามเนื่องจากมีความหลากหลายของบทความ 'pro-immutability in javascript' และการโต้เถียงที่นั่นฉันรู้สึกว่าฉันต้องการสร้างความสมดุลให้กับสิ่งต่าง ๆ ดังนั้นมือใหม่มีมุมมองตรงข้ามเพื่อช่วยให้พวกเขาตัดสินด้วยวิธีใดวิธีหนึ่ง
Steven de Salas

4
ให้ข้อมูลและตั้งชื่ออย่างชาญฉลาด จนกว่าฉันจะพบคำตอบนี้ฉันคิดว่าฉันเป็นคนเดียวที่ถือมุมมองที่คล้ายกัน ฉันตระหนักถึงคุณค่าของความไม่เปลี่ยนรูป แต่สิ่งที่รบกวนจิตใจฉันก็คือมันกลายเป็นความเชื่อที่มีเทคนิคอื่น ๆ (เช่นความเสียหายของการผูกมัดแบบ 2 ทางซึ่งมีประโยชน์อย่างมากสำหรับการจัดรูปแบบอินพุตตามที่นำมาใช้ใน KnockoutJS เป็นต้น)
Tyblitz

53

คำถามคือทำไมการไม่เปลี่ยนรูปจึงสำคัญมาก? เกิดอะไรขึ้นในการกลายพันธุ์วัตถุ? มันไม่ได้ทำให้สิ่งต่าง ๆ ง่ายขึ้น?

อันที่จริงแล้วตรงกันข้ามคือความจริง: ความไม่แน่นอนทำให้สิ่งต่าง ๆ มีความซับซ้อนมากขึ้นอย่างน้อยในระยะยาว ใช่มันทำให้การเข้ารหัสเริ่มต้นของคุณง่ายขึ้นเพราะคุณสามารถเปลี่ยนแปลงสิ่งต่าง ๆ ได้ทุกที่ที่คุณต้องการ แต่เมื่อโปรแกรมของคุณมีขนาดใหญ่ขึ้นมันจะกลายเป็นปัญหา - ถ้าค่าเปลี่ยนไป

เมื่อคุณทำให้ทุกอย่างเปลี่ยนแปลงไม่ได้หมายความว่าข้อมูลไม่สามารถเปลี่ยนแปลงได้ด้วยความประหลาดใจอีกต่อไป คุณรู้แน่นอนว่าถ้าคุณส่งค่าเข้าไปในฟังก์ชั่นมันจะไม่สามารถเปลี่ยนแปลงได้ในฟังก์ชั่นนั้น

กล่าวง่ายๆ: ถ้าคุณใช้ค่าที่ไม่เปลี่ยนรูปแบบมันทำให้เหตุผลของโค้ดของคุณนั้นง่ายมาก: ทุกคนได้รับสำเนาของข้อมูลของคุณที่ไม่ซ้ำใครดังนั้นมันจึงไม่สามารถ Futz กับมันและทำลายส่วนอื่น ๆ ของรหัสของคุณ ลองนึกภาพว่าการทำงานในแบบมัลติเธรดนั้นง่ายขึ้นเพียงใด!

หมายเหตุ 1: มีค่าประสิทธิภาพที่อาจเกิดขึ้นกับการเปลี่ยนไม่ได้ขึ้นอยู่กับสิ่งที่คุณทำ แต่สิ่งต่าง ๆ เช่น Immutable.js จะปรับให้เหมาะสมที่สุดเท่าที่จะทำได้

หมายเหตุ 2: ในเหตุการณ์ที่ไม่น่าเป็นไปได้ที่คุณไม่แน่ใจ Immutable.js และ ES6 constหมายถึงสิ่งที่แตกต่างกันมาก

ในกรณีปกติฉันสามารถเพิ่มวัตถุลงในอาร์เรย์ได้ ฉันจะประสบความสำเร็จในกรณีนี้ได้อย่างไร ลบร้านค้าและสร้างใหม่ไหม การเพิ่มวัตถุลงในอาร์เรย์เป็นการดำเนินการที่ไม่แพงหรือไม่ ป.ล. : หากตัวอย่างไม่ใช่วิธีที่ถูกต้องในการอธิบายการเปลี่ยนแปลงไม่ได้โปรดแจ้งให้เราทราบว่าตัวอย่างการปฏิบัติที่ถูกต้องคืออะไร

ใช่ตัวอย่างข่าวของคุณดีมากและการให้เหตุผลของคุณถูกต้อง: คุณไม่สามารถแก้ไขรายการที่มีอยู่ได้ดังนั้นคุณต้องสร้างรายการใหม่:

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

1
ฉันไม่เห็นด้วยกับคำตอบนี้ แต่ไม่ได้ตอบคำถามของเขาว่า "ฉันต้องการเรียนรู้จากตัวอย่างที่ใช้งานได้จริง" หนึ่งอาจยืนยันว่าการอ้างอิงเดียวกับรายการส่วนหัวของข่าวที่ใช้ในหลายพื้นที่เป็นสิ่งที่ดี "ฉันต้องอัปเดตรายการเพียงครั้งเดียวและทุกอย่างที่อ้างอิงรายการข่าวจะได้รับการอัปเดตฟรี" - ฉันคิดว่าคำตอบที่ดีกว่าน่าจะเป็นปัญหาทั่วไปเช่นเขานำเสนอและแสดงทางเลือกที่มีค่าที่ใช้ไม่ได้
ขอบคุณ

1
ฉันดีใจที่คำตอบนั้นมีประโยชน์! เกี่ยวกับคำถามใหม่ของคุณ: อย่าพยายามเดาระบบ :) ในกรณีนี้สิ่งที่เรียกว่า "การแบ่งปันโครงสร้าง" ช่วยลด GC thrashing อย่างมาก - ถ้าคุณมี 10,000 รายการในรายการและเพิ่มอีก 10 ฉันเชื่อว่าไม่เปลี่ยนรูป js จะพยายามใช้โครงสร้างก่อนหน้านี้อีกครั้งอย่างดีที่สุดเท่าที่จะทำได้ ปล่อยให้ Immutable.js กังวลเกี่ยวกับความทรงจำและโอกาสที่คุณจะพบว่ามันออกมาดีกว่า
TwoStraws

6
Imagine how much easier this makes working in a multi-threaded environment!-> ตกลงสำหรับภาษาอื่น ๆ แต่นี่ไม่ใช่ข้อได้เปรียบใน JavaScript แบบเธรดเดียว
Steven de Salas

1
@StevendeSalas โปรดทราบว่า JavaScript นั้นเป็นแบบอะซิงโครนัสและเป็นตัวขับเคลื่อนเหตุการณ์เป็นหลัก มันไม่ได้มีภูมิคุ้มกันต่อสภาวะการแข่งขัน
Jared Smith

1
@ JaredSmith ยังคงเป็นจุดของฉัน FP และ Immutability เป็นกระบวนทัศน์ที่มีประโยชน์ยิ่งใหญ่เพื่อหลีกเลี่ยงความเสียหายของข้อมูลและ / หรือการล็อกทรัพยากรในสภาพแวดล้อมแบบมัลติเธรด แต่ไม่ได้อยู่ใน JavaScript เนื่องจากเป็นเธรดเดี่ยว ถ้าฉันไม่มีนักเก็ตศักดิ์สิทธิ์ผู้รู้แจ้งเรื่องการแลกเปลี่ยนหลักที่นี่คือว่าคุณพร้อมที่จะทำให้โค้ดของคุณซับซ้อนมากขึ้น (และช้าลง) ในการค้นหาเพื่อหลีกเลี่ยงสภาพการแข่งขัน ... ซึ่งมีปัญหาน้อยกว่าคนส่วนใหญ่ คิด.
Steven de Salas

37

ถึงแม้ว่าคำตอบอื่น ๆ จะมีการปรับเพื่อตอบคำถามของคุณเกี่ยวกับกรณีการใช้งานจริง (จากความคิดเห็นในคำตอบอื่น ๆ ) ช่วยให้ขั้นตอนนอกรหัสของคุณทำงานสำหรับนาทีและมองไปที่คำตอบที่แพร่หลายขวาภายใต้จมูกของคุณ: คอมไพล์ จะเกิดอะไรขึ้นถ้าทุกครั้งที่คุณส่งข้อความที่เขียนทับข้อมูลลงในที่เก็บ?

ตอนนี้เรากำลังอยู่ในหนึ่งในปัญหาที่คอลเลกชันที่ไม่เปลี่ยนรูปเผชิญ: หน่วยความจำขยายตัว Git นั้นฉลาดพอที่จะไม่เพียงแค่สร้างสำเนาไฟล์ใหม่ทุกครั้งที่คุณทำการเปลี่ยนแปลง แต่มันก็คอยติดตามความแตกต่าง

แม้ว่าฉันจะไม่ทราบมากเกี่ยวกับการทำงานภายในของ git แต่ฉันสามารถสันนิษฐานได้ว่ามันใช้กลยุทธ์ที่คล้ายกับของไลบรารีที่คุณอ้างอิง: การแบ่งปันโครงสร้าง ภายใต้ประทุนห้องสมุดใช้ลองหรือต้นไม้อื่น ๆ เพื่อติดตามเฉพาะโหนดที่แตกต่างกัน

กลยุทธ์นี้ยังมีประสิทธิภาพพอสมควรสำหรับโครงสร้างข้อมูลในหน่วยความจำเนื่องจากมีอัลกอริทึมการดำเนินการทรีที่รู้จักกันดีซึ่งทำงานในเวลาลอการิทึม

อีกกรณีการใช้งาน: สมมติว่าคุณต้องการปุ่มยกเลิกบนเว็บแอปของคุณ ด้วยการนำเสนอข้อมูลของคุณที่ไม่เปลี่ยนแปลงการดำเนินการดังกล่าวค่อนข้างไม่สำคัญ แต่ถ้าคุณพึ่งพาการกลายพันธุ์นั่นหมายความว่าคุณต้องกังวลกับการแคชสถานะของโลกและทำการอัปเดตอะตอมมิก

ในระยะสั้นมีราคาที่ต้องจ่ายสำหรับความไม่สามารถเปลี่ยนแปลงได้ในประสิทธิภาพรันไทม์และช่วงการเรียนรู้ แต่โปรแกรมเมอร์ที่มีประสบการณ์คนใดคนหนึ่งจะบอกคุณว่าเวลาในการดีบั๊กเมื่อเทียบกับเวลาในการเขียนโค้ดตามลำดับความสำคัญ และความนิยมในประสิทธิภาพการทำงานของรันไทม์นั้นน้อยกว่าข้อบกพร่องที่เกี่ยวข้องกับสถานะที่ผู้ใช้ของคุณไม่ต้องทน


1
ตัวอย่างที่ยอดเยี่ยมที่ฉันพูด ความเข้าใจของฉันเกี่ยวกับความไม่สามารถเปลี่ยนรูปได้ชัดเจนขึ้น ขอบคุณเจเร็ด ที่จริงแล้วการใช้งานอย่างใดอย่างหนึ่งคือปุ่ม UNDO: D และคุณทำสิ่งที่ง่ายสำหรับฉัน
bozzmob

3
เพียงเพราะรูปแบบที่ทำให้รู้สึกในคอมไพล์ไม่ได้หมายความว่าสิ่งเดียวกันทำให้รู้สึกทุกที่ ในคอมไพล์คุณสนใจจริง ๆ เกี่ยวกับประวัติทั้งหมดที่เก็บไว้และคุณต้องการรวมสาขาที่แตกต่างกัน ส่วนหน้าคุณไม่สนใจประวัติส่วนใหญ่ของรัฐและคุณไม่ต้องการความซับซ้อนทั้งหมดนี้
สกี

2
@Ski มันซับซ้อนเพียงเพราะไม่ใช่ค่าเริ่มต้น ฉันมักจะไม่ใช้ mori หรือ immutable.js ในโครงการของฉัน: ฉันมักจะลังเลที่จะเป็นตัวแทนของบุคคลที่สาม แต่ถ้านั่นเป็นค่าเริ่มต้น (a la clojurescript) หรืออย่างน้อยก็มีอ็อปชั่นอ็อปชั่นดั้งเดิมฉันจะใช้มันตลอดเวลาเพราะเมื่อฉันเช่นโปรแกรมใน clojure ฉันไม่ได้ใส่ทุกอย่างลงในอะตอมทันที
Jared Smith

โจอาร์มสตรองจะบอกว่าไม่ต้องกังวลเกี่ยวกับการแสดงเพียงรอไม่กี่ปีและกฎหมายของมัวร์จะดูแลเรื่องนี้ให้คุณ
ximo

1
@JaredSmith คุณพูดถูกสิ่งเล็ก ๆ น้อย ๆ และ จำกัด ทรัพยากรมากขึ้น ฉันไม่แน่ใจว่าจะเป็นปัจจัย จำกัด สำหรับ JavaScript หรือไม่ เราค้นหาวิธีการใหม่ ๆ เพื่อปรับปรุงประสิทธิภาพ (ตัวอย่างเช่น Svelte) อย่างไรก็ตามฉันเห็นด้วยกับความคิดเห็นอื่นของคุณอย่างสมบูรณ์ ความซับซ้อนหรือความยากของการใช้โครงสร้างข้อมูลที่ไม่เปลี่ยนรูปมักจะเกิดขึ้นกับภาษาที่ไม่มีการสนับสนุนแนวคิด Clojure ทำให้การเปลี่ยนแปลงไม่ได้ง่าย ๆเพราะมันถูกอบเข้ากับภาษาภาษาทั้งหมดได้รับการออกแบบรอบความคิด
ximo

8

คำถามคือทำไมการไม่เปลี่ยนรูปจึงสำคัญมาก? เกิดอะไรขึ้นในการกลายพันธุ์วัตถุ? มันไม่ได้ทำให้สิ่งต่าง ๆ ง่ายขึ้น?

เกี่ยวกับความไม่แน่นอน

ไม่มีอะไรผิดปกติในความไม่แน่นอนจากมุมมองทางเทคนิค มันเร็วมันคือการใช้หน่วยความจำอีกครั้ง นักพัฒนาใช้มันตั้งแต่เริ่มต้น (ตามที่ฉันจำได้) มีปัญหาในการใช้ความไม่แน่นอนและปัญหาที่การใช้นี้สามารถนำมาได้

หากวัตถุไม่ได้ใช้ร่วมกับสิ่งใด ๆ ตัวอย่างเช่นมีอยู่ในขอบเขตของฟังก์ชั่นและไม่ได้สัมผัสกับภายนอกมันก็ยากที่จะเห็นประโยชน์ในความไม่สามารถเปลี่ยนแปลงได้ จริงๆแล้วในกรณีนี้มันไม่มีเหตุผลที่จะไม่เปลี่ยนรูป ความรู้สึกของการไม่เปลี่ยนรูปเริ่มต้นเมื่อมีการแชร์บางสิ่ง

ปวดหัวไม่แน่นอน

โครงสร้างที่ใช้ร่วมกันที่ไม่แน่นอนสามารถสร้างข้อผิดพลาดมากมาย การเปลี่ยนแปลงใด ๆ ในส่วนของรหัสที่มีการเข้าถึงการอ้างอิงมีผลกระทบต่อส่วนอื่น ๆ ที่มีการแสดงผลของการอ้างอิงนี้ ผลกระทบดังกล่าวเชื่อมต่อทุกส่วนเข้าด้วยกันแม้ว่าพวกเขาไม่ควรระวังโมดูลที่แตกต่างกัน การกลายพันธุ์ในฟังก์ชั่นหนึ่งอาจทำให้แอพแตกต่างกันโดยสิ้นเชิง สิ่งนั้นเป็นผลข้างเคียงที่ไม่ดี

ปัญหาการกลายพันธุ์ต่อไปมักจะเป็นสถานะที่เสียหาย สถานะที่เสียหายสามารถเกิดขึ้นได้เมื่อโพรซีเดอร์การกลายพันธุ์ล้มเหลวที่อยู่ตรงกลางและบางฟิลด์ถูกแก้ไขและบางอันไม่

ยิ่งไปกว่านั้นด้วยการกลายพันธุ์มันเป็นการยากที่จะติดตามการเปลี่ยนแปลง การตรวจสอบการอ้างอิงอย่างง่ายจะไม่แสดงความแตกต่างหากต้องการทราบว่าต้องทำการเปลี่ยนแปลงบางอย่างในเชิงลึก นอกจากนี้เพื่อตรวจสอบการเปลี่ยนแปลงบางรูปแบบที่สังเกตได้จะต้องมีการแนะนำ

ในที่สุดการกลายพันธุ์เป็นเหตุผลของการขาดดุลความไว้วางใจ คุณจะมั่นใจได้อย่างไรว่าโครงสร้างบางอย่างต้องการคุณค่าถ้ามันสามารถกลายพันธุ์ได้

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

ตัวอย่างข้างต้นแสดงให้เห็นว่าการผ่านโครงสร้างที่ไม่แน่นอนสามารถทำได้โดยมีโครงสร้างที่แตกต่างกัน ฟังก์ชั่น doSomething กำลังกลายพันธุ์แอตทริบิวต์ที่ได้รับจากภายนอก ไม่น่าเชื่อถือสำหรับรหัสคุณไม่ทราบว่าสิ่งที่คุณมีและสิ่งที่คุณจะมี ปัญหาทั้งหมดเหล่านี้เกิดขึ้นเพราะ: โครงสร้างที่เปลี่ยนแปลงได้แสดงถึงตัวชี้ไปยังหน่วยความจำ

ความไม่สามารถเปลี่ยนแปลงได้นั้นเกี่ยวกับค่านิยม

การเปลี่ยนไม่ได้หมายความว่าการเปลี่ยนแปลงไม่ได้ทำในวัตถุโครงสร้างเดียวกัน แต่การเปลี่ยนแปลงจะแสดงในใหม่ และนี่เป็นเพราะการอ้างอิงหมายถึงค่าไม่เพียง แต่ตัวชี้หน่วยความจำ การเปลี่ยนแปลงทุกครั้งจะสร้างคุณค่าใหม่และไม่ได้สัมผัสสิ่งเก่า กฎที่ชัดเจนดังกล่าวให้ความน่าเชื่อถือและการคาดการณ์โค้ดกลับมา ฟังก์ชั่นมีความปลอดภัยในการใช้เพราะแทนที่จะเป็นการกลายพันธุ์พวกมันจะจัดการกับเวอร์ชั่นของตัวเองด้วยค่าของตัวเอง

การใช้ค่าแทนคอนเทนเนอร์หน่วยความจำให้ความมั่นใจว่าทุกอ็อบเจ็กต์แสดงถึงค่าที่ไม่สามารถเปลี่ยนได้โดยเฉพาะและปลอดภัยที่จะใช้

โครงสร้างที่ไม่เปลี่ยนรูปจะแสดงค่า

ฉันดำน้ำมากขึ้นในหัวข้อในบทความขนาดกลาง - https://medium.com/@macsikora/the-state-of-immutability-169d2cd11310


6

เหตุใดการเปลี่ยนแปลงไม่ได้จึงสำคัญ (หรือจำเป็น) ใน JavaScript

ความไม่เข้ากันสามารถติดตามได้ในบริบทต่าง ๆ แต่ที่สำคัญที่สุดคือการติดตามสถานะของแอปพลิเคชันและกับ UI แอปพลิเคชัน

ฉันจะพิจารณารูปแบบ JavaScript Redux เป็นแนวทางที่ทันสมัยและทันสมัยมากและเพราะคุณพูดถึงเรื่องนี้

สำหรับ UI เราต้องทำให้คาดเดาได้ UI = f(application state)มันจะสามารถคาดเดาได้ถ้า

โปรแกรม (ใน JavaScript) จะเปลี่ยนรัฐผ่านการกระทำที่ดำเนินการโดยใช้ฟังก์ชั่นลด

ฟังก์ชั่นลดจะใช้เวลาการกระทำและรัฐเก่าและส่งกลับรัฐใหม่ทำให้รัฐเก่าเหมือนเดิม

new state  = r(current state, action)

ป้อนคำอธิบายรูปภาพที่นี่

ประโยชน์คือ: คุณเดินทางข้ามเวลาตั้งแต่บันทึกวัตถุสถานะทั้งหมดและคุณสามารถแสดงผลแอปในสถานะใด ๆ นับตั้งแต่ UI = f(state)

ดังนั้นคุณสามารถเลิกทำ / ทำซ้ำได้อย่างง่ายดาย


เกิดขึ้นในการสร้างสถานะทั้งหมดเหล่านี้ยังคงมีประสิทธิภาพของหน่วยความจำการเปรียบเทียบกับ Git นั้นยอดเยี่ยมและเรามีการเปรียบเทียบที่คล้ายคลึงกันใน Linux OS พร้อมลิงก์สัญลักษณ์ (อิง inodes)


5

ประโยชน์อีกประการหนึ่งของความไม่สามารถเปลี่ยนแปลงได้ใน Javascript ก็คือมันช่วยลด Temporal Coupling ซึ่งมีประโยชน์มากมายสำหรับการออกแบบโดยทั่วไป พิจารณาอินเทอร์เฟซของวัตถุด้วยสองวิธี:

class Foo {

      baz() {
          // .... 
      }

      bar() {
          // ....
      }

}

const f = new Foo();

อาจเป็นกรณีที่baz()จำเป็นต้องมีการเรียกเพื่อรับวัตถุในสถานะที่ถูกต้องสำหรับการเรียกเพื่อbar()ให้ทำงานได้อย่างถูกต้อง แต่คุณจะรู้ได้อย่างไร

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

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

ในการคิดออกคุณจะต้องตรวจสอบภายใน internals เพราะไม่ปรากฏทันทีจากการตรวจสอบส่วนต่อประสานสาธารณะ ปัญหานี้สามารถเกิดการระเบิดใน codebase ขนาดใหญ่ที่มีสถานะไม่แน่นอนและชั้นเรียนจำนวนมาก

หากFooไม่เปลี่ยนรูปก็จะไม่มีปัญหาอีกต่อไป มันปลอดภัยที่จะสมมติว่าเราสามารถโทรbazหรือbarในลำดับใด ๆ เนื่องจากสภาพภายในของชั้นเรียนไม่สามารถเปลี่ยนแปลงได้


4

กาลครั้งหนึ่งมีปัญหากับการซิงโครไนซ์ข้อมูลระหว่างเธรด ปัญหานี้เป็นความเจ็บปวดที่ยอดเยี่ยมมีวิธีแก้ปัญหามากกว่า 10 ข้อ บางคนพยายามที่จะแก้ปัญหาอย่างรุนแรง มันเป็นสถานที่ที่การเขียนโปรแกรมการทำงานเกิด มันก็เหมือนกับมาร์กซ์ ฉันไม่เข้าใจว่า Dan Abramov ขายไอเดียนี้ให้ JS อย่างไรเพราะมันเป็นเธรดเดี่ยว เขาเป็นอัจฉริยะ

ฉันสามารถยกตัวอย่างเล็กน้อย มีแอตทริบิวต์เป็น__attribute__((pure))gcc คอมไพเลอร์พยายามที่จะแก้ปัญหาว่าฟังก์ชั่นของคุณบริสุทธิ์หรือไม่ ฟังก์ชั่นของคุณสามารถบริสุทธิ์แม้รัฐของคุณจะไม่แน่นอน การเปลี่ยนไม่ได้เป็นเพียงหนึ่งใน 100 วิธีที่จะรับประกันว่าการทำงานของคุณจะบริสุทธิ์ ที่จริง 95% ของฟังก์ชั่นของคุณจะบริสุทธิ์

คุณไม่ควรใช้ข้อ จำกัด ใด ๆ (เช่นการเปลี่ยนแปลงไม่ได้) หากคุณไม่มีเหตุผลที่จริงจัง หากคุณต้องการ "เลิกทำ" บางรัฐคุณสามารถสร้างธุรกรรม หากคุณต้องการทำให้การสื่อสารง่ายขึ้นคุณสามารถส่งกิจกรรมด้วยข้อมูลที่ไม่เปลี่ยนรูปแบบ มันขึ้นอยู่กับคุณ.

ฉันกำลังเขียนข้อความนี้จากสาธารณรัฐมาร์กซ์โพสต์ ฉันแน่ใจว่าการทำให้รุนแรงของความคิดใด ๆ เป็นวิธีที่ผิด


ย่อหน้าที่ 3 สมเหตุสมผลมาก ขอบคุณสำหรับสิ่งนั้น. 'หากคุณต้องการ "เลิกทำ" บางสถานะคุณสามารถสร้างธุรกรรม' !!
bozzmob

การเปรียบเทียบกับลัทธิมาร์กซ์ยังสามารถทำได้สำหรับ OOP จำชวา Heck, เศษเล็กเศษน้อยของ Java ใน JavaScript? Hype ไม่เคยดีมันทำให้เกิดอนุมูลอิสระและโพลาไรซ์ ในอดีต OOP นั้นถูกสะกดจิตมากกว่าการสะกดจิตของ Redux ใน Facebook แม้ว่าพวกเขาจะพยายามอย่างดีที่สุด
ximo

4

ใช้เวลาที่แตกต่างกัน ...

คำตอบอื่น ๆ ของฉันตอบคำถามจากมุมมองที่ใช้งานได้จริงและฉันก็ยังชอบ ฉันตัดสินใจที่จะเพิ่มคำตอบนี้เป็นคำตอบอื่น ๆ แทนที่จะเป็นภาคผนวกของคำตอบนั้นเพราะมันเป็นการพูดจาโผงผางที่น่าเบื่อซึ่งหวังว่าจะตอบคำถามได้ แต่ก็ไม่เหมาะกับคำตอบที่ฉันมีอยู่

TL; DR

แม้ในโครงการขนาดเล็กที่ไม่สามารถเปลี่ยนแปลงได้ก็มีประโยชน์ แต่อย่าคิดว่ามันมีอยู่สำหรับคุณ

คำตอบที่ยาวกว่ามาก

หมายเหตุ:สำหรับจุดประสงค์ของคำตอบนี้ฉันใช้คำว่า 'วินัย' เพื่อหมายถึงการปฏิเสธตนเองเพื่อประโยชน์บางอย่าง

สิ่งนี้มีความคล้ายคลึงกันในรูปแบบของคำถามอื่น: "ฉันควรใช้ตัวพิมพ์ดีดเหตุใดจึงมีความสำคัญใน JavaScript" มันมีคำตอบที่คล้ายกันด้วย พิจารณาสถานการณ์สมมติต่อไปนี้:

คุณเป็นผู้แต่งและผู้ดูแลฐานรหัส JavaScript / CSS / HTML เพียง 5,000 บรรทัด หัวหน้ากึ่งเทคนิคของคุณอ่านบางอย่างเกี่ยวกับ typescript-as-the-new-hotness และแนะนำว่าเราอาจต้องการที่จะย้ายไป แต่ให้การตัดสินใจกับคุณ ดังนั้นคุณอ่านเกี่ยวกับมันเล่นกับมัน ฯลฯ

ดังนั้นตอนนี้คุณมีทางเลือกที่จะทำให้คุณย้ายไปที่ typescript หรือไม่

typescript มีข้อได้เปรียบที่น่าสนใจ: Intellisense, การจับข้อผิดพลาดก่อนกำหนด, APIs ของคุณล่วงหน้า, ความสะดวกในการแก้ไขสิ่งต่าง ๆ เมื่อ refactoring แบ่งพวกเขา, การทดสอบน้อยลง typescript ยังมีค่าใช้จ่าย: สำนวน JavaScript ที่เป็นธรรมชาติและถูกต้องบางอย่างอาจเป็นเรื่องยากที่จะสร้างแบบจำลองในระบบประเภทที่ไม่ทรงพลังโดยเฉพาะคำอธิบายประกอบจะเพิ่มขึ้น LoC เวลาและความพยายามในการเขียนรหัสเบสที่มีอยู่ขั้นตอนพิเศษ โดยพื้นฐานแล้วมันจะทำการแกะส่วนย่อยของโปรแกรม JavaScript ที่ถูกต้องที่เป็นไปได้เพื่อแลกกับสัญญาที่รหัสของคุณมีแนวโน้มที่จะถูกต้องมากขึ้น มัน จำกัด โดยพลการ นั่นคือประเด็นทั้งหมด: คุณบังคับใช้วินัยที่ จำกัด คุณ

กลับไปที่คำถาม rephrased ในบริบทของวรรคข้างต้น: มันคุ้มค่าหรือไม่

ในสถานการณ์ที่อธิบายไว้ฉันจะยืนยันว่าถ้าคุณคุ้นเคยกับฐานรหัส JS ขนาดเล็กถึงปานกลางตัวเลือกในการใช้ typescript นั้นสวยงามกว่าการใช้งานจริง และก็ไม่เป็นไรมีอะไรผิดปกติกับความสวยงามพวกเขาก็ไม่จำเป็นต้องน่าสนใจ

สถานการณ์ B:

คุณเปลี่ยนงานและตอนนี้เป็นโปรแกรมเมอร์สายงานธุรกิจของ Foo Corp. คุณกำลังทำงานกับทีมงาน 10 คนใน 90000 LoC (และเพิ่มขึ้นเรื่อย ๆ ) JavaScript / HTML / CSS codebase พร้อมขั้นตอนการสร้างที่ค่อนข้างซับซ้อนซึ่งเกี่ยวข้องกับ babel, webpack ชุดของ polyfills ตอบสนองกับปลั๊กอินต่างๆระบบการจัดการของรัฐ ~ ห้องสมุดของบุคคลที่สาม 20 ~ 10 ห้องสมุดภายในปลั๊กอินแก้ไขเช่น linter กับกฎสำหรับคู่มือสไตล์ในบ้าน ฯลฯ

ย้อนกลับไปตอนที่คุณอายุ 5 ขวบ LoC ผู้ชาย / ผู้หญิงมันไม่สำคัญมากนัก เอกสารแม้ไม่ได้อยู่ที่การจัดการขนาดใหญ่แม้จะกลับไปเป็นส่วนหนึ่งของรหัสหลังจาก 6 เดือนที่ผ่านมาคุณอาจจะคิดออกได้อย่างง่ายดายพอ แต่ตอนนี้มีระเบียบวินัยไม่ได้เป็นเพียงดี แต่สิ่งที่จำเป็น มีระเบียบวินัยที่อาจไม่เกี่ยวข้องกับ typescript แต่จะมีแนวโน้มที่จะเกี่ยวข้องกับรูปแบบของการวิเคราะห์แบบคงที่บางเช่นเดียวกับทุกรูปแบบอื่น ๆ ของการเข้ารหัสวินัย (เอกสารคู่มือสไตล์สร้างสคริปต์การทดสอบการถดถอย CI) วินัยจะไม่มีอีกต่อไปความหรูหราก็เป็นความจำเป็น

ทั้งหมดนี้นำไปใช้กับGOTOในปี 1978: เกมแบล็กแจ็กตัวน้อยของคุณใน C สามารถใช้GOTOตรรกะและสปาเก็ตตี้และมันก็ไม่ใช่เรื่องใหญ่ที่จะเลือก - ของคุณเอง - ผจญภัยทางผ่าน แต่เป็นโปรแกรมที่มีขนาดใหญ่และ ความทะเยอทะยานมากขึ้น, ดี, วินัยใช้GOTOไม่สามารถยั่งยืน และทั้งหมดนี้นำไปใช้กับการเปลี่ยนแปลงไม่ได้ในปัจจุบัน

เช่นเดียวกับประเภทสแตติกถ้าคุณไม่ได้ทำงานกับ codebase ขนาดใหญ่กับทีมวิศวกรที่ดูแลรักษา / ขยายมันทางเลือกในการใช้ความไม่เปลี่ยนรูปนั้นมีความสวยงามมากกว่าในทางปฏิบัติ: ประโยชน์ยังอยู่ที่นั่น แต่อาจไม่คุ้มกับต้นทุน

แต่เช่นเดียวกับสาขาวิชาที่มีประโยชน์ทั้งหมดมีประเด็นที่ไม่จำเป็นอีกต่อไป ถ้าฉันต้องการรักษาน้ำหนักตัวให้แข็งแรงการมีวินัยที่เกี่ยวข้องกับไอศกรีมอาจเป็นทางเลือก แต่ถ้าฉันต้องการเป็นนักกีฬาที่แข่งขันการเลือกของฉันว่าจะกินไอศกรีมหรือไม่นั้นขึ้นอยู่กับเป้าหมายที่ฉันเลือก หากคุณต้องการเปลี่ยนแปลงโลกด้วยซอฟต์แวร์ความผันแปรไม่ได้อาจเป็นส่วนหนึ่งของสิ่งที่คุณต้องหลีกเลี่ยงการยุบตัวภายใต้น้ำหนักของตัวเอง


1
+1 ฉันชอบมัน มากขึ้นในจุด Jared และการที่ไม่สามารถเปลี่ยนแปลงได้นั้นจะไม่ช่วยทีมจากการขาดวินัยของตัวเอง 😉
Steven de Salas

@ StevendeSalas เป็นรูปแบบของการมีระเบียบวินัย และเช่นนี้ฉันคิดว่ามันมีความสัมพันธ์กับ (แต่ไม่แทนที่) ระเบียบวินัยวิศวกรรมซอฟต์แวร์รูปแบบอื่น ๆ มันเติมเต็มมากกว่าแทนที่ แต่ดังที่ฉันได้กล่าวไว้ในความคิดเห็นเกี่ยวกับคำตอบของคุณฉันไม่แปลกใจเลยที่มันถูกผลักดันโดยยักษ์ใหญ่ด้านเทคโนโลยีที่มีกลุ่มวิศวกรจำนวนหนึ่งบดขยี้ใน codebase ขนาดใหญ่เดียวกัน :) พวกเขาต้องการวินัยทั้งหมดที่พวกเขาจะได้รับ ฉันส่วนใหญ่ไม่ได้กลายพันธุ์วัตถุ แต่ยังไม่ได้ใช้รูปแบบการบังคับใด ๆ ตั้งแต่นั้นเป็นเพียงฉัน
Jared Smith

0

ฉันได้สร้างกรอบโอเพนซอร์สที่ไม่เชื่อเรื่องพระเจ้า (MIT) lib สำหรับสถานะที่ไม่แน่นอน (หรือไม่เปลี่ยนรูป) ซึ่งสามารถแทนที่ที่เก็บข้อมูลที่ไม่เปลี่ยนรูปแบบเหล่านั้นทั้งหมดเช่น libs (redux, vuex ฯลฯ ... )

รัฐที่ไม่เปลี่ยนรูปนั้นน่าเกลียดสำหรับฉันเพราะมีงานมากเกินไปที่จะทำ (การกระทำจำนวนมากสำหรับการดำเนินการอ่าน / เขียนอย่างง่าย) รหัสไม่สามารถอ่านได้และประสิทธิภาพสำหรับชุดข้อมูลขนาดใหญ่ไม่เป็นที่ยอมรับ

ด้วยผู้สังเกตการณ์ลึกฉันสามารถอัปเดตเพียงโหนดเดียวด้วยเครื่องหมายจุดและใช้สัญลักษณ์แทน ฉันยังสามารถสร้างประวัติศาสตร์ของรัฐ (ยกเลิก / ทำซ้ำ / เดินทางข้ามเวลา) โดยรักษาเฉพาะค่าที่เป็นรูปธรรมซึ่งมีการเปลี่ยนแปลง{path:value}= ใช้หน่วยความจำน้อยลง

ด้วยผู้สังเกตการณ์ระดับลึกฉันสามารถปรับแต่งสิ่งต่าง ๆ ได้อย่างละเอียดและฉันสามารถควบคุมการทำงานขององค์ประกอบของธัญพืชเพื่อให้สามารถปรับปรุงประสิทธิภาพได้อย่างมาก รหัสอ่านได้ง่ายขึ้นและการปรับโครงสร้างใหม่นั้นง่ายกว่ามากเพียงแค่ค้นหาและแทนที่สตริงพา ธ (ไม่จำเป็นต้องเปลี่ยนรหัส / ตรรกะ)


-1

ฉันคิดว่าเหตุผลหลักที่โปรไม่เปลี่ยนรูปวัตถุคือการรักษาสถานะของวัตถุที่ถูกต้อง

arrสมมติว่าเรามีวัตถุที่เรียกว่า วัตถุนี้ใช้ได้เมื่อรายการทั้งหมดเป็นตัวอักษรเดียวกัน

// 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

หากarrกลายเป็นวัตถุที่ไม่เปลี่ยนรูปแล้วเราจะมั่นใจได้ว่า arr อยู่ในสถานะที่ถูกต้องเสมอ


ฉันคิดว่าarrจะกลายพันธุ์ทุกครั้งที่คุณโทรfillWithZ
rodrigo-silveira

หากคุณใช้ immutable.js คุณจะได้รับสำเนาของวัตถุใหม่ทุกครั้งที่คุณเปลี่ยนแปลง ดังนั้นวัตถุดั้งเดิมจะไม่ถูกแตะต้อง
bedorlan
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.