Js中的作用域/this/闭包


作用域

全局作用域、函数作用域、块作用域(ES6)
函数作用域在函数定义的时候就确定了,this是在函数调用的时候确定的

Js变量
  1. 实例变量:(this)类的实例才能访问到的变量
  2. 静态变量:(属性)直接类型对象能访问到的变量
  3. 局部变量: 当前作用域内有效的变量
1
2
3
4
5
function ClassA(){
var a = 1; // 局部变量
this.b = 2; //实例变量,只有实例可以访问
}
ClassA.c = 3; // 静态变量,也就是属性

this

this指向

每次函数调用的时候解析器都会向函数内部传递进一个隐形的参数,这个参数就是this,对应的是当前的对象。
根据函数的调用方式的不同,this会指向不同的对象:
1、以函数的形式调用时,this永远都是window。比如fun();相当于window.fun()
2、以方法的形式调用时,this是调用方法的那个对象
3、以构造函数的形式调用时,this是新创建的那个对象
4、使用bind,call和apply调用时,this是指定的那个对象
5、箭头函数this:箭头函数的this不是调用的时候决定的,而是在定义的时候处在的对象就是它的this。箭头函数的this看外层的是否有函数,如果有,外层函数的this就是内部箭头函数的this,如果没有函数,则this是window。

转换this方法

bind(arg1, arg2…) 第一个参数为this,第二个参数当函数的第一个实参,执行的时候还可以再传
call(arg1,arg2,arg3…);第一个参数为替换this,第二个开始是传给函数的参数,并执行函数
apply(arg1,[arg2,arg3…]);第一个参数为替换this,第二个开始是数组,数组里的值传给函数的参数,并执行函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// 场景1
var xw={
name: "小王",
say: function(){
console.log(this.name)
}
}
var xh={
name: "小红"
}
xw.say() // '小王'
// 怎么让xh也有say函数功能
let fn = xw.say.bind(xh)
fn(2) // '小红'

// 场景2:获取数组中最大值
var arr=[1,3,9,7,4];
//Math.max(1,3,9,7,4);
console.log(Math.max.apply(null,arr));

// 场景3:函数中的arguments
// 函数中的arguments
let fn = function () {
Array.prototype.forEach.call(arguments, item => {
console.log(item)
})
}
fn(1,2,3,4,5)

// 场景5
// document.querySelectorAll('div')

闭包

  1. 一个函数里的一个局部变量和一个内部函数的总和就是闭包, 常常用来间接访问一个局部变量,避免污染全局
  2. 一般函数执行完局部变量是会被释放掉的,但是存在于闭包中的变量会存在
  3. 闭包的缺点:函数执行完后, 函数内的局部变量没有释放,占用内存时间会变长,容易造成内存泄露。
  4. 解决办法:f = null; // 让内部函数成为垃圾对象 –>回收闭包
1
2
3
4
5
6
7
8
9
let closure = function () {
var local = 'aaa'
return function foo() {
local++
return local
}
}
let fn2 = closure()
fn2 = null // 让内部函数成为垃圾对象

内存溢出和内存泄露

  1. 内存溢出:当程序运行需要的内存超过了剩余的内存时, 比如死循环,数据过大。
  2. 占用的内存没有及时释放。比如:1.意外的全局变量 2.没有及时清理的计时器或回调函数 3.闭包