JavaScript ਅਤੇ TypeScript ਆਬਜੈਕਟ ਰੈਫਰੈਂਸਾਂ (object references) ਨੂੰ ਇੱਕ ਵਾਰ ਵਰਤ ਕੇ ਸੁੱਟ ਦੇਣ (disposable) ਵਾਂਗ ਮੰਨਣਾ ਬਹੁਤ ਆਸਾਨ ਬਣਾ ਦਿੰਦੇ ਹਨ, ਜੋ ਕਿ ਖ਼ਤਰਨਾਕ ਹੋ ਸਕਦਾ ਹੈ। ਤੁਸੀਂ ਇੱਕ ਆਬਜੈਕਟ ਬਣਾਉਂਦੇ ਹੋ, ਇਸਨੂੰ ਕਿਸੇ ਫੰਕਸ਼ਨ ਨੂੰ ਭੇਜਦੇ ਹੋ, ਇਸਨੂੰ ਕੈਸ਼ (cache) ਵਿੱਚ ਸਟੋਰ ਕਰਦੇ ਹੋ, ਅਤੇ ਬਾਅਦ ਵਿੱਚ ਵੇਰੀਏਬਲ ਨੂੰ ਇੱਕ ਨਵੇਂ ਇੰਸਟੈਂਸ (instance) ਨਾਲ ਬਦਲ ਦਿੰਦੇ ਹੋ। ਭਾਸ਼ਾ ਇਸ ਬਾਰੇ ਕੋਈ ਸ਼ਿਕਾਇਤ ਨਹੀਂ ਕਰਦੀ। ਪੁਰਾਣਾ ਰੈਫਰੈਂਸ ਤੁਹਾਡੇ ਪ੍ਰੋਗਰਾਮ ਵਿੱਚ ਕਿਤੇ ਹੋਰ ਅਜੇ ਵੀ ਮੌਜੂਦ ਹੁੰਦਾ ਹੈ, ਜੋ ਅਜਿਹੇ ਡੇਟਾ ਵੱਲ ਇਸ਼ਾਰਾ ਕਰ ਰਿਹਾ ਹੁੰਦਾ ਹੈ ਜੋ ਹੁਣ ਮੌਜੂਦ ਨਹੀਂ ਹੈ। ਇਹ ਕੋਈ ਕ੍ਰੈਸ਼ (crash) ਨਹੀਂ ਹੈ। ਇਹ ਇਸ ਤੋਂ ਵੀ ਮਾੜੀ ਚੀਜ਼ ਹੈ: ਤੁਹਾਡੇ ਕੋਡਬੇਸ ਦੇ ਦੋ ਹਿੱਸਿਆਂ ਵਿਚਕਾਰ ਇੱਕ ਚੁੱਪਚਾਪ ਵੱਖ ਹੋਣਾ, ਜਿੱਥੇ ਦੋਵੇਂ ਹੀ ਸੋਚਦੇ ਹਨ ਕਿ ਸੱਚਾਈ ਉਹਨਾਂ ਕੋਲ ਹੈ।

ਇਸ ਤੋਂ ਬਚਣ ਲਈ ਜੋ ਅਨੁਸ਼ਾਸਨ ਵਰਤਿਆ ਜਾਂਦਾ ਹੈ, ਉਸਨੂੰ Hard Object References ਕਿਹਾ ਜਾਂਦਾ ਹੈ। ਇਹ ਕੋਈ ਲਾਇਬ੍ਰੇਰੀ ਜਾਂ ਕੰਪਾਈਲਰ ਫੀਚਰ ਨਹੀਂ ਹੈ। ਇਹ ਇੱਕ ਇਕਰਾਰਨਾਮਾ (contract) ਹੈ ਜਿਸ ਨੂੰ ਤੁਸੀਂ ਆਪਣੇ ਪੂਰੇ ਕੋਡ ਵਿੱਚ ਲਾਗੂ ਕਰਦੇ ਹੋ।

Stale Alias ਦੀ ਸਮੱਸਿਆ

ਇੱਕ stale alias ਉਦੋਂ ਹੁੰਦਾ ਹੈ ਜਦੋਂ ਇੱਕ ਮੋਡਿਊਲ ਕਿਸੇ ਆਬਜੈਕਟ ਦਾ ਰੈਫਰੈਂਸ ਰੱਖਦਾ ਹੈ ਜਦੋਂ ਕਿ ਦੂਜਾ ਮੋਡਿਊਲ ਉਸ ਆਬਜੈਕਟ ਨੂੰ ਇੱਕ ਨਵੇਂ ਆਬਜੈਕਟ ਨਾਲ ਬਦਲ ਦਿੰਦਾ ਹੈ। ਪਹਿਲਾ ਰੈਫਰੈਂਸ ਅਜੇ ਵੀ ਵੈਧ (valid) ਕੋਡ ਹੈ, ਪਰ ਇਹ ਹੁਣ ਮੌਜੂਦਾ ਡੇਟਾ ਵੱਲ ਇਸ਼ਾਰਾ ਨਹੀਂ ਕਰਦਾ।

ਇੱਕ ਆਮ ਵੈੱਬ ਐਪਲੀਕੇਸ਼ਨ ਵਿੱਚ ਯੂਜ਼ਰ ਰਿਕਾਰਡ ਦੀ ਕਲਪਨਾ ਕਰੋ:

const user = {
  name: "Alice",
  address: {
    city: "Seoul",
    country: "KR"
  }
};

ਇੱਕ ਸ਼ਿਪਿੰਗ ਕੰਪੋਨੈਂਟ ਸ਼ੁਰੂ ਵਿੱਚ ਹੀ ਪਤਾ (address) ਕੈਪਚਰ ਕਰ ਲੈਂਦਾ ਹੈ:

const shippingAddress = user.address;

ਬਾਅਦ ਵਿੱਚ, ਇੱਕ ਪ੍ਰੋਫਾਈਲ ਅੱਪਡੇਟ ਆਉਂਦਾ ਹੈ। ਇੱਕ reducer ਜਾਂ service handler ਪੂਰੇ ਆਬਜੈਕਟ ਨੂੰ ਬਦਲਣ ਦਾ ਫੈਸਲਾ ਕਰਦਾ ਹੈ:

user.address = { city: "Tokyo", country: "JP" };

ਇਸ ਸਮੇਂ 'ਤੇ, user.address ਟੋਕੀਓ (Tokyo) ਵੱਲ ਇਸ਼ਾਰਾ ਕਰਦਾ ਹੈ। ਪਰ shippingAddress ਅਜੇ ਵੀ ਸੀਓਲ (Seoul) ਵਿੱਚ ਪੁਰਾਣੇ ਆਬਜੈਕਟ ਵੱਲ ਇਸ਼ਾਰਾ ਕਰਦਾ ਹੈ। ਕੋਈ ਐਕਸੈਪਸ਼ਨ (exception) ਨਹੀਂ ਆਉਂਦੀ। TypeScript ਖੁਸ਼ ਹੈ ਕਿਉਂਕਿ ਟਾਈਪਸ (types) ਅਜੇ ਵੀ ਮੇਲ ਖਾਂਦੇ ਹਨ। UI ਪ੍ਰੋਫਾਈਲ ਪੇਜ 'ਤੇ ਅੱਪਡੇਟ ਕੀਤਾ ਸ਼ਹਿਰ ਦਿਖਾ ਸਕਦਾ ਹੈ ਜਦੋਂ ਕਿ ਸ਼ਿਪਿੰਗ ਲੇਬਲ ਚੁੱਪਚਾਪ ਪੁਰਾਣਾ ਸ਼ਹਿਰ ਪ੍ਰਿੰਟ ਕਰ ਦਿੰਦਾ ਹੈ। ਇਹ ਬੱਗ (bug) ਉਦੋਂ ਹੀ ਸਾਹਮਣੇ ਆਉਂਦਾ ਹੈ ਜਦੋਂ ਕੋਈ ਯੂਜ਼ਰ ਸ਼ਿਕਾਇਤ ਕਰਦਾ ਹੈ ਕਿ ਉਸਦਾ ਪੈਕੇਜ ਗਲਤ ਦੇਸ਼ ਵਿੱਚ ਚਲਾ ਗਿਆ ਹੈ।

ਇਹ ਇਸ ਲਈ ਹੁੰਦਾ ਹੈ ਕਿਉਂਕਿ JavaScript ਪਛਾਣ (identity) ਨੂੰ ਮੁੱਲ (value) ਤੋਂ ਵੱਖ ਕਰਦਾ ਹੈ। ਜਦੋਂ ਤੁਸੀਂ ਕਿਸੇ ਆਬਜੈਕਟ ਪ੍ਰਾਪਰਟੀ ਨੂੰ ਨਵੇਂ object literal ਨਾਲ ਬਦਲਦੇ ਹੋ, ਤਾਂ ਤੁਸੀਂ ਲੜੀ (chain) ਤੋੜ ਦਿੰਦੇ ਹੋ। ਪੁਰਾਣਾ ਆਬਜੈਕਟ ਖਤਮ ਨਹੀਂ ਹੁੰਦਾ; ਇਹ ਸਿਰਫ਼ ਅਨਾਥ (orphaned) ਹੋ ਜਾਂਦਾ ਹੈ। ਜਿਸ ਕੋਲ ਵੀ ਇਹ ਅਜੇ ਵੀ ਹੈ, ਉਹ ਇੱਕ ਭੂਤ (ghost) ਨਾਲ ਕੰਮ ਕਰ ਰਿਹਾ ਹੈ।

Hard Object References ਦਾ ਕੀ ਮਤਲਬ ਹੈ

ਨਿਯਮ ਸਧਾਰਨ ਹੈ: primitive values ਨੂੰ ਬਦਲੋ, ਪਰ ਕਦੇ ਵੀ object ਜਾਂ array ਰੈਫਰੈਂਸਾਂ ਨੂੰ ਨਾ ਬਦਲੋ। ਜਦੋਂ ਨਵਾਂ ਡੇਟਾ ਆਉਂਦਾ ਹੈ, ਤਾਂ ਕੰਟੇਨਰ ਨੂੰ ਬਦਲਣ ਦੀ ਬਜਾਏ ਉਸਨੂੰ ਮੌਜੂਦਾ ਕੰਟੇਨਰ ਵਿੱਚ ਕਾਪੀ ਕਰੋ।

ਇਸ ਲਈ ਤਿੰਨ ਖਾਸ ਆਦਤਾਂ ਦੀ ਲੋੜ ਹੈ।

ਪਹਿਲਾਂ, ਆਬਜੈਕਟਾਂ ਅਤੇ ਐਰੇ (arrays) ਨੂੰ const ਨਾਲ ਡਿਕਲੇਅਰ ਕਰੋ। ਇਹ ਟਾਪ-ਲੈਵਲ ਵੇਰੀਏਬਲ ਨੂੰ ਨਵੇਂ ਇੰਸਟੈਂਸ ਨਾਲ ਦੁਬਾਰਾ ਬੰਨ੍ਹਣ (rebind) ਦੇ ਲਾਲਚ ਨੂੰ ਖਤਮ ਕਰ ਦਿੰਦਾ ਹੈ। ਵੇਰੀਏਬਲ ਸਕੋਪ (scope) ਦੇ ਜੀਵਨ ਕਾਲ ਲਈ ਸਥਿਰ ਰਹਿਣਾ ਚਾਹੀਦਾ ਹੈ।

ਦੂਜਾ, ਕਦੇ ਵੀ ਅਜਿਹੀ ਪ੍ਰਾਪਰਟੀ ਨੂੰ ਨਵੇਂ ਬਣਾਏ ਗਏ ਆਬਜੈਕਟ ਨਾਲ ਨਾ ਬਦਲੋ ਜੋ ਕਿਸੇ ਆਬਜੈਕਟ ਜਾਂ ਐਰੇ ਨੂੰ ਰੱਖਦੀ ਹੈ। ਜੇਕਰ ਤੁਹਾਨੂੰ ਪਤਾ (address) ਅੱਪਡੇਟ ਕਰਨ ਦੀ ਲੋੜ ਹੈ, ਤਾਂ ਉਸਦੇ ਅੰਦਰ ਦੀਆਂ ਪ੍ਰਾਪਰਟੀਆਂ ਨੂੰ ਮਿਊਟੇਟ (mutate) ਕਰੋ।

ਤੀਜਾ, ਜੇਕਰ ਤੁਹਾਨੂੰ ਸਟੇਟ (state) ਨੂੰ ਸਾਫ਼ ਕਰਨ ਜਾਂ ਰੀਸੈੱਟ ਕਰਨ ਦੀ ਲੋੜ ਹੈ, ਤਾਂ ਨਵੇਂ ਖਾਲੀ ਆਬਜੈਕਟ ਜਾਂ ਐਰੇ ਲਈ ਇਸਨੂੰ ਸੁੱਟ

ਜੇਕਰ ਤੁਸੀਂ Redux ਜਾਂ ਇਸ ਤਰ੍ਹਾਂ ਦੀਆਂ immutable state libraries ਨਾਲ ਕੰਮ ਕੀਤਾ ਹੈ, ਤਾਂ ਇਹ ਮਾਡਲ ਸ਼ਾਇਦ ਉਲਟ ਲੱਗ ਸਕਦਾ ਹੈ। ਉਹਨਾਂ ਪ੍ਰਣਾਲੀਆਂ ਵਿੱਚ, ਬਦਲਾਅ ਦਾ ਸੰਕੇਤ ਇੱਕ ਨਵਾਂ ਆਬਜੈਕਟ ਬਣਾ ਕੇ ਦਿੱਤਾ ਜਾਂਦਾ ਹੈ। ਰੈਫਰੈਂਸ ਵਿੱਚ ਬਦਲਾਅ ਹੀ ਸੰਕੇਤ ਹੁੰਦਾ ਹੈ। ਕੰਪੋਨੈਂਟਸ ਇਹ ਜਾਣਨ ਲਈ ਕਿ ਕੀ re-render ਕਰਨਾ ਹੈ, prevProps.data === nextProps.data ਦੀ ਤੁਲਨਾ ਕਰਦੇ ਹਨ।

Hard Object References ਲਈ ਤੁਹਾਨੂੰ ਉਸ ਅਨੁਮਾਨ ਨੂੰ ਬਦਲਣ ਦੀ ਲੋੜ ਹੁੰਦੀ ਹੈ। ਕਿਉਂਕਿ ਰੈਫਰੈਂਸ ਸਥਿਰ ਰਹਿੰਦਾ ਹੈ, ਰੈਫਰੈਂਸ ਦੀ ਸਮਾਨਤਾ (reference equality) ਤੁਹਾਨੂੰ ਇਹ ਨਹੀਂ ਦੱਸਦੀ ਕਿ ਡੇਟਾ ਬਦਲਿਆ ਹੈ ਜਾਂ ਨਹੀਂ। ਤੁਹਾਨੂੰ ਅਪਡੇਟਸ ਨੂੰ ਪ੍ਰਸਾਰਿਤ ਕਰਨ ਲਈ ਇੱਕ ਵੱਖਰੇ ਤਰੀਕੇ ਦੀ ਲੋੜ ਹੈ।

ਅਭਿਆਸ ਵਿੱਚ, ਇਸਦਾ ਮਤਲਬ ਹੈ reactivity systems, explicit observers, ਜਾਂ dirty flags 'ਤੇ ਨਿਰਭਰ ਕਰਨਾ। user.address.city ਨੂੰ mutate ਕਰਨ ਨਾਲ ਇੱਕ setter ਟ੍ਰਿਗਰ ਹੋ ਸਕਦਾ ਹੈ ਜੋ subscribers ਨੂੰ ਸੂਚਿਤ ਕਰਦਾ ਹੈ। ਇੱਕ ਆਬਜੈਕਟ event bus ਰਾਹੀਂ ਇੱਕ change event ਜਾਰੀ ਕਰ ਸਕਦਾ ਹੈ। ਇੱਕ game loop ਜਾਂ canvas tool ਇੱਕ global dirty flag ਸੈੱਟ ਕਰ ਸਕਦਾ ਹੈ ਅਤੇ ਫਰੇਮ ਦੇ ਅੰਤ ਵਿੱਚ ਗ੍ਰਾਫ ਨੂੰ ਦੁਬਾਰਾ ਸਕੈਨ ਕਰ ਸਕਦਾ ਹੈ। ਰੈਫਰੈਂਸ ਸਥਿਰ ਹੈ, ਇਸ ਲਈ ਤੁਹਾਨੂੰ ਹੋਰ ਵਿਧੀਆਂ ਰਾਹੀਂ data flow ਨੂੰ ਦਿਖਾਈ ਦੇਣ ਯੋਗ ਬਣਾਉਣਾ ਪਵੇਗਾ।

ਇਹ ਆਰਕੀਟੈਕਚਰਲ ਤਬਦੀਲੀ ਹੀ ਕਾਰਨ ਹੈ ਕਿ ਇਹ ਪਹੁੰਚ ਗੁੰਝਲਦਾਰ frontend state, ਵੱਡੇ component-local state, visual editors, canvas tools, ਅਤੇ runtime controllers ਵਿੱਚ ਸਭ ਤੋਂ ਵਧੀਆ ਫਿੱਟ ਹੁੰਦੀ ਹੈ। ਇਹ ਪ੍ਰਣਾਲੀਆਂ ਪਹਿਲਾਂ ਹੀ granular updates, direct mutations, ਜਾਂ imperative APIs 'ਤੇ ਨਿਰਭਰ ਕਰਦੀਆਂ ਹਨ। ਇਸ ਦੇ ਉੱਪਰ immutability ਨੂੰ ਲਾਗੂ ਕਰਨ ਨਾਲ ਅਕਸਰ ਬਿਨਾਂ ਕਿਸੇ ਵੱਧ ਸਪੱਸ਼ਟਤਾ ਦੇ, ਬਹੁਤ ਜ਼ਿਆਦਾ allocation pressure ਅਤੇ reference churn ਪੈਦਾ ਹੁੰਦਾ ਹੈ। ਜਦੋਂ ਹਰ ਫਰੇਮ ਮਹੱਤਵਪੂਰਨ ਹੁੰਦਾ ਹੈ, ਤਾਂ ਸਿਰਫ਼ ਇੱਕ slider ਨੂੰ ਹਿਲਾਉਣ ਲਈ ਇੱਕ ਨਵਾਂ object graph allocate ਕਰਨਾ ਬੇਕਾਰ ਹੈ। ਰੈਫਰੈਂਸ ਨੂੰ hard ਰੱਖਣਾ ਅਤੇ ਅੰਦਰੂਨੀ ਹਿੱਸੇ ਨੂੰ mutate ਕਰਨਾ ਸਮੱਸਿਆ ਦੇ ਅਸਲ ਮਕੈਨਿਕਸ ਨਾਲ ਮੇਲ ਖਾਂਦਾ ਹੈ।

ਇਸ ਨੂੰ ਪ੍ਰਭਾਵਸ਼ਾਲੀ ਬਣਾਉਣਾ

ਇਸ ਨਿਯਮ ਦੇ ਅਣਗੌਲੇ ਕੀਤੇ ਗਏ ਫਾਇਦਿਆਂ ਵਿੱਚੋਂ ਇੱਕ ਹੈ