闭包与this指向的问题
一、闭包的概念.
简单的理解就是内层函数可以访问外层函数中的变量
有时候需要用到函数内的局部变量,在正常情况下是不能读取到的,这个时候就需要用到闭包
二、产生闭包的方法有两种方式
函数作为参数被传递
// 函数作为参数被传递
function print(fn) {
const a = 200
fn()
}
const a = 100
function fn() {
console.log(a) // 这个a是自由变量,自由变量的概念就是往上去一层一层去寻找,就找到 a = 100
}
print(fn) // 100
函数作为返回值被返回
// 函数作为返回值
function create() {
const a = 100
return function () {
console.log(a) // 这个跟上面的同理
}
}
const fn = create()
const a = 200
fn() // 100
函数中的自由变量,取决于函数定义的地方,跟执行的地方没关系
优点:闭包因为长期驻扎在内存中,可以重复使用变量,不会造成变量污染
缺点:闭包会使函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,
否则会造成网页的性能问题,可能会导致内存泄露。解决方法是在退出函数之前,
将不使用的变量全部删除。
三、this指向问题
5大调用场景:
普通函数、
对象方法、
call apply bind
class
箭头函数
普通函数
普通函数this指向window
function fn(){
console.log(this)
}
fn() // this指向window
// 其实是 window.fn() 但是window可以省略不写
对象方法
对象方法中的this,指向当前对象
let fox = {
name:'张三'
run(){
console.log(this)
}
}
fox.run() // this指向当前调用的对象
call() /apply() /bind() 都可以改变this指向
call apply bind中调用, this指向被传入的对象
//案例一
let obj={name:'小明'}
let pox={
name:'小红',
run:function(){
console.log(this.name)
}
}
// 对象方法中的this.指向方法的调用者。
pox.run();// pox 小红
pox.run.call(obj)// 小明
pox.run.apply(obj);// 小明
pox.run.bind(obj)();//小明
//案例二
call和apply和bind都可以改变this的指向
// call 可以改变this的指向 将this指向改成第一个参数
// 第二个参数是单个
// apply 可以改变this的指向 将this指向改成第一个参数
// 第二个参数是一组
function fn(){
console.log(this) // this 指向[1,2,3]
}
fn.call([1,2,3])
function foo(){
// arguments其实就是一个伪数组
let arg = arguments;
console.log(arguments); // [1,2,3]
// arg.push(4) // 会报错,因为arguments不是真正的数组 是个伪数组
// 借用array数组的方法 改变this的指向为这个伪数组
Array.prototype.push.call(arg,4) // [1,2,3,4]
// Array.prototype.push.call(arg,[5,6]) // [1,2,3,4,Array(2)]
let arr = [5,6,7]
Array.prototype.push.apply(arg,arr) // [1,2,3,4,5,6,7]
}
foo(1,2,3)
// bind 也可以改变this的指向 需要手动调用
let obj = {name:'李四'}
let fox = {
name:'张三'
run(){
console.log(this)
}
}
fox.run()
// 第一个括号里面是要改变到哪个this
// 第二个括号是this
fox.run.bind(obj)() // this指向obj对象
相同点:call() /apply() /bind() 都可以改变this指向,指向第一个参数
不同点:bind()需要手动执行
class(es6新增)
class中的方法中调用, this指向实例对象
class Person(){
constructor(name,age){
this.name = name;
this.age = age;
}
say(){
console.log(`我叫${this.name}年龄是${this.age}`)
}
}
var person = new Person('哈哈',18)
person.say() // this指向实例出来的person对象
箭头函数(es6新增)
箭头函数,this指向父级上下文
var name = '李四'
let fox = {
name:'张三'
run:(){
console.log(this.name)
}
}
fox.run() // this指向window 所以最后打印出来的是 李四
四、this总结
普通函数中调用,this指向window
对象方法中调用,this指向当前对象
call apply bind中调用, this指向被传入的对象
class中的方法中调用, this指向实例对象
箭头函数,this就是父级上下文
定时器里的this始终指向window