小白初读冴羽大神Blog的笔记
给自己看的,就是个蓝图,没价值!
➡️➡️➡️冴羽大神Blog
- ECMAScript 和 JavaScript 的关系。
通过阅读ECMAScript标准,你可以学会怎样实现一个脚本语言;
而通过阅读JavaScript文档,你可以学会怎样使用脚本语言编程。
词法作用域(lexical scoping),也就是静态作用域
local scope: 局部作用域
可执行代码(executable code)
- 全局代码
- 函数代码
- eval代码
执行上下文(execution context)
执行上下文栈(Execution context stack,ECS)
全局执行上下文,我们用 globalContext
函数执行上下文 functionContext
对于每个执行上下文,都有三个重要属性:
- 变量对象(Variable object,VO)
- 作用域链(Scope chain)
- this
在函数上下文中,我们用活动对象(activation object, AO)来表示变量对象。
变量对象会包括:
- 函数的所有形参 (如果是函数上下文)
- 由名称和对应值组成的一个变量对象的属性被创建
- 没有实参,属性值设为 undefined
- 函数声明
- 由名称和对应值(函数对象(function-object))组成一个变量对象的属性被创建
- 如果变量对象已经存在相同名称的属性,则完全替换这个属性
- 变量声明
- 由名称和对应值(undefined)组成一个变量对象的属性被创建;
- 如果变量名称跟已经声明的形式参数或函数相同,则变量声明不会干扰已经存在的这类属性
function foo(a) {
var b = 2;
function c() {}
var d = function() {};
b = 3;
}
foo(1);
初始化:
AO = {
arguments: {
0: 1,
length: 1
},
a: 1,
b: undefined,
c: reference to function c(){},
d: undefined
}
执行后:
AO = {
arguments: {
0: 1,
length: 1
},
a: 1,
b: 3,
c: reference to function c(){},
d: reference to FunctionExpression "d"
}
- 全局上下文的变量对象初始化是全局对象
- 函数上下文的变量对象初始化只包括 Arguments 对象
- 在进入执行上下文时会给变量对象添加形参、函数声明、变量声明等初始的属性值
- 在代码执行阶段,会再次修改变量对象的属性值
?? 函数的作用域在函数定义的时候就决定了。
这是因为函数有一个内部属性 [[scope]],当函数创建的时候,就会保存所有父变量对象到其中,你可以理解 [[scope]] 就是所有父变量对象的层级链,但是注意:[[scope]] 并不代表完整的作用域链!
关注大神的github: JavaScript深入之从ECMAScript规范解读this
ECMAScript 的类型分为语言类型和规范类型。
ECMAScript 语言类型是开发者直接使用 ECMAScript 可以操作的。其实就是我们常说的Undefined, Null, Boolean, String, Number, 和 Object。
而规范类型相当于 meta-values,是用来用算法描述 ECMAScript 语言结构和 ECMAScript 语言类型的。规范类型包括:Reference, List, Completion, Property Descriptor, Property Identifier, Lexical Environment, 和 Environment Record。
Reference
这段讲述了 Reference 的构成,由三个组成部分,分别是:
- base value
- referenced name
- strict reference
base value 就是属性所在的对象或者就是 EnvironmentRecord,它的值只可能是 undefined, an Object, a Boolean, a String, a Number, or an environment record 其中的一种。
referenced name 就是属性的名称。
var foo = {
bar: function () {
return this;
}
};
foo.bar(); // foo
// bar对应的Reference是:
var BarReference = {
base: foo,
propertyName: 'bar',
strict: false
};
1.计算 MemberExpression 的结果赋值给 ref(括号之前部分)
2.判断 ref 是不是一个 Reference 类型
2.1 如果 ref 是 Reference,并且 IsPropertyReference(ref) 是 true, 那么 this 的值为 GetBase(ref)
2.2 如果 ref 是 Reference,并且 base value 值是 Environment Record, 那么this的值为 ImplicitThisValue(ref)
2.3 如果 ref 不是 Reference,那么 this 的值为 undefined
变量提升 var
块级作用域存在于:
- 函数内部
- 块中(字符 { 和 } 之间的区域)
块级声明用于声明在指定块的作用域之外无法访问的变量。
let 和 const 都是块级声明的一种。
1.不会被提升
2.重复声明报错
3.不绑定全局作用域
const 用于声明常量,其值一旦被设定不能再被修改,否则会报错。
值得一提的是:const 声明不允许修改绑定,但允许修改值。这意味着当用 const 声明对象时:
const data = {
value: 1
}
// 没有问题
data.value = 2;
data.num = 3;
// 报错
data = {}; // Uncaught TypeError: Assignment to constant variable.
临时死区(Temporal Dead Zone)
因为 JavaScript 引擎在扫描代码发现变量声明时,要么将它们提升到作用域顶部(遇到 var 声明),要么将声明放在 TDZ 中(遇到 let 和 const 声明)。访问 TDZ 中的变量会触发运行时错误。只有执行过变量声明语句后,变量才会从 TDZ 中移出,然后方可访问。
箭头函数 arrow function
An arrow function expression has a shorter syntax than a function expression and does not have its own this, arguments, super, or new.target. These function expressions are best suited for non-method functions, and they cannot be used as constructors.
箭头函数表达式的语法比函数表达式更简洁,并且没有自己的this,arguments,super或 new.target。这些函数表达式更适用于那些本来需要匿名函数的地方,并且它们不能用作构造函数。
引入箭头函数有两个方面的作用:更简短的函数并且不绑定this。
箭头函数的特性一:
- 默认绑定外层 this
- 没有 arguments
- 不能通过 new 关键字调用
- 没有 new.target
- 没有prototype
- 没有 super
总结
最后,关于箭头函数,引用 MDN 的介绍就是:
An arrow function expression has a shorter syntax than a function expression and does not have its own this, arguments, super, or new.target. These function expressions are best suited for non-method functions, and they cannot be used as constructors.
翻译过来就是:
箭头函数表达式的语法比函数表达式更短,并且不绑定自己的this,arguments,super或 new.target。这些函数表达式最适合用于非方法函数(non-method functions),并且它们不能用作构造函数。
?? 那么什么是 non-method functions 呢?
我们先来看看 method 的定义:
A method is a function which is a property of an object.
对象属性中的函数就被称之为 method,那么 non-mehtod 就是指不被用作对象属性中的函数了,可是为什么说箭头函数更适合 non-method 呢?
让我们来看一个例子就明白了:
var obj = {
i: 10,
b: () => console.log(this.i, this),
c: function() {
console.log( this.i, this)
}
}
obj.b();
// undefined Window
obj.c();
// 10, Object {...}