文章目录
一、this
1.1 this
this:this表示对当前对象的引用,this随着执行环境的改变而改变
this使用 | this指向 |
---|---|
方法中使用 | this表示方法所属的对象 |
单独使用 | this表示全局对象 |
函数中使用 | this表示全局对象(在函数中,在严格模式下,this无法指向全局对象,是未定义的undefined) |
事件中 | this表示接收事件的元素 |
call、apply | 改变函数执行时的上下文,再具体一点就是改变函数运行时的this指向 |
this指向相关文章:
https://www.cnblogs.com/penghuwan/p/7356210.html
https://www.icode9.com/content-4-609501.html
1.2 call、apply、bind
作用:改变this的指向
区别:
bind会产生新的函数,返回了改变上下文的一个函数,需要手动执行函数
call、apply不会产生新函数,但是两者传参格式不同
1.3 call、apply应用
参考博客:https://juejin.cn/post/6844903567967387656
(文章中有详细介绍,图片来源于此文章)
1.3.1 求一个数组中的最大值或最小值
var arr = [1,2,7,2];
Math.max.apply(Math, arr);//7
Math.max.call(Math, 1,2,7,2);//7
1.3.2 利用call、apply做继承(可以、多继承)
调用父类构造函数时,使用call或apply
1.3.3 将数组转化为伪数组
伪数组:dom节点、函数的arguments、具有length属性的对象。伪数组具有length属性,可以通过下标访问,但是不能使用数组的方法。
1.3.4 数组拼接,添加
1.3.5 判断变量类型
1.4 bind应用
函数柯里化
二、作用域
2.1 作用域
作用域:指定了程序中变量的生命周期和适用范围
分类:全局作用域、局部作用域、块级作用域
2.1.1 全局作用域
最外层函数和在最外层函数外面定义的变量,拥有全局作用域
所有末定义直接赋值的变量,拥有全局作用域
所有window对象的属性拥有全局作用域
2.1.2 局部作用域
函数作用域
2.1.3 块级作用域(es6新增)
新增原因:循环变量泄露为全局变量,变量提升导致内层变量覆盖外层变量
块级作用域范围:块级作用域入口——变量赋值
var声明的变量可以提升,可以在声明之前使用,但是let定义的变量在声明之前使用会报错
因为预编译时,var声明的变量提升到作用域顶部,let声明的变量放在TDZ,输出结果为referenceError
图片来源于其他文章(地址不记得了)
2.2 作用域链
函数创建时,js引擎(后台)会默认创建一个仅供后台使用的内部属性[[Scope]],此属性存储函数作用域链,如果是全局函数,此时则包含一个变量对象(全局变量),如果是嵌套函数(闭包),作用域链还加上了父函数的变量对象。
函数调用时,js引擎(后台)创建内部对象——执行环境,执行环境有它自己的作用域链,执行环境创建时就以定义函数时的作用域链初始化它自己的作用域链,并且随后创建了一个活动对象,活动对象作为函数执行期的一个变量对象,包含所有局部变量(在函数内定义的)、命名参数、arguments、this,它会被推入到执行环境作用域链的前端(如下图)。每执行一次函数都会创建一个新的执行环境,当函数执行完毕执行环境就会被销毁。
当代码在一个环境中执行时,会创建变量对象的一个作用域链(scope chain)。作用域链的用途,是保证对执行环境有权访问的所有变量和函数的有序访问。作用域链的前端,始终都是在当前执行的代码所在环境的变量对象。如果这个环境是函数,则将其活动对象(activation object)作为变量对象。活动对象在最开始时只包含一个变量,即arguments 对象(这个对象在全局环境中是不存在的)。作用域链中的下一个变量对象来自包含(外部)环境,而再下一个变量对象则来自下一个包含环境。这样,一直延续到全局执行环境;全局执行环境的变量对象始终都是作用域链中的最后一个对象。
标识符解析是沿着作用域链一级一级地搜索标识符的过程。搜索过程始终从作用域的前端开始,然后逐级地向后回溯,直到找到标识符为止(如果找不到标识符,通常会导致错误发生)。
由于作用域存在着嵌套(比如函数嵌套另一个函数),所以js引擎在查找变量时会先查找当前作用域内,如果查找不到,会查找外层作用域内是否含有,直到查找到全局作用域。这就形成了作用域链的概念。
2.3 with语句
临时扩展作用域链,将with语句中的对象添加到作用域的头部。
一旦使用with,并将with的对象添加到作用域头部后,访问函数中的局部变量也需要经过这个变量,影响了性能,严格模式不支持with
PS:try catch也会延长作用域链,新增了catch语句块
2.4 词法作用域
词法作用域就是定义在词法阶段的作用域,无论函数在哪里被调用,也无论它如何被调用,它的词法作用域都只由函数被声明时所处的位置决定
[注意]词法作用域查找只会查找一级标识符,如果代码引用了foo.bar.baz,词法作用域查找只会试图查找foo标识符,找到这个变量后,对象属性访问规则分别接管对bar和baz属性的访问
作用域查找从运行时所处的最内部作用域开始,逐级向外或者说向上进行,直到遇见第一个匹配的标识符为止
在多层的嵌套作用域中可以定义同名的标识符,这叫作“遮蔽效应”,内部的标识符“遮蔽”了外部的标识符
全局变量会自动为全局对象的属性,因此可以不直接通过全局对象的词法名称,而是间接地通过对全局对象属性的引用来对其进行访问。过这种技术可以访问那些被同名变量所遮蔽的全局变量。但非全局的变量如果被遮蔽了,无论如何都无法被访问到
参考博客:https://www.cnblogs.com/xiaohuochai/p/5700095.html
2.5 动态作用域——运行时确定
动态作用域并不关心函数是如何声明以及在任何处声明的,只关心它们从何处调用。换句话说,作用域链是基于调用栈的,而不是代码中的作用域嵌套