1⃣,闭包。
说到闭包呢,我们想到的肯定是函数嵌套函数,函数内部可以访问外部函数的变量。但其实这只是我们平时一个普通的理解,那么比较官方的说法就是,它本质上是一个函数,与作用域环境形成的一个闭包 。那么这句话该怎么理解呢?
就是说它必须得是函数,那环境作用域就是我们闭包函数的一个作用域链的规则。那关于作用域我一会儿会细说。现在我们先来看一下闭包的运用场景以及实例,以便于我们了解更深刻。
那么它的运用场景其实很广泛,比如说我们写一个数组,但是要取到数组的指定的值,这个时候我们就可以(假如取2到7的值)
var arr =[1,2,3,4,5,6,7]
funcrion new (a, b) {
return fuction newarr (v) {
return v<=a && v>=b
}
}
new(2,7)
console. log(v)
通过这个闭包来取到我们想到的值。
那么还有一个比较经典的,常出现在面试题里的一个闭包就是1到10循环递增。
那下面举一个简单的例子来了解一下。
那说到循环递增,我们想的方法可能是这样:
for(var a =0;a<10;a++){
setTimeout(
function() {
console. log(a)
},1000) //这里设置几秒输出一个
}
那么这个思想其实是正确的,但是它输出的却是11。你知道为什么嘛?
其实因为函数是同步进行的,定时器是异步进行的,那么执行的顺序是先同步后异步,所以当同步执行完了就已经是11了。那么这时候我们有两种方式来解决这个问题。
第一种方案:把for循环里的var换成let。
(原理:因为let是块级作用域)
第二种方案:函数自执行
写法附上:
for(var a =0;a<10;a++){
(function(j) {//此处的j为自由变量
setTimeout(
function() {
console. log(j )
} },1000*j) //这里设置几秒输出一个 }
}) (j) //自执行的写法
}
这里有的说明的点,就是说其实let语法它的根源就是闭包写法,let只不过是一个语法糖。
那其实运用到闭包的地方还有很多很多,就看实际操作的灵活性了
2⃣,那么第二部分就是关于js中的this指向问题。
首先对于他的一个概念就是,谁调用他就指向谁。(当然如果你深究其根的话,这句话是不完全正确的)
那么它主要是为了方便我们辨别代码输出结果的一个方向。
那下面来说明它每次不同的指向场景。
A . 全局函数以及普通函数,他们的指向一般都是全局变量,也就是window。
B . 构造函数,他的this指向是实例化他的对象。怎么理解呢,构造函数本来就是new关键字创建的函数赋给了一个新的值,一个新的对象。那么最终是由这个对象调用它,所以他的this就指向这个对象。
C . 对象,对象中的this指向为调用他的对象名。
D . 定时器,不管在任何时候,定时器的this都是指向全局的!!!也就是window。如果我们想让他指向调用的对象,我们可以把this对象赋给一个新的值,然后输出这个值,这时this指向就指向了调用他的对象。
E . 箭头函数this指向调用他的父级(其实也涉及到了作用域链)
2. 那么以上就是主要的两个部分,那上面很多次提到作用域,那么闭包的作用域是个什么概念呢?其实很简单,像是原型链一样。
就是我们一个闭包输出时,他会在当前函数的内部进行查找,如果没有找到变量,它就会去它的父级找,如果父级没有,它会继续向父级的父级找,以此类推,最终找到全局的作用域。如果全局也没有定义,他就会返回一个报错。