操作字符、对象方法, 深浅拷贝

741 阅读6分钟

        在一个项目中,我们通常会通过例如substring,slice,concat等一些方法来操作字符,数组,对象来获取我们想要的结果

深浅拷贝

         首先我觉得,所有的操作应该对深浅拷贝有一个认识,因为有时候我们需要利用浅拷贝的特性来达到一些功能效果,更多的时候我们需要深拷贝来复制对象和数组,在不影响原有数据的基础上来对数据进行一些操作。

  • 浅拷贝
        如果是基本元素,就会拷贝一份,互不影响             
        如果是对象或者数组,就只会拷贝对象和数组的引用,无论是对新还是旧数组或对象操作,两者都会发生变化
  • 深拷贝
        完全拷贝了一个对象,即使嵌套了对象,两者也相互分离,修改一个对象的属性,也不会影响另一个

  • 图示

        对于引用数据类型,名存在栈内存中,值存在于堆内存中,但是栈内存会提供一个引用的地址指向堆内存中的值


对于数组和对象的一些拷贝方法(复制,合并,截取)

深拷贝的方法:

1、JSON.parse(JSON.stringify(obj))

 浅拷贝的一些方法:
         对一级属性没有影响的,但对二级以及更深层次的拷贝会有影响:         

1、arr.concat() // 合并多个数组    
2、[...arr1, ...arr2] // ES6新增延展操作符,合并多个数组
3、arr.slice() // 截取数组中的一部分,不破坏原数组,返回新数组
4、Object.assign(target, ...sources) 

对于String的操作( [ ] 表示可取到 )

1、string.substring([startIndex], endIndex)  // 截取字符
2、string.slice([startIndex], endIndex)  // 截取字符
2、string.charAt(index) // 返回指定位置的字符

对于数组的操作 

1、arr.push()  // 添加至数组的末尾,并返回修改后的数组的长度
2、arr.unshift()  // 在数组的开始添加任意个新元素,并返回修改后的数组长度
3、arr.splice() // 删除指定位置指定个数的元素,并返回

数组与字符之间的转换

1、arr.join()   // 数组转为以特定符号分割的字符,默认以逗号分割
2、string.split(separator, howmany)  // 把一个字符串分割乘字符串数组
3、arr.toString()  //把数组转换为字符串,并返回结果,每一项以逗号分割


以上是对一些常用的方法的一个总结,以下是各个函数的用法以及例子

JSON.parse(JSON.stringify(obj))  

  • 深拷贝

var arr = [    
    { name: "test" },    
    { title: "flag" },    
    "string",   
    2
]
var deepClone = (obj) => {    
    return JSON.parse(JSON.stringify(obj))
}
var deepCopyArr = deepClone(arr)
deepCopyArr[0].name = 'test1'
console.log('deepCopyArr', deepCopyArr)   
console.log('arr', arr)

// deepCopyArr [{ name: 'test1' }, { title: 'flag' }, 'string', 2]
// arr [{ name: 'test' }, { title: 'flag' }, 'string', 2]

局限性:1、不能解决循环引用的对象; 2、 会忽略undefined;3、会忽略symbol;4、不能序列化函数

arr.concat(array1,  array2, ....,  array3)  

  • 浅拷贝(复制数据的更改对于原数据只影响二级以上的属性)
  • 数组的合并

Tip:  参数可以是具体的值,也可以是数组对象

// 浅拷贝
var arr = [1, 2, 3]
var concatArrconcatArr = arr.concat()
console.log('concatArr', concatArr)  // [1, 2, 3]
console.log('arr', arr)  // [1, 2, 3]

// 复制对象若更改,对于原数据的一级属性没有影响,对二级以上的属性有影响
var arr = [    
    { name: "test" },    
    { title: "flag" },    
    "string",  
    2
]
concatArr = arr.concat()
concatArr[0].name = "test2"
concatArr[3] = 10
console.log('concatArr', concatArr)
console.log('arr', arr)

// concatArr2 [ { name: 'test2' }, { title: 'flag' }, 'string', 10 ]
// arr [ { name: 'test2' }, { title: 'flag' }, 'string', 2 ]

// 连接两个或多个数组
var arr = [1, 2, 3]
var concatArr = arr.concat('test')  // 连接具体的值
console.log('concatArr', concatArr)  // [1, 2, 3, 'test']

var concatArr2 = arr2.concat([4, 5, 6])  // 连接数组
console.log('concatArr2', concatArr2)   // [1, 2, 3, 4, 5, 6]
console.log('arr2', arr2)  // [1, 2, 3]  // 原数组未被破坏

[...arr1, ...arr2] ES6新增延展操作符

  • 浅拷贝(复制数据的更改对于原数据只影响二级以上的属性)
  • 数据的合并(数组,对象,基本类型)

var arr = [    
    { name: "test" },   
    { title: "flag" },    
    "string",    
    2
]
var arr2 = [3, 4, 5]
var arr3 = [...arr, ...arr2]
arr3[0].name = "test2"
arr3[2] = 6

// arr [{ name: 'test2' }, { title: 'flag' }, 'string', 2]
// arr2 [3, 4, 5]
// arr3 [{ name: 'test2' }, { title: 'flag' }, 6, 2, 3, 4, 5]

arr.slice(start, end) / string.slice(start, end)

  • 浅拷贝
  • 数组截取,从start处开始选取(可为负数,代表从尾部开始算起),从end处结束选取(不包含, 可为负数),未指定,则到末尾

// 浅拷贝
var arr = [    
    { name: "test" },   
    { title: "flag" },   
    "string",    
    2
]

var arr1 = arr.slice()  // [{ name: 'test' }, { title: 'flag' }, 'string', 2]

// 复制对象若更改,对于原数据的一级属性没有影响,对二级以上的属性有影响

arr1[0].name = 'test2'

// arr [{ name: 'test2' }, { title: 'flag' }, 'string', 2]
// arr1 [{ name: 'test2' }, { title: 'flag' }, 'string', 2]

// 截取, 不破坏原数组,返回新数组
var arr1 = [3, 4, 5]
var arr2 = arr2.slice(0, 1)  // [3]
var arr3 = arr2.slice(0, -1) // [3, 4]
var arr4 = arr2.slice(1)  // [4, 5]

Object.assign(target, ...source)

  • 将所有可枚举属性的值从一个或多个源对象复制到目标对象,返回目标对象
  • target, 目标对象; source,原对象
  • 浅拷贝 (复制数据的更改对于原数据只影响二级以上的属性)
  • 合并对象 (相同属性,则后续参数覆盖原有的)

// 复制一个对象
var object = {    
    a: 1,    
    b: 2,    
    c: 3,    
    d: {        
        child: 4    
    }
}
var object2 = Object.assign({}, object)

// object2 {a: 1, b: 2, c: 3, d: { child: 4 }}

// 复制对象若更改,对于原数据的一级属性没有影响,对二级以上的属性有影响
object2.a = 'test'
object2.d.child = 'test2'

// object2 {a: 'test', b: 2, c: 3, d: { child: 'test2' }}
// object {a: 1, b: 2, c: 3, d: { child: 'test2' }}
// 合并对象
var o1 = {a: 1, b: 2, c: 1}
var o2 = {b: 3, c: 4}
var obj = Object.assign({}, o1, o2)   // { a: 1, b: 3, c: 4 }

string.substring(start, end) string.slice(start, end)

  • start(非负整数)要提取的字串的第一个字符的位置,end(非负整数)结束字符位置(不包含)

string.charAt(index)

  • index 指定位置的字符

string = 'test'
var string2 = string.substring(1, 3)  // 'es'
var string3 = string.slice(1, 3)  // 'es'
var string4 = string.charAt(1)  // 'e'

arr.push() 在末尾添加元素 

arr.unshift() 在开始添加元素  

arr.splice(index, howmany, item1,....,itemX)  

  • 向/从数组中添加/删除项目,然后返回被删除的项目
  • index 规定添加/删除项目的位置,负数可从数组结尾处规定位置; howmay 要删除的项目数量,设置为0,则不会删除,item1,...,itemX 可向数组添加的新项目
  • 以上操作都是在原数组上操作,所以如果不想破坏原数据的话,可以对原数据进行深拷贝

var arr = [3, 4, 5]
arr.push(6)   // [3, 4, 5, 6]
arr.unshift(2) // [2, 3, 4, 5, 6]
arr.splice(1, 1) // [2, 4, 5, 6]
arr.splice(1, 0, 'test') // [2, 'test', 4, 5, 6]

arr.join(separator)  

  • 把数组中的所有元素通过指定的分隔符放入一个字符串
  • separator 指定要使用的分隔符。如果省略,使用逗号作为分隔

var arr = [3, 4, 5]
var arr1 = arr.join()  // 3, 4, 5
var arr2 = arr.join('/')  // 3/4/5

arr.toString()

var arr3 = arr.toString()  // 3, 4, 5

string.split(separator, howmany) 

  • 用于把一个字符串分割成字符串数组
  • separator 字符串或正则表达式,从该参数指定的地方分割
  • howmany 若指定,指定返回数组的最大长度

var str = "how are you doing today"
var arr1 = str.split(" ")   // ['how', 'are', 'you', 'doing', 'today']
var arr2 = str.split(" ", 3)  // ['how', 'are', 'you']