原型&原型链
原型定义:任何一个js对象中创建时关联的对象,根据原型构造函数创建出的对象都会继承原型上的属性
案例:
function Person(){}
const person= new Person()
console.log(person.__proto__ === Person.prototype) //true
console.log(Person.prototype.constructor === Person) //true
console.log(Object.getPrototypeOf(person) === Person.prototype) //true
原型的关系图:
原型链定义:当我们访问一个对象的属性或方法时,如果该对象自身没有该属性或方法,会沿着原型链向上查找,直到找到该属性或方法或者到达原型链的末端(即null)为止。
案例:
function Person(){}
const person= new Person()
console.log(person.constructor === Person) //true
// person.constructor 没有这个属性会一直往上找
原型链关系图:
作用域
定义:是指在程序中定义变量的区域,作用域中定义了如何找到对应的变量 在执行代码运行作用域中获取变量权限,作用域又分为词法作用域和动态作用域
词法作用域:是指作用域是在代码编写阶段确定的,基于变量在源代码中声明的位置来确定其作用域。在词法作用域中,作用域链是通过代码的嵌套关系来确定的 js就是词法作用域
动态作用域:是指作用域是在代码运行阶段确定的,基于程序的执行流程来确定变量的作用域。在动态作用域中,作用域链是根据代码的调用栈来确定的
案例:
const value=1
function foo(){
console.log(value)
}
function bar(){
const value=2
foo()
}
bar() //1
执行上下文
案例
var foo = function () {
console.log('foo1');
}
foo(); // foo1
var foo = function () {
console.log('foo2');
}
foo(); // foo2
function foo() {
console.log('foo1');
}
foo(); // foo2
function foo() {
console.log('foo2');
}
foo(); // foo2
这两个为什么会不一样?
因为 JavaScript 引擎并非一行一行地分析和执行程序,而是一段一段地分析执行。当执行一段代码的时候,会进行一个“准备工作”执行时会形成执行上下文栈
ECStack = [
globalContext
];
栈特点:先进后出
对于每个执行上下文,都有三个重要属性:
- 变量对象(
Variable object
,VO); - 作用域链(
Scope chain
); - this;
变量对象:是与执行上下文相关的数据作用域,存储了在上下文中定义的变量和函数声明。 因为不同执行上下文下的变量对象稍有不同,所以我们来聊聊全局上下文下的变量对象和函数上下文下的变量对象
全局上下文(全局对象): 全局上下文中的变量对象就是全局对象
函数上下文: 它通过函数的 arguments 属性初始化。arguments 属性值是 Arguments 对象
执行过程:
- 进入执行上下文;
- 代码执行;
作用域链:当查找变量的时候,会先从当前上下文的变量对象中查找,如果没有找到,就会从父级(词法层面上的父级)执行上下文的变量对象中查找,一直找到全局上下文的变量对象,也就是全局对象。这样由多个执行上下文的变量对象构成的链表就叫做作用域链
过程: 执行函数,创建函数执行上下文,函数执行上下文被压入执行上下文栈 (函数创建->函数激活 )
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 类型就是用来解释诸如 delete、typeof 以及赋值等操作行为的。
这里的 Reference 是一个 Specification Type,也就是 “只存在于规范里的抽象类型”。它们是为了更好地描述语言的底层行为逻辑才存在的
如何确定this的值 :
-
计算 MemberExpression 的结果赋值给 ref;
-
判断 ref 是不是一个 Reference 类型;
- 如果 ref 是 Reference,并且 IsPropertyReference(ref) 是 true, 那么 this 的值为 GetBase(ref)
- 如果 ref 是 Reference,并且 base value 值是 Environment Record, 那么this的值为 ImplicitThisValue(ref)
- 如果 ref 不是 Reference,那么 this 的值为 undefined;