let和const
1.var聲明的變量掛載在window上,而let和const聲明的變量不會(huì);
var a = 4;
console.log(a) //4
console.log(window.a); //4
const a = 4;
console.log(a) //4
console.log(window.a); //undefined
let a = 4;
console.log(a) //4
console.log(window.a); //ubdefined
2 .var聲明的變量存在變量提升;let和const不存在變量提升;
console.log(a);//undefined a已經(jīng)聲明,但還沒有賦值,默認(rèn)得到undefined
var a = 10;
console.log(b);//報(bào)錯(cuò),b is not defined 找不到
let b = 4;
console.log(c);//報(bào)錯(cuò),c is not defined 找不到
const c = 100;
3.let 和const 聲明形成塊級(jí)作用域
function fn() {
var a = 100;
console.log(a); //100
}
fn()
4。在同一作用域下;let和const不能聲明同名變量,而var 可以;
var a = 10;
var a = 20;
console.log(a);//20
let b = 10;
let b = 20;
console.log(b);//報(bào)錯(cuò) 標(biāo)識(shí)符b已經(jīng)被聲明;
5.暫時(shí)死區(qū)
let和const命令聲明的變量無變量提升;且都會(huì)被所在聲明的代碼塊中;在let和const
// 命令執(zhí)行前,使用該變量都會(huì)報(bào)錯(cuò),這一部分被稱為暫時(shí)性死區(qū);
var a = 123;
if(true) {
a = 'abc';
let a;
}
6.const
一旦聲明必須賦值,不能使用null占位;
聲明后不能再修改
如果聲明的是復(fù)合數(shù)據(jù)類性,可以修改其屬性
const a =100; //聲明必須賦值
const list = [];
list[0] = 10;
console.log(list); //10
const obj = {a:100};
obj.name = 'apple';
obj.a = 10000; //復(fù)合數(shù)據(jù)類型,屬性被修改
console.log(obj); {a:10000,name:apple};
7,在let聲明之前,typeof運(yùn)算符是百分百安全的,不會(huì)拋出錯(cuò)誤;
console.log(typeof a) ; //undefined
在以前沒有l(wèi)et和const命令的時(shí)候,typeof是一個(gè)安全的運(yùn)算符,
即使變量沒有被聲明,也會(huì)正常返回undefined,但如果typeof處在死區(qū)中, 處理了在后文被let和const的變量,將會(huì)報(bào)錯(cuò)。
var a = 123;
typeof undeclared_variable;
if(true) {
// 暫時(shí)性死區(qū)
typeof a;
let a
console.log(a)
}
Proxy
在vue3.0中將會(huì)通過Proxy來替換原來的 Object.defineProperty 來實(shí)現(xiàn)數(shù)據(jù)庫響應(yīng)式,
Proxy是ES6中新增的功能, 用于修改某些操作做的默認(rèn)行為;等同于在語言層面作出修改;所以屬于一種“元編程”;即:對(duì)語言編程進(jìn)行編程; Proxy可以理解為: 在目標(biāo)對(duì)象之前架設(shè)一層‘?dāng)r截’;外界對(duì)該對(duì)象的訪問,都必須先通過這層攔截; 因此提供了一層機(jī)制,可以對(duì)外界的訪問進(jìn)行過濾和改寫, Proxy意思為代理;代理某些操作,或者也可以叫為"代理器";
1.arget代表要添加代理的對(duì)象;
2handel 用來自定義對(duì)象中的操作;比如可以用來自定義set或者get函數(shù);
3.obj:是被代理完成之后返回的對(duì)象;
當(dāng)外界每次對(duì)obj進(jìn)行操作時(shí),就會(huì)執(zhí)行handel對(duì)象上的一些方法
let p = new Proxy(target,handel,obj);
Proxy有以下幾種方法:
1.get(target, propKey, receiver
get()方法: 用于攔截某個(gè)屬性的讀取操作;可以接受三個(gè)參數(shù),1:目標(biāo)對(duì)象;2屬性名,實(shí)例本身(操作行為所針對(duì)的對(duì)象)3:可選;
var person = {
name: '張大帥'
};
var proxy = new Proxy(person, {
get: function (target, property) {
if (property in target) {
return target[property];
}else {
throw new ReferenceError('拋出錯(cuò)誤')
}
}
})
console.log(proxy.name);
//如果沒有g(shù)et方法攔截,則返回undefined;有則拋出錯(cuò)誤;
console.log(proxy.age)
2. set(target, propKey, value, receiver)
set()方法: 用來攔截某個(gè)屬性的賦值操作,可以接收4個(gè)參數(shù); 1;目標(biāo)對(duì)象,2屬性名,屬性值,Proxy實(shí)例本身;4:可選;
const obj = {
'name': 'null'
};
// <!-- 設(shè)置該對(duì)象的屬性不可寫 -->
Object.defineProperty(obj, 'name', {
writable: false
});
const handler = {
set: function (obj, prop, value, receiver) {
Reflect.set(obj, prop, value);
}
};
const proxy = new Proxy(obj, handler);
proxy.name = '我是空智';
console.log(proxy.name); // 打印的是 null
3. has(target, propKey)
has()方法:該方法是判斷某個(gè)目標(biāo)對(duì)象是否有該屬性的姓名;接受兩個(gè)參數(shù);1.目標(biāo)對(duì)象,2屬性名,;返回的是一個(gè)布爾值;
4. construct(target, args)
construct()方法:用來攔截new命令的;接受三個(gè)參數(shù):1目標(biāo)對(duì)象,2構(gòu)造函數(shù)的參數(shù)對(duì)象及創(chuàng)造實(shí)例的對(duì)象;3可選,用來攔截對(duì)象屬性;
5.apply(target, object, args)
apply()該方法用來攔截函數(shù)的調(diào)用,接受三個(gè)參數(shù):1目標(biāo)對(duì)象,2目標(biāo)上下文this對(duì)象;3目標(biāo)對(duì)象的數(shù)組
下面是 Proxy 支持的攔截操作一覽,一共 13 種。
get(target, propKey, receiver):攔截對(duì)象屬性的讀取,比如proxy.foo和proxy['foo']。 set(target, propKey,lue, receiver):攔截對(duì)象屬性的設(shè)置,比如proxy.foo = v或proxy['foo'] = v,返回一個(gè)布爾值。
has(target, propKey):攔截propKey in proxy的操作,返回一個(gè)布爾值;deleteProperty(target, propKey):攔截delete proxy[propKey]的操作,返回一個(gè)布爾值。
ownKeys(target):攔截Object.getOwnPropertyNames(proxy)、Object.getOwnPropertySymbols(proxy)、Object.keys(proxy)、for...in循環(huán),返回一個(gè)數(shù)組。該方法返回目標(biāo)對(duì)象所有自身的屬性的屬性名,而Object.keys()的返回結(jié)果僅包括目標(biāo)對(duì)象自身的可遍歷屬性。
getOwnPropertyDescriptor(target, propKey):攔截Object.getOwnPropertyDescriptor(proxy, propKey),返回屬性的描述對(duì)象。 defineProperty(target,propKey, propDesc):攔截Object.defineProperty(proxy, propKey, propDesc)、Object.defineProperties(proxy, propDescs),返回一個(gè)布爾值。
preventExtensions(target):攔截Object.preventExtensions(proxy),返回一個(gè)布爾值。
getPrototypeOf(target):攔截Object.getPrototypeOf(proxy),返回一個(gè)對(duì)象。isExtensible(target):攔截Object.isExtensible(proxy),返回一個(gè)布爾值。 setPrototypeOf(target, proto):攔截Object.setPrototypeOf(proxy, proto),返回一個(gè)布爾值。如果目標(biāo)對(duì)象是函數(shù),那么還有兩種額外操作可以攔截。
apply(target, object, args):攔截 Proxy 實(shí)例作為函數(shù)調(diào)用的操作,比如proxy(...args)、proxy.call(object,...args)、proxy.apply(...)。
construct(target, args):攔截 Proxy 實(shí)例作為構(gòu)造函數(shù)調(diào)用的操作,比如new proxy(...args)。
Proxy有許多用途,包括運(yùn)算符重載,對(duì)象模擬,簡潔而靈活的API創(chuàng)建,對(duì)象變化事件,甚至Vue 3背后的內(nèi)部響應(yīng)系統(tǒng)提供動(dòng)力。
數(shù)據(jù)響應(yīng)式
Proxy可以完美的監(jiān)聽到任何方式的數(shù)據(jù)改變;唯一缺陷可能就是瀏覽器的兼容性不好了
let str = (obj,setBind,getLogger) => {
let handel ={
get(target,perty,receiver) {
getLogger(target,perty);
return Reflect.get(target,perty,receiver)
},
set(target,perty,value,receiver) {
setBind(value,perty)
return Reflect.set(target,perty,value);
}
}
return new Proxy(obj,handel)
}
let obj = {age:21};
let q = str(
obj,
(v,perty) => {
console.log(`監(jiān)聽到屬性${perty}改變?yōu)?{v}`)
},
(target,perty) => {
console.log(`'${perty}' = ${target[perty]}`)
}
)
q.a = 2;
console.log(q.a)