1.var都要改為let和const
- var聲明的變量 (污染全局變量)
- 使用var導(dǎo)致變量提升的問(wèn)題
- var可以被重復(fù)聲明途蒋;let可以解決重復(fù)定義的問(wèn)題
- var作用域的問(wèn)題(全局作用域);let(函數(shù)作用域)
2.常見(jiàn)的作用域
全局作用域
函數(shù)作用域
塊作用域{} + let
3.let
問(wèn)題:暫存死區(qū)
let a = 100;
{
console.log(a); //這里會(huì)報(bào)錯(cuò):a is not defined
//當(dāng)前作用域有a,就不會(huì)去外面找号坡;但是let不會(huì)變量提升宽堆,所以a在打印的時(shí)候還未被聲明腌紧,不會(huì)是undefined
let a = 200;
}
4.const 常量 不會(huì)變的量(地址不變即可)
const的值習(xí)慣性大寫
const PI = { r: '3.14' };
PI.r = 3.15; // 此時(shí)不會(huì)報(bào)錯(cuò)壁肋,地址沒(méi)有變
5.展開(kāi)運(yùn)算符...
- 數(shù)組和對(duì)象都可以使用
- ...只能拷貝一層,是淺拷貝
- 淺拷貝(拷貝之后還有關(guān))
- 深拷貝(拷貝之后無(wú)關(guān))
- Object.assign也是淺拷貝
6.不靠譜的深拷貝嘗試:
我們可以把對(duì)象先轉(zhuǎn)化成字符串 在把字符串轉(zhuǎn)換成對(duì)象浸遗。會(huì)有一個(gè)問(wèn)題,完全無(wú)法處理fn
Object.assign = ...
let school = {name:'zfpx',fn:function(){},aa:undefined,b:null,arr:[1,2,3,[4,5]]};
let my = {age:{count:18},name:'jw'};
let all = JSON.parse(JSON.stringify({...school,...my}));
my.age.count = 100;
console.log(all);
7.自己實(shí)現(xiàn)一個(gè)深拷貝方法(遞歸拷貝)
先掌握類型判斷:
- typeof
- instanceof
- Object.prototype.toString.call
- constructor
小技巧:
- [].constructor 返回一個(gè) fn杜漠,即:Array()察净;new Array()返回[]
- {}.constructor 返回一個(gè)fn盼樟,即:Object();new Object()返回{}
- new obj.constructor會(huì)返回一個(gè)[]或者{}
注意:
- function直接返回译秦;typeof function() {} == 'function'
- Symbol不是對(duì)象击碗,直接返回;typeof Symbol == 'function'
- null == undefined true
- 用weakMap來(lái)解決“循環(huán)引用”
function deepClone(obj, hash = new WeakMap()) {
if (obj == null) return obj; // 判斷obj是null還是undefined
if (obj instanceof Date) return new Date(obj);
if (obj instanceof RegExp) return new RegExp(obj);
if (typeof obj !== 'object') return obj; // 不是對(duì)象就不用拷貝了
if (hash.has(obj)) return hash.get(obj); // 如果weakmap中有對(duì)象就直接返回之前拷貝過(guò)得obj
let cloneObj = new obj.constructor(); // 適配數(shù)組和對(duì)象
// 如果是對(duì)象把他放到weakMap中,如果再拷貝這個(gè)對(duì)象這個(gè)對(duì)象就存在了,直接返回這個(gè)對(duì)象即可
hash.set(obj, cloneObj); // 防止循環(huán)調(diào)用問(wèn)題,(程序會(huì)崩潰)
for (let key in obj) {
if (obj.hasOwnProperty(key)) { // for in會(huì)遍歷出原型上的屬性
// 只拷貝私有屬性,不考慮原型鏈上的屬性
// 如果賦予的值是對(duì)象 我就把這個(gè)對(duì)象放到weakmap中
cloneObj[key] = deepClone(obj[key], hash); // 實(shí)現(xiàn)深拷貝
}
}
return cloneObj;
}
8.set
- set是集合;不能重復(fù)的東西,否則就白放了;沒(méi)順序
- Set有symbol.iterator能被迭代,能被...展開(kāi)
- add,delete 添加和刪除
- 基礎(chǔ)類型 string number boolean undefined object symbol ???
let s = new Set([1, 2, 3, 4, 1, 2, 3, 4]);
console.log(s); // Set { 1, 2, 3, 4 }
console.log(typeof s); // object
s.add('5');
s.delete('5');
let arr = [...s]; // 有迭代,才能被展開(kāi)
console.log(arr); // [ 1, 2, 3, 4 ]
集合:并集阁吝、交集械拍、差集
let s01 = [1, 2, 3, 1, 2, 6];
let s02 = [3, 4, 5, 1, 2];
// 并集:
function union() {
let s1 = new Set(s01);
let s2 = new Set(s02);
console.log([...new Set([...s1, ...s2])]);
}
union(); // [ 1, 2, 3, 6, 4, 5 ]
// 交集:
function intersection() {
return [...new Set(s01)].filter(function (item) {
// filter返回true表示留下
return new Set(s02).has(item);
});
}
console.log(intersection()); // [ 1, 2, 3 ]
// 差集: 要看誰(shuí)差誰(shuí),順序不同結(jié)果也不同
function diff() {
return [...new Set(s01)].filter(function (item) {
return !new Set(s02).has(item); // 跟intersection相比就加了一個(gè)!
});
}
console.log(diff()); // [6]
9.Map
- map 映射表
- 跟set唯一的不同是:map有key。
- map也不能放重復(fù)的
- 在Map里銷毀obj坷虑,有引用關(guān)系迄损。
let m = new Map();
m.set('name', '123');
m.set('name', '111');
let obj = { age: 1 };
m.set(obj, '123');
m.set(obj, '456'); // 這個(gè)obj的引用的空間被set所引用
obj = null; // 把obj清空,但是這個(gè)空間還是在的
console.log(m.obj); // undefined
console.log(m); // Map { 'name' => '123', { age: 1 } => '456' }
10.WeakMap
- WeakMap的key,必須是對(duì)象類型,否則會(huì)報(bào)錯(cuò):Invalid value used as weak map key;
- 作為對(duì)象key的對(duì)象芹敌,其應(yīng)用關(guān)系會(huì)被銷毀掉。
- 在WeakMap里可以銷毀obj拗引,因?yàn)闆](méi)有引用關(guān)系幌衣,也不會(huì)再引用原來(lái)的對(duì)象壤玫。
let m = new WeakMap();
let obj = { age: 1 };
m.set(obj, '123');
obj = null; // 把obj清空,但是這個(gè)空間還是在的
console.log(m.obj); // undefined
console.log(m); // WeakMap { <items unknown> }
11.weakMap和Map的區(qū)別(與回收機(jī)制有關(guān))
- weakMap是弱鏈接哼凯,可以清空,對(duì)象刪除了也不會(huì)有引用關(guān)系猎贴。
- Map即便刪除了蝴光,還是會(huì)有引用關(guān)系,會(huì)繼續(xù)占用空間蔑祟,不會(huì)被銷毀。
12.Object.defineProperty
ES5語(yǔ)法苛败,使用場(chǎng)景很多:vue径簿,react...
- 通過(guò)Object.defineProperty定義屬性,可以增加攔截器篇亭;
- 定義的屬性是隱藏屬性,不可枚舉鄙币,不能用for...in遍歷到蹂随。
- 通過(guò)Object.defineProperty定義屬性 可以增加攔截器
- 只能用在對(duì)象上,數(shù)組是不行的
let obj = {};
let other = '';
// 不可枚舉 函數(shù)的原型 Array.protoype
Object.defineProperty(obj, 'name', {
enumerable: true, // 是否可以枚舉
configurable: true, // 是否可以配置: 能不能刪除這個(gè)屬性
//writable:true, // 是否可以重寫
get() { // 讀取方法
console.log('----');
return other;
},
set(val) { // 設(shè)置方法
other = val;
}
});
// delete obj.name; // 如果configurable為false,那么會(huì)刪不掉對(duì)象的屬性
obj.name = 456;
console.log(obj.name); // 456
13.對(duì)象的setter和getter(Vue中的數(shù)據(jù)雙向綁定)
let obj = {
other: '123',
get name() {
return this.other;
},
set name(val) {
this.other = val;
}
};
obj.name = 456;
console.log(obj.name);
14.vue的數(shù)據(jù)劫持 (把所有的屬性都改成 get和set方法)
function update() { // 模擬的更新方法
console.log('更新視圖');
}
let data = {
name: 'zfpx',
age: 18,
address: {
location: '回龍觀'
}
};
function observer(obj) {
// Object.defineProperty只能用在 對(duì)象上 (數(shù)組也不識(shí)別)
if (typeof obj !== 'object') return obj;
for (let key in obj) {
defineReactive(obj, key, obj[key]);
}
}
// 定義響應(yīng)式
function defineReactive(obj, key, value) {
observer(value); // 遞歸,嵌套的數(shù)據(jù)也會(huì)被觀測(cè)到
Object.defineProperty(obj, key, {
get() {
return value;
},
set(val) {
if (val !== value) {
observer(val);
update();
value = val;
}
}
});
}
observer(data);
data.address = [1, 2, 3];
let methods = ['push', 'slice', 'pop', 'sort', 'reverse', 'unshift'];
methods.forEach((method) => {
// 面相切片開(kāi)發(fā) 裝飾器
let oldMethod = Array.prototype[method];
Array.prototype[method] = function () {
update();
oldMethod.call(this, ...arguments);
};
});
data.address.push(4);
data.address.push(4);
15.箭頭函數(shù)
- 沒(méi)有this,沒(méi)有arguments
- 53min開(kāi)始舉的this例子沒(méi)看懂激率??招盲?
- obj是一個(gè)對(duì)象嘉冒,不是作用域咆繁,也就沒(méi)有this
- let聲明的變量顶籽,不屬于window屬性;屬于自己window下的作用域礼饱??匀伏?
let a = 1;
let obj = { //obj是一個(gè)對(duì)象镰吆,不是作用域
a: 2,
fn: () => {
setTimeout(() => {
console.log(this.a); // undefined
// 因?yàn)槎〞r(shí)器是window在調(diào)用,let的a不會(huì)掛載到window上
});
}
};
obj.fn();