likes
comments
collection
share

JavaScript this、闭包和箭头函数

作者站长头像
站长
· 阅读数 14

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, ...)

callbind 的区别: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对象),在函数调用时被创建,在函数执行完后被销毁,即只存在于函数执行期间。而在全局上下文中,这叫做变量对象

JavaScript this、闭包和箭头函数

[[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呢?

JavaScript this、闭包和箭头函数

这是因为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++;
    }
}