作用域链
- 作用域就是变量(变量作用域也叫上下文)和函数生效(能被访问)的区域集合
- 作用域包括全局作用域、函数作用域、块级作用域(ES6提出的let和const)
- 词法作用域是js遵循的,又叫静态作用域,变量被创建时就确定好了,而非执行阶段确定的
- 作用域链就是会现在本层作用域查找,查找不到再一层层往上查
对象的原型和原型链
每一个对象都拥有一个原型对象
属性和方法定义在Object对象的构造器函数的prototype属性上,而非实例对象本身
function doSomething(){}
console.log( doSomething.prototype );
// 输出------也就是原型对象
{
constructor: ƒ doSomething(),
__proto__: {
constructor: ƒ Object(),
hasOwnProperty: ƒ hasOwnProperty(),
isPrototypeOf: ƒ isPrototypeOf(),
propertyIsEnumerable: ƒ propertyIsEnumerable(),
toLocaleString: ƒ toLocaleString(),
toString: ƒ toString(),
valueOf: ƒ valueOf()
}
}
当试图访问一个对象的属性时,它不仅仅在该对象上搜寻,还会搜寻该对象的原型,以及该对象的原型的原型,依次层层向上搜索,直到找到一个名字匹配的属性或到达原型链的末尾
__proto__
作为不同对象之间的桥梁,用来指向创建它的构造函数的原型对象的
person._proto_ === Person.prototype //每个对象的_proto_都是指向它的构造函数的原型对象prototype的
Person.prototype.constructor === Person
Person.prototype._proto_ === Object.prototype //原型对象本身是一个普通对象,而普通对象的构造函数都是Object
Object.prototype.constructor === Object
Object._proto_ === Function.prototype //所有的构造器都是函数对象,函数对象都是 Function构造产生的
Person._proto_ === Function.prototype //构造函数是一个函数对象,是通过 Function构造器产生的
Function.prototype.constructor === Function
Function._proto_ === Function.prototype
Function.prototype._proto_ === Object.prototype
Object.prototype._proto_ === null
this的指向
this
关键字是函数运行时自动生成的一个内部对象,只能在函数内部使用,总指向调用它的对象
this的绑定规则
-
默认绑定
严格模式下,不能将全局对象用于默认绑定,this会绑定到
undefined
,只有函数运行在非严格模式下,默认绑定才能绑定到全局对象 -
隐式绑定
函数还可以作为某个对象的方法调用,这时
this
就指这个上级对象var o = { a:10, b:{ fn:function(){ console.log(this.a); //undefined } } } o.b.fn();
特殊情况
var o = { a:10, b:{ a:12, fn:function(){ console.log(this.a); //undefined console.log(this); //window } } } var j = o.b.fn; j();
此时
this
指向的是window
,this
永远指向的是最后调用它的对象,虽然fn
是对象b
的方法,但是fn
赋值给j
时候并没有执行,所以最终指向window
-
new绑定
通过构建函数
new
关键字生成一个实例对象,此时this
指向这个实例对象特殊情况
-
new
过程遇到return
一个对象,此时this
指向为返回的对象 -
如果返回一个简单类型的时候,则
this
指向实例对象 -
注意的是
null
虽然也是对象,但是此时new
仍然指向实例对象
-
-
显示修改
-
apply()、call()、bind()
是函数的一个方法,作用是改变函数的调用对象。它的第一个参数就表示改变后的调用这个函数的对象。因此,这时this
指的就是这第一个参数 -
new绑定优先级 > 显示绑定优先级 > 隐式绑定优先级 > 默认绑定优先级
-
箭头函数
在 ES6 的语法中还提供了箭头函语法,在代码书写时就能确定 this
的指向(编译时绑定)
不适用箭头函数的场景
场景1:对象方法
场景2:对象原型
场景3:构造函数
场景4:动态上下文的回调函数
场景5:vue的生命周期和method
执行上下文和执行栈
- 全局执行上下文:只有一个,浏览器中的全局对象就是
window
对象,this
指向这个全局对象 - 函数执行上下文:存在无数个,只有在函数被调用的时候才会被创建,每次调用函数都会创建一个新的执行上下文
- Eval 函数执行上下文: 指的是运行在
eval
函数中的代码,很少用而且不建议使用
执行上下文的生命周期包括三个阶段:创建阶段 → 执行阶段 → 回收阶段
-
创建阶段即当函数被调用,但未执行任何其内部代码之前
-
创建阶段做了三件事:
-
- 确定 this 的值,也被称为
This Binding
- LexicalEnvironment(词法环境) 组件被创建------------(一个函数和对其周围状态(lexical environment,词法环境)的引用捆绑在一起(或者说函数被引用包围),这样的组合就是闭包。每当创建一个函数,闭包就会在函数创建的同时被创建出来,作为函数内部与外部连接起来的一座桥梁)
- VariableEnvironment(变量环境) 组件被创建--------------在 ES6 中,词法环境和变量环境的区别在于前者用于存储函数声明和变量(
let
和const
)绑定,而后者仅用于存储变量(var
)绑定
- 确定 this 的值,也被称为
-
var声明的变量从在创建阶段被赋值为undefined。这是因为,创建阶段,会在代码中扫描变量和函数声明,然后将函数声明存储在环境中,但变量会被初始化为
undefined
(var
声明的情况下)和保持uninitialized
(未初始化状态)(使用let
和const
声明的情况下)。这就是变量提升的实际原因 -
回收阶段 执行上下文出栈等待虚拟机回收