您好,登錄后才能下訂單哦!
React學習與開發過程要經歷一個相當長的準備階段,此前看阮一峰老師的文章中,他就特別提到這一點。但是,由于React框架或者說是一種優秀的前端架構實在太誘人,所以,掌握這項技術所涉及的技術棧過程中經歷的任何苦惱都是值得的。在還沒有全面掌握這項技術的不斷探索過程中,如果包括后端的一部分在內(例如Node.js和Express等,還有一些數據庫及API知識),至少要有幾十部分,僅限于核心的算起來也有十多項吧。
作為一個基礎部分,ES6勢在必學。此前,我曾得意于自己已經掌握了一定程度的JS知識,但是在匆讀阮老師的《ES6標準入門》一書后才感覺自己落后許多了。同時,在閱讀本書的過程中,也發現:這本書或者整個ES6,的確是為著眼于將來的“一統前后端”的大項目作準備的,因此,重復地專門學習這個語言是沒有必要的。這是一本案頭書,需要什么時再讀什么更合適。
本文羅列的就是在本人在學習Redux過程中在遭遇到JS的深淺拷貝過程中總結的相關內容。太匆忙與粗略,僅供同學們參考。
結論:JavaScript中變量的賦值分為「傳值」與「傳址」。
基本數據類型的賦值,就是「傳值」;而引用類型變量賦值,實際上是「傳址」。
基本數據類型變量的賦值、比較,只是值的賦值和比較,也即棧內存中的數據的拷貝和比較,參見如下代碼:
var num1 = 123;
var num2 = 123;
var num3 = num1;
num1 === num2; // true
num1 === num3; // true
num1 = 456;
num1 === num2; // false
num1 === num3; // false
引用數據類型變量的賦值、比較,只是存于棧內存中的堆內存地址的拷貝、比較,參加如下代碼:
var arr1 = [1, 2, 3];
var arr2 = [1, 2, 3];
var arr3 = arr1;
arr1 === arr2; // false
arr1 === arr3; // true
arr1 = [1, 2, 3];
arr1 === arr2; // false
arr1 === arr3; // false
JavaScript中的拷貝區分為「淺拷貝」與「深拷貝」。
淺拷貝只會將對象的各個屬性進行依次復制,并不會進行遞歸復制,也就是說只會進行賦值目標對象的第一層屬性。
對于目標對象第一層為基本數據類型的數據,就是直接賦值,即「傳值」;而對于目標對象第一層為引用數據類型的數據,就是直接賦存于棧內存中的堆內存地址,即「傳址」。
深拷貝不同于淺拷貝,它不但拷貝目標對象的第一層屬性,而且還遞歸拷貝目標對象的所有屬性。
一般來說,在JavaScript中考慮復合類型的深層復制的時候,往往就是指對于 Date 、Object 與 Array 這三個復合類型的處理。我們能想到的最常用的方法就是先創建一個空的新對象,然后遞歸遍歷舊對象,直到發現基礎類型的子節點才賦予到新對象對應的位置。
不過這種方法會存在一個問題,就是 JavaScript 中存在著神奇的原型機制,并且這個原型會在遍歷的時候出現,然后需要考慮原型應不應該被賦予給新對象。那么在遍歷的過程中,我們可以考慮使用 hasOwnProperty 方法來判斷是否過濾掉那些繼承自原型鏈上的屬性。
Object.assign 方法可以把 任意多個的源對象所擁有的自身可枚舉屬性 拷貝給目標對象,然后返回目標對象。
注意:
對于訪問器屬性,該方法會執行那個訪問器屬性的 getter 函數,然后把得到的值拷貝給目標對象,如果你想拷貝訪問器屬性本身,請使用 Object.getOwnPropertyDescriptor() 和 Object.defineProperties() 方法;
字符串類型和 symbol 類型的屬性都會被拷貝;
在屬性拷貝過程中可能會產生異常,比如目標對象的某個只讀屬性和源對象的某個屬性同名,這時該方法會拋出一個 TypeError 異常,拷貝過程中斷,已經拷貝成功的屬性不會受到影響,還未拷貝的屬性將不會再被拷貝;
該方法會跳過那些值為 null 或 undefined 的源對象;
var dest = JSON.parse(JSON.stringify(target));
同樣的它也有缺點:
該方法會忽略掉值為 undefined 的屬性以及函數表達式,但不會忽略值為 null 的屬性。
在Redux開發中的一個應用是借助于Lodash 的 merge 方法可以實現深拷貝,達到管理范式化數據的目的,示例代碼如下:
import merge from "lodash/object/merge";
function commentsById(state = {}, action) {
switch(action.type) {
default : {
if(action.entities && action.entities.comments) {
return merge({}, state, action.entities.comments.byId);
}
return state;
}
}
}
實際上,即使我們知道了如何在各種情況下進行深拷貝,我們也仍然面臨一些問題: 深拷貝實際上是很消耗性能的。(我們可能只是希望改變新數組里的其中一個元素的時候不影響原數組,但卻被迫要把整個原數組都拷貝一遍,這不是一種浪費嗎?)所以,當你的項目里有大量深拷貝需求的時候,性能就可能形成了一個制約的瓶頸了。
immutable的作用是通過immutable引入的一套API,實現:
1.在改變新的數組(對象)的時候,不改變原數組(對象)
2.在大量深拷貝操作中顯著地減少性能消耗
參考代碼:
const { Map } = require('immutable')
const map1 = Map({ a: 1, b: 2, c: 3 })
const map2 = map1.set('b', 50)
map1.get('b') // 2
map2.get('b') // 50
在React+Redux開發中,經常要遇到不可變數據的更新問題。復雜情形中,往往需要復制嵌套數據的所有層級。但不幸的是,正確地使用不變的更新去深度嵌套狀態的過程很容易變得冗長難讀。 更新 ate.first.second[someId].fourth 的示例(http://www.redux.org.cn/docs/recipes/reducers/ImmutableUpdatePatterns.html)大概如下所示:
function updateVeryNestedField(state, action) {
return {
....state,
first : {
...state.first,
second : {
...state.first.second,
[action.someId] : {
...state.first.second[action.someId],
fourth : action.someValue
}
}
}
}
}
顯然,每一層嵌套使得閱讀更加困難,并給了更多犯錯的機會。這是其中一個原因,鼓勵你保持狀態扁平,盡可能構建小巧而靈活的Reducer。
1,https://juejin.im/post/5acc7e606fb9a028c67609f7
2,https://zhuanlan.zhihu.com/p/28508795
3,http://www.zsoltnagy.eu/cloning-objects-in-javascript/
4,http://www.cnblogs.com/penghuwan/p/7359026.html
5,https://blog.csdn.net/github_38524608/article/details/78812761
6,https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/Spread_syntax
7,http://www.redux.org.cn/docs/recipes/reducers/UpdatingNormalizedData.html
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。