深浅拷贝
深浅拷贝的含义:
通常是指将一个 引用数据类型, 拷贝到另外一个变量中,但是根据拷贝方法的不同,展示出来的效果也有差异
浅拷贝:
将一份数据拷贝到另一个变量中,修改 第一层 数据是 不会 相互影响,但是修改 第二层数据时 会 相互影响
注意:将 浅拷贝 与 赋值 区分开
例:
let obj = {
name:'秦霄贤',
age:'24',
info:{
width:120,
height:180
}
}
let obj2 = obj
obj2.name = '彭于晏'
obj2.age = 41
console.log(obj)
console.log(obj2)
let obj = {
name:'秦霄贤',
age:'24',
info:{
width:120,
height:180
}
}
let newObj = {}
for(let key in obj){
newObj[key] = obj[key]
}
newObj.name = '彭于晏'
newObj.age = 41
console.log(obj)
console.log(newObj)
深拷贝:
将一份数据拷贝到另一个变量中,不管修改哪一层数据,两个对象之间都不会相互影响
在日常工作中使用快捷语法: deepClone(target,origin)
例:
let obj = {
name:'秦霄贤',
age:'24',
info:{
width:120,
height:180
},
arr:[1, 2, 3, 4]
}
let newObj = {}
function fn(newObj,obj){
for(let key in obj){
if(Object.prototype.toString.call(obj[key]) === 'Object Object'){
newObj[key] === {}
fn(newObj[key],obj[key])
}else if(Object.prototype.toString.call(obj[key]) === 'Object Array'){
newObj[key] === []
fn(newObj[key],obj[key])
}else{
newObj[key] === obj[key]
}
}
}
const n1 = fn(newObj,obj)
newObj.name = '彭于晏'
newObj.age = 41
newObj.info.width = 140
newObj.info.height = 183
console.log(obj)
console.log(newObj)
永不销毁的执行空间
函数的定义与调用:
1.定义
=> 在堆内存开一个空间
=> 将函数的函数体内的代码 保存在堆内存中
=> 将堆内存的地址保存在变量名中(函数名), 最后将存储到栈内存内
2.调用
=> 根据变量名(函数名)中的地址,找到对应的函数
=> 然后再调用栈中开一个新的空间(函数的执行空间)
=> 在执行空间中,对函数的形参进行赋值
=> 在执行空间中,进行变量的预解析
=> 在执行空间中,执行函数代码
=> 销毁当前函数的执行空间
永不销毁的执行空间:
1.正常书写一个函数
2.在这函数内 向外返回一个 引用数据类型
3.当满足上述条件时,这个函数的执行空间将不会被销毁
例:
function fn () {
let obj = {
name:'彭于晏',
age:41
}
return obj
}
const newObj = fn()
console.log(newObj)
// 可以利用 newObj = null 销毁空间
闭包
闭包是指有权访问外层函数作用域中变量的函数
创建闭包的最常见的方式就是在一个函数内创建一个内层函数,通过内层函数访问外层函数的局部变量
闭包的特性:
=> 函数内再嵌套函数
=> 内部函数可以 引用 外层函数的 参数 和 变量
=> 函数的执行空间不会被销毁
闭包的优点:
可以避免全局变量的污染
闭包的缺点:
闭包会常驻内存,会增大内存的使用量,使用不当很容易造成内存泄漏
闭包最大的用处:
=> 可以读取函数内部的变量
=> 函数内部的变量始终保持在内存中
闭包使用时的注意点:
由于闭包会使函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,可能导致内存泄漏
解决方法: 在退出函数之前,将不适用的局部变量全部删除
例:
function fn(){
let a = 20;
let b = 50;
let obj = {
name:'彭于晏',
age:41
}
function fn2 () {
return obj
}
return fn2
}
const newFn = fn()
comnsole.log(newFn)
const f2 = newFn()
console.log(f2)
沙箱模式
条件:
=> 利用了函数内 "间接" 的返回了一个函数
=> 外部函数 返回了一个对象, 这个对象内书写多个函数
例:
function outer(){
let a = 0;
let b = 999;
const obj = {
getA(){
return a
},
setA(val){
a = val
},
getB(){
return b
},
setB(val){
b = val
}
}
return obj
}
const res = outr()
res.setA(23)
console.log(res.getA())
沙箱模式语法糖
语法糖: 在不影响功能的情况下,给我们提供了一些更简单的方法(其实就是利用了 getter 和 setter 帮助我们简化了一些操作和代码)
例:
function outer () {
let a = 1;
return {
get a () {
return a
},
set a (val) {
a = val
}
}
}
const res = outer()
console.log(res.a)
res.a = 999
console.log(res.a)
console.log(res.a + 1)
函数的柯里化
柯里化函数:
一个函数接收多个参数能够完成功能,柯里化函数就是将这一个函数拆分为两个函数,每个函数都只接收一个参数,然后完成的功能相同
实例:
function fn (fnReg) {
return function (fnStr) {
return fnReg.test(fnStr)
}
}
const num = fn(/^\d\w{6,12}$/)
console.log(num('12sad56fds'))
函数的柯里化封装
函数柯里化内
外层函数: 收集参数
内层函数: 负责处理功能
curry 函数需要接收两个参数
callback: 当参数传递足够时需要执行的函数
...arg: 接收后续这个参数传递所有实参(以数组的形式存储)
例:
功能:拼接地址栏字符串
地址栏:
传输协议:http https
域名: 127.0.0.1 localhost
端口名: 0~65535 7777 8080 8081
地址:/a /a/b.html /index.html
function fn(a, b, c, d){
return a + '://' + b + ':' + c + d
}
function curry(callback, ...arg) {
return function(...arg){
_arg = [...arg, ..._arg]
if(_arg.length === callback.length){
return callback(..._arg)
}else{
return curry(callback, ..._arg)
}
}
}
const newFn = curry(fn)
const newFn2 = newFn('https')
const newFn3 = newFn2('127.0.0.1')
const newFn4 = newFn3('7777')
const newFn5 = newFn4('/index.html')
console.log(newFn5)