关于变量提升
使用关键字给变量赋值可以分为三个阶段:
- 创建 变量,在内存中开辟空间
- **初始化 **变量,将变量初始化为 undefined
- 给变量 赋值
对于let
、var
、function
:
-
let
的 创建 过程被提升了,但是 初始化 没有被提升 -
var
的 创建 和 初始化 都被提升了 -
function
的 创建、初始化 和 赋值 都被提升了
关于 let
声明的变量是否存在 变量提升 ?
let name = 'Catalina';
{
console.log(name); // Uncaught ReferenceError: name is not defined
let name = 'Mozila';
}
如果 let
声明的变量不存在变量提升 ,console.log(name)
就会输出外层作用域的 name
Catalina,结果却抛出了 ReferenceError
,这很好的说明 let
也能变量提升,只是它存在“暂时死区”,在变量未初始化或赋值前不能被访问。
事件的三两事
javascript dom 事件传播的三个阶段
捕获 -> 目标 -> 冒泡
说明:在捕获阶段,事件通过父元素向下传递到目标元素。 然后它到达目标元素,冒泡开始。
event.target
上面点击按钮时 event.target
是 button
元素。
导致事件的最深嵌套元素是事件的目标。
事件冒泡
Click here!
上面的html再点击后会先后输出 p
和 div
。
在事件传播期间,有三个阶段:捕获,目标和冒泡。 默认情况下,事件处理程序在冒泡阶段执行(除非您将useCapture
设置为true
)。 它从最深的嵌套元素向外延伸。
JavaScript全局执行上下文为你创建了两个东西:全局对象和this关键字
基本执行上下文是全局执行上下文:它是代码中随处可访问的内容。
使用对象作为另一个对象的 key
const a = {};
const b = { key: "b" };
const c = { key: "c" };
a[b] = 123;
a[c] = 456;
console.log(a[b]);
// 456
对象的 key 值永远都是字符串,如果使用其他类型的值作为对象的 key,会先被使用 toString 方法转换成字符串。 b是一个对象,把它当作 key 使用时 先被转成字符串 "[object Object]",其实等式等于:
a["[object Object]"] = 123;
c也是这个原理:
a["[object Object]"] = 456;
等同于给这个字段覆盖了新值。
所以最后等于 456
。
手写 new
new
操作符创建一个实例,做了四件事情:
- 创建一个空对象(
{}
) - 链接该对象(即设置该对象的构造函数)到另一个对象
- 将
this
的上下文设置为新创建的空对象 - 如果该函数没有返回对象(比如,基础类型值),则返回
this
function _new(Fn, ...args) {
if (typeof Fn !== 'function') { // 如果不是函数,排除不是构造函数
throw 'Frist arg must be a function';
}
let obj = {}, res; // 创建空对象,用来设置 this 上下文,当作构造函数的实例
obj.__proto__ = Fn.prototype; // 链接实例的 __proto__ 到构造函数
// obj = Object.create(Fn.prototype)
res = Fn.call(obj, ...args); // 生成的新对象会绑定到函数调用的`this`
return res instanceof Object ? res : obj
}
匿名函数二三
- 本应匿名的函数如果设置了函数名,在函数之外是无法调用这个函数的,但是在函数体内部是可以调用这个函数名变量。
- 而且类似于创建常量一样,这个名字存储的值是不能修改的(普通模式下不报错,但是没有任何效果;严格模式下会直接报错)
var b = 10;
(function b() {
b = 20;
console.log(b);
})();
console.log(b)
/**
ƒ b() {
b = 20;
console.log(b);
}
10
*/
使用 严格模式
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 的实现方法,可以简单的如下模拟:
Array.prototype.push = function(xx) {
this[this.length] = xx
// this.length ++
return this.length
}
当执行 obj.push(1)
的时候, obj[obj.length] = 1
,于是 obj[2] = 1
;
当执行 obj.push(2)
的时候, obj[obj.length] = 2
,于是 obj[3] = 2
;
最后输出 {2: 1, 3: 2, length: 4, push: ƒ}
;