JavaScript this、闭包和箭头函数
this
this是函数内部的特殊对象之一(其他还有arguments、caller、new.target)。
this的 指向或值是不确定的,取决于函数的调用方式。
在JavaScript中,this的指向有以下几种情况:
- 作为对象的方法调用
- 作为普通函数调用
- 构造器调用
- Function.prototype.call、Function.prototype.apply和Function.prototype.bind调用
此外,this在使用 闭包 和 箭头函数 时的情况我们在后面介绍两者时再谈。
1.作为对象的方法调用
当函数作为对象的方法被调用时,this指向该对象。
const obj = {
name: 'obj',
getName: function () {
console.log(this.name);
}
}
obj.getName(); //obj
2.作为普通函数调用
当函数不作为对象的属性被调用时,this指向全局对象,浏览器中是window对象。
const name = 'window'
const getName = function () {
console.log(this.name);
}
getName(); //window
3.构造器调用
当函数被new调用时,this指向新创建的对象。
const Person = function (name) {
this.name = name;
}
const person = new Person('person');
console.log(person.name); //person
4.Function.prototype.call、Function.prototype.apply和Function.prototype.bind调用
当使用call或apply调用时,this指向传入的第一个参数。
function.call(thisArg, arg1, arg2, ...)
function.apply(thisArg, [argsArray])
function.bind(thisArg, arg1, arg2, ...)
call
和 bind
的区别:call 会立即执行函数,bind 不会立即执行函数,而是返回一个新函数,你可以随时调用它。
深入理解闭包
闭包(closure)是函数及其周围词法环境的组合。
闭包会捕获并记住函数创建时的作用域,使得函数可以在其声明范围之外的地方执行。
闭包是什么?
闭包是指内部函数可以访问外部函数的变量,即使外部函数执行完后在内部函数中仍然可以访问这些变量。
在JavaScript中,函数是第一类对象,因此函数可以被当作参数传递、返回值返回,甚至嵌套在其他函数中,形成闭包。
创建闭包的最常见的方式就是在一个函数内部创建另一个函数,即嵌套函数。
const a4=4;
var a5=5;
const func1 = function (a3) {
const a2=2;
function func2() {
const a1=1;
return function func3(){
console.log(a1+a2+a3+a4+a5);
}
};
return func2();
};
const result=func1(3);
result();
外部函数的活动对象位于内部函数作用域链上的第二个,该作用域链直到全局执行上下文才终止。
活动对象是包含函数的所有局部变量的对象(包括arguments
对象),在函数调用时被创建,在函数执行完后被销毁,即只存在于函数执行期间。而在全局上下文中,这叫做变量对象。
[[Scopes]]
保存了函数的作用域链。
闭包读取函数内部的变量,这使得变量始终保存在内存中,不会在函数调用后被自动清除,这会导致内存泄漏,如果闭包的作用域中有大量的变量,会占用大量的内存。
闭包的用途
🏝创建私有变量
闭包可以用于封装数据,创建私有变量。这样可以避免全局变量污染,同时提供了对变量的控制。
function createCounter() {
let count = 0;
return {
increment: function () {
count++;
},
decrement: function () {
count--;
},
getCount: function () {
return count;
},
};
}
const counter1 = createCounter();
const counter2 = createCounter();
counter1.increment();
counter2.decrement();
console.log(counter1.getCount());
console.log(counter2.getCount());
输出
1
-1
🏝创建私有方法
const myModule = (function () {
let privateVar = "I am private";
function privateFunction() {
console.log(privateVar);
}
return {
publicFunction: function () {
privateFunction();
},
};
})();
myModule.publicFunction();
箭头函数
箭头函数是ES6新增的语法,它的this指向是固定的,指向定义时所在的对象,而不是使用时所在的对象。
示例分析
window.count=1;
function Counter() {
this.count = 0;
console.log(this);
this.add = function () {
this.count++;
}
}
var counter = new Counter();
setTimeout(counter.add, 1000);
setTimeout(function () {
console.log(counter.count);
console.log(window.count);
}, 2000);
输出结果为
Counter {count: 0}
0
2
奇怪,为什么输出结果是0和2,而不是1和1呢?
这是因为setTimeout
中的this
指向了window
,而不是counter
,所以counter.add()
中的this.count++
实际上是window.count++
,而不是counter.count++
。
解决方法:
1.使用bind绑定this
setTimeout(counter.add.bind(counter), 1000);
2.使用_this = this
保存this
function Counter() {
var _this = this;
this.count = 0;
console.log(this);
this.add = function () {
_this.count++;
}
}
3.使用箭头函数
function Counter() {
this.count = 0;
console.log(this);
this.add = () => {
this.count++;
}
}
转载自:https://juejin.cn/post/7282744150842818615