關(guān)于變量提升
使用關(guān)鍵字給變量賦值可以分為三個(gè)階段:
- 創(chuàng)建 變量,在內(nèi)存中開辟空間
- **初始化 **變量,將變量初始化為 undefined
- 給變量 賦值
對(duì)于let、var、function:
-
let的 創(chuàng)建 過(guò)程被提升了,但是 初始化 沒(méi)有被提升 -
var的 創(chuàng)建 和 初始化 都被提升了 -
function的 創(chuàng)建、初始化 和 賦值 都被提升了
?? 關(guān)于 let 聲明的變量是否存在 變量提升 ?
let name = 'Catalina';
{
console.log(name); // Uncaught ReferenceError: name is not defined
let name = 'Mozila';
}
如果 let 聲明的變量不存在變量提升 ,console.log(name) 就會(huì)輸出外層作用域的 name Catalina,結(jié)果卻拋出了 ReferenceError,這很好的說(shuō)明 let 也能變量提升,只是它存在“暫時(shí)死區(qū)”,在變量未初始化或賦值前不能被訪問(wèn)。
事件的三兩事
javascript dom 事件傳播的三個(gè)階段
捕獲 -> 目標(biāo) -> 冒泡
說(shuō)明:在捕獲階段,事件通過(guò)父元素向下傳遞到目標(biāo)元素。 然后它到達(dá)目標(biāo)元素,冒泡開始。
event.target
<div onclick="console.log('first div')">
<div onclick="console.log('second div')">
<button onclick="console.log('button')">
Click!
</button>
</div>
</div>
上面點(diǎn)擊按鈕時(shí) event.target 是 button 元素。
導(dǎo)致事件的最深嵌套元素是事件的目標(biāo)。
事件冒泡
<div onclick="console.log('div')">
<p onclick="console.log('p')">
Click here!
</p>
</div>
上面的html再點(diǎn)擊后會(huì)先后輸出 p 和 div。
在事件傳播期間,有三個(gè)階段:捕獲,目標(biāo)和冒泡。 默認(rèn)情況下,事件處理程序在冒泡階段執(zhí)行(除非您將useCapture設(shè)置為true)。 它從最深的嵌套元素向外延伸。
JavaScript全局執(zhí)行上下文為你創(chuàng)建了兩個(gè)東西:全局對(duì)象和this關(guān)鍵字
基本執(zhí)行上下文是全局執(zhí)行上下文:它是代碼中隨處可訪問(wèn)的內(nèi)容。
使用對(duì)象作為另一個(gè)對(duì)象的 key
const a = {};
const b = { key: "b" };
const c = { key: "c" };
a[b] = 123;
a[c] = 456;
console.log(a[b]);
// 456
對(duì)象的 key 值永遠(yuǎn)都是字符串,如果使用其他類型的值作為對(duì)象的 key,會(huì)先被使用 toString 方法轉(zhuǎn)換成字符串。 b是一個(gè)對(duì)象,把它當(dāng)作 key 使用時(shí) 先被轉(zhuǎn)成字符串 "[object Object]",其實(shí)等式等于:
a["[object Object]"] = 123;
c也是這個(gè)原理:
a["[object Object]"] = 456;
等同于給這個(gè)字段覆蓋了新值。
所以最后等于 456。
手寫 new
new 操作符創(chuàng)建一個(gè)實(shí)例,做了四件事情:
- 創(chuàng)建一個(gè)空對(duì)象(
{}) - 鏈接該對(duì)象(即設(shè)置該對(duì)象的構(gòu)造函數(shù))到另一個(gè)對(duì)象
- 將
this的上下文設(shè)置為新創(chuàng)建的空對(duì)象 - 如果該函數(shù)沒(méi)有返回對(duì)象(比如,基礎(chǔ)類型值),則返回
this
function _new(Fn, ...args) {
if (typeof Fn !== 'function') { // 如果不是函數(shù),排除不是構(gòu)造函數(shù)
throw 'Frist arg must be a function';
}
let obj = {}, res; // 創(chuàng)建空對(duì)象,用來(lái)設(shè)置 this 上下文,當(dāng)作構(gòu)造函數(shù)的實(shí)例
obj.__proto__ = Fn.prototype; // 鏈接實(shí)例的 __proto__ 到構(gòu)造函數(shù)
// obj = Object.create(Fn.prototype)
res = Fn.call(obj, ...args); // 生成的新對(duì)象會(huì)綁定到函數(shù)調(diào)用的`this`
return res instanceof Object ? res : obj
}
匿名函數(shù)二三
- 本應(yīng)匿名的函數(shù)如果設(shè)置了函數(shù)名,在函數(shù)之外是無(wú)法調(diào)用這個(gè)函數(shù)的,但是在函數(shù)體內(nèi)部是可以調(diào)用這個(gè)函數(shù)名變量。
- 而且類似于創(chuàng)建常量一樣,這個(gè)名字存儲(chǔ)的值是不能修改的(普通模式下不報(bào)錯(cuò),但是沒(méi)有任何效果;嚴(yán)格模式下會(huì)直接報(bào)錯(cuò))
var b = 10;
(function b() {
b = 20;
console.log(b);
})();
console.log(b)
/**
? b() {
b = 20;
console.log(b);
}
10
*/
使用 嚴(yán)格模式
var b = 10;
(function b() {
"use strict";
b = 20;
console.log(b);
})();
console.log(b)
/**
VM20050:4 Uncaught TypeError: Assignment to constant variable.
*/
Array.prototype.push
let obj = {
2: 3,
3: 4,
length: 2,
push: Array.prototype.push,
}
obj.push(1);
obj.push(2);
console.log(obj);
可以先考慮 push 的實(shí)現(xiàn)方法,可以簡(jiǎn)單的如下模擬:
Array.prototype.push = function(xx) {
this[this.length] = xx
// this.length ++
return this.length
}
當(dāng)執(zhí)行 obj.push(1) 的時(shí)候, obj[obj.length] = 1,于是 obj[2] = 1;
當(dāng)執(zhí)行 obj.push(2) 的時(shí)候, obj[obj.length] = 2,于是 obj[3] = 2;
最后輸出 {2: 1, 3: 2, length: 4, push: ?};