[深刻01] 執行上下文
[深刻02] 原型鏈
[深刻03] 繼承
[深刻04] 事件循環
[深刻05] 柯里化 偏函數 函數記憶
[深刻06] 隱式轉換 和 運算符
[深刻07] 瀏覽器緩存機制(http緩存機制)
[深刻08] 前端安全
[深刻09] 深淺拷貝
[深刻10] Debounce Throttle
[深刻11] 前端路由
[深刻12] 前端模塊化
[深刻13] 觀察者模式 發佈訂閱模式 雙向數據綁定
[深刻14] canvas
[深刻15] webSocket
[深刻16] webpack
[深刻17] http 和 https
[深刻18] CSS-interview
[react] Hooks前端
[部署01] Nginx
[部署02] Docker 部署vue項目
[部署03] gitlab-CIvue
[源碼-webpack01-前置知識] AST抽象語法樹
[源碼-webpack02-前置知識] Tapable
[源碼-webpack03] 手寫webpack - compiler簡單編譯流程react
引用類型和原始類型的案例
var a = 1 // 基本類型的數據
var b = {name: 'woow_wu7'} // 引用類型的數據
var aa = a // a 和 aa 是不一樣的數據
var bb = b // b 和 bb 指向堆中的同一份數據,修改堆中數據,b和bb的指向沒變,則引用的值也會跟着改變
a = 2
b.name = 'wang'
console.log(a, aa, 'a和aa是不一樣的數據') // 改變後不等
console.log(b.name, bb.name, 'b和bb兩個變量中的指針 => 都同時指向了同一個堆內存中的數據') // 改變後相等
console.log(b === bb) // true,說明兩個變量指向了同一個堆內存
複製代碼
字符串-值
對應值-值
對應Map.prototype.set(key, value) // key能夠是任意類型
Map.prototype.get(key)
Map.prototype.has(key) // 返回布爾值
Map.prototype.delete(key) // 刪除某個鍵,但返回布爾值,表示是否刪除成功
Map.prototype.clear() // 清除全部成員,沒有返回值
Map.prototype.keys() values() entries() forEach()
const mapArrKey = [1,2];
const mapKeyAddress = ['chongqign']
const mapInstance = new Map([
['name', 'woow_wu'],
[[1,2], 20],
[mapArrKey, 20],
[{age: 20}, {age: 20}],
])
console.log(mapInstance, 'mapInstance')
console.log(mapInstance.size, 'size') // 4
console.log(mapInstance.get(mapArrKey), 'Map.prototype.get(key) => key是一個數組')
console.log(mapInstance.get([1,2]), 'Map.prototype.get(key)') // undefined 必須是同一個數組
mapInstance.set(mapKeyAddress, '地址')
console.log(mapInstance.get(mapKeyAddress))
console.log(mapInstance.has(mapKeyAddress), 'Map.prototype.has(key) => key是否存在,布爾值') // true
console.log(mapInstance.delete(mapKeyAddress), 'Map.prototype.delete(key) => 刪除鍵,返回布爾值,表示是否刪除成功') // true
console.log(mapInstance.get(mapKeyAddress)) // undefined
console.log(mapInstance.clear(), 'Map.prototype.clear() => 刪除全部鍵,沒有返回值')
console.log(mapInstance)
複製代碼
Reflect.get(target, name, receiver)
Reflect.set(target, name, value, receiver)
Reflect.deleteProperty(obj, name)
Reflect.constructor(target, args)
Reflect.getPrototypeOf(obj)
Reflect.setProrotypeOf(obj, prototypeObj)
Reflect.apply(func, thisArg, args)
返回對象參數的全部屬性,注意:包括Symbol類型的屬性
等同於Object.getOwnPropertyNames與Object.getOwnPropertySymbols之和
三元運算符是右結合:即從右向左算,先算右邊的三元表達式,再算左邊的三元表達式
三元運算符右結合
let name = null
1 === true ? name = 'wang' : 1 < 0 ? name = 'zhang' : name = 'woow_wu7';
//至關於:1 === true ? name = 'wang' : (1 < 0 ? name = 'zhang' : name = 'woow_wu7')
console.log(name, 'name')
// 'woow_wu7'
// 1 === true // false,類型不同都是false
複製代碼
typeof
- 返回值有(7種):number,string,boolean,undefined,symbol,function,object
- 基礎數據類型(6種):number,string,boolean,undefined,symbol,null
typeof NaN ---------------------- 'number'
typeof Symbol() ----------------- 'symbol'
typeof function(){} ------------- 'function'
typeof [] ---------------------- 'object'
typeof {} ---------------------- 'object'
複製代碼
即拷貝的是值,互不干擾
)即拷貝的是指針,相互干擾
)之因此不易區分淺拷貝和賦值,是由於拷貝後通常都伴隨者賦值webpack
一句話總結: (1)賦值不會開創新的堆內存空間,而淺拷貝會開創新的堆內存空間; |
賦值和淺拷貝的區別
var a = {
name: 'woow_wu',
score: {
ch: 90,
en: 80
}
};
var b = a
var c = {...a}
console.log(a===b, '賦值 => 不會開創新的堆空間,修改相互影響') // true,說明是同一份堆數據
console.log(a===c, '淺拷貝 => 會開創新的堆空間,修改原始值屬性互不干擾,修改引用值屬性,相互影響') // false,不一樣堆數據
a.name = 'wang'
console.log(b, 'b') // 相互影響
console.log(c, 'c => 淺拷貝,修改屬性值爲基本類型 => 互不干擾') // 互不干擾
a.score.en = 100
console.log(c, 'c => 淺拷貝,修改屬性值爲引用類型 => 相互影響') // 相互影響
複製代碼
// 不傳參
const objComplex = {
name: 'woow_wu7',
address: {
city: 'chongqing',
district: 'yubei',
town: 'jiazhou',
detail: ['chongqing', 'yubei', 'jiazhou']
},
arr: [1,2, {l:20, r: 30}],
fn: function(){}, // Function
date: new Date(), // Date
err: new Error(), // Error
reg: new RegExp(), // RegExp
number: 1,
string: '',
boolean: true,
null: null,
undefined: undefined,
symbol: Symbol('symbol'), // Symbol
}
const copy = JSON.parse(JSON.stringify(objComplex))
console.log(objComplex, 'objComplex')
console.log(copy, 'copy')
以下圖:
JSON.parse(JSON.stringify()) 不能拷貝function,Date,Error,RegExp,等對象
複製代碼
const objComplex = {
name: 'woow_wu7',
address: {
city: 'chongqing',
district: 'yubei',
town: 'jiazhou',
detail: ['chongqing', 'yubei', 'jiazhou']
},
score: [100, 200]
}
function deepClone(parameter) {
const parameterType = Object.prototype.toString.call(parameter).slice(9, -1)
// 獲取類型字符串
// Array.prototype.slice(9, -1) 從第9個字符開始截取,直到倒數第2個值
const cloneObj = null
// 參數是數組,賦值[]
// 參數是對象,賦值{}
// 其餘類型:直接返回
if (parameterType === 'Array') {
cloneObj = []
}
else if (parameterType === 'Object') {
cloneObj = {}
}
else {
return parameter
}
for(let key in parameter) {
if (parameter.hasOwnProperty(key)) {
// 是不是自身屬性
if (typeof parameter[key] === 'object') {
// 對象或數組,繼續判斷
cloneObj[key] = deepClone(parameter[key])
} else {
cloneObj[key] =parameter[key]
}
}
}
return cloneObj
}
const res = deepClone(objComplex)
console.log(res, 'res')
複製代碼
----------
更精簡的寫法
const obj = {
name: 'woow_wu7',
address: {
city: 'chongqing',
districe: 'yubei',
town: 'jiazhou',
detail: ['chongqign', 'yubei', 'jiazhou']
},
arr: [1,2]
}
function deepClone(parameter) {
if (typeof parameter === 'object') {
// 這裏只考慮 對象和數組
// typeof返回值是字符串,有7種
// number string boolean undefined symbol function object
const objClone = Array.isArray(parameter) ? [] : {}
for (let key in parameter) {
if (parameter.hasOwnProperty(key)) {
objClone[key] = deepClone(parameter[key])
// 無論是對象類型仍是基本數據類型,都去調用deepClone(parameter[key])
// 在deepClone()函數中會去判斷對象類型是數組仍是對象,基本數據類型直接返回並賦值給objClone[key]
}
}
return objClone
}
else {
// 不是數組和對象直接返回形參
// 注意形參是新聲明的變量
return parameter
}
}
const res = deepClone(obj)
console.log(obj)
console.log(res)
複製代碼
(1) 什麼是循環引用?
const obj = {name: 'wang'}
obj.circle = obj
// obj新增circle屬性,值是obj對象自己
// 這樣的狀況,像上面的代碼例子中,for..in循環中deepClone(parameter[key])會不斷重複執行
// 最終形成內存溢出
----------
(2) 如何解決循環引用?
1. 檢查map實例中是否有克隆過的對象
2. 若是存在,直接返回
3. 若是不存在,就賦值鍵值對,key是傳入的對象,value是克隆的對象
var objComplex = {
address: {
city: 'chongqing',
town: 'jiazhou',
},
score: [100, 200],
}
objComplex.circular = objComplex
function deepClone(objComplex, mapx = new Map()) { // 默認值,是一個空的map實例
if (typeof objComplex !== 'object') {
// 不是對象和數組直接返回
return objComplex
}
const objClone = Array.isArray(objComplex) ? [] : {}
if (mapx.get(objComplex)) {
// 存在被克隆的對象,直接返回
return mapx.get(objComplex)
}
// 不存在,就添加鍵值對,將被克隆對象做爲key,克隆的對象做爲value
mapx.set(objComplex, objClone)
for(let key in objComplex) {
objClone[key] = deepClone(objComplex[key], mapx)
// 注意:mapx要傳入作判斷
// 無論objComplex[key]是什麼類型,都調用deepClone(),由於在deepClone()中會判斷
}
return objClone
}
const res = deepClone(objComplex) // 這樣就不會內存溢出了
console.log(res, 'res')
複製代碼
缺點:Reflect不能取到原型鏈上的屬性和方法 |
用 Reflect 解決 Symbol類型數據的複製
var objComplex = {
address: {
city: 'chongqing',
town: 'jiazhou',
},
score: [100, 200],
}
objComplex.circular = objComplex
objComplex[Symbol()] = 'symbol'
function deepClone(objComplex, mapx = new Map()) {
if (typeof objComplex !== 'object') {
return objComplex
}
const objClone = Array.isArray(objComplex) ? [] : {}
if (mapx.get(objComplex)) {
return mapx.get(objComplex)
}
mapx.set(objComplex, objClone)
// for(let key in objComplex) {
// objClone[key] = deepClone(objComplex[key], mapx)
// }
Reflect.ownKeys(Array.isArray(objComplex) ? [...objComplex] : { ...objComplex }).forEach(key => {
// Reflect.ownKeys(obj)返回對象參數的全部屬性,包括symbol類型的屬性
objClone[key] = deepClone(objComplex[key], mapx)
})
return objClone
}
const res = deepClone(objComplex)
console.log(res, 'res')
複製代碼
缺點:不能處理Error,不能處理Function,不能處理DOM節點 |
function Message() {
this.sex = 'man'
}
Message.prototype.age = 1000
var objComplex = {
address: {
city: 'chongqing',
town: 'jiazhou',
},
score: [100, 200],
[Symbol()]: 'symbol',
date: new Date(),
reg: new RegExp(),
fn: function () { },
err: new Error(),
message: new Message()
}
objComplex.circle = objComplex
function deepClone(objComplex, mapx = new Map()) {
if (typeof objComplex !== 'object') {
return objComplex
}
let objClone = Array.isArray(objComplex) ? [] : {}
if (mapx.get(objComplex)) {
return mapx.get(objComplex)
}
mapx.set(objComplex, objClone)
// for(let key in objComplex) {
// objClone[key] = deepClone(objComplex[key], mapx)
// }
// Reflect.ownKeys(Array.isArray(parameter) ? [...parameter] : { ...parameter }).forEach(key => {
// objClone[key] = deepClone(parameter[key], mapx)
// })
switch (objComplex.constructor) { // 傳入的參數對象的構造函數
case Date:
case RegExp:
case Message: // 自定義的構造函數
objClone = new objComplex.constructor(objComplex)
break
// 若是是Date,RegExp,Message構造函數的請求
// 就分別用這些構造函數生成實例,而後再賦值給拷貝對象
default:
Reflect.ownKeys(Array.isArray(objComplex) ? [...objComplex] : {...objComplex}).forEach(key => {
objClone[key] = deepClone(objComplex[key], mapx)
})
}
return objClone
}
const res = deepClone(objComplex)
console.log(res, 'res')
console.log(res.message.age, '克隆的對象')
console.log(objComplex.message.age, '原對象')
複製代碼
基本:juejin.im/post/5b5dcf…
深刻:juejin.im/post/5d6aa4…
知乎(lodash deepClone源碼分析):zhuanlan.zhihu.com/p/41699218
stack,heap:segmentfault.com/a/119000000…
juejin.im/post/5d235d…
個人簡書 www.jianshu.com/p/a2306eba0…web