函数上下文 this 判断技巧。

493 阅读3分钟

在 JavaScript 的世界里,一切都可以理解为对象。包括函数,函数在 JS 中也是一类对象,不过是一类特殊的对象,将函数作为构造类来使用,可以生成新的对象,从而实现JS 世界中的类的概念。

接下来我们从头开始回顾函数的发展过程。

我们知道,函数包含定义调用两个阶段,函数在使用之前,必须先定义。

函数定义

有的同学可能更习惯用声明来表示定义,没关系,都可以。

函数定义共分为如下几种:

  • 声明式定义
  • 表达式定义
  • 构造函数式
  • 箭头函数

接下来我们一一介绍。

声明式定义函数

最早我们定义一个函数是这样子的,也是最常见的。

function test(){
    //todo
}

很简单,定义好之后,我们就可以使用了:

test();

表达式定义函数

定义一个函数,也可以理解为定义一个变量,将这个变量的值指向一个函数,于是就有了另外一种定义函数的方式(表达式定义):

var test = function(){
    //todo
}

调用也很简单

test();

那声明式定义函数与表达式定义函数之间的区别是什么? 大家看下面两段代码:

test();
function test(){
    //todo
}

对象方法的调用:

var a = {
    say:function(){
        //todo
    }
    
}
a.say();

函数调用时, 内部的this,一定是指向函数所属的对象的。

构造函数式定义

var say = new Function('a','b','return a + b');

箭头函数

ES6 规范中的函数定义方式。

let say = () => {};

函数调用

直接调用

let say = function(){console.log(this)}
say();

间接调用

间接调用分为两种,callapplycallapply 的作用就是改变函数调用的上下文。下面举个例子来说明一下它们的作用。

我们先定义一个函数 test:

function test(){
    console.log(this);
}

这个函数很简单,仅仅是打印当前上下文 this。

我们这样调用

test();

输出结果是 window。

我现在又有一个对象 a :

var a = {
    name: '小A'
}

我想让a 对象执行 test 方法提供的功能,该怎么办呢?

当然,大家可以说,我给 a 对象增加一个方法 testA,然后执行 a 对象的 testA 方法,不就可以了吗?

a.testA = function(){
    console.log(this);
}
a.testA();

那我们如果不想为 a 对象额外增加这个方法,而是复用最开始定义的 test 方法,怎么办?? 这就是 call 和 apply 的作用。

test.call(a);
//或者
test.apply(a);

这就是改变函数执行上下文的意思。

call 和 apply 的唯一区别是传参不同。

call 的第一个参数是上下文对象,剩余的参数就是函数调用时的参数。

test.call(a, 1, 2, 3);

apply 的第一个参数是上下文对象,第二个参数是个数组,数组中存放的是函数调用时的参数。

test.apply(a, [1, 2, 3]);

函数执行上下文 this 指向。

var a = {
    name: 'A',
    say: function(){
        console.log(this.name);
    }
}
a.say();

打印的是 'A'。

我们接着看:

var a = {
    name: 'A',
    say: function(){
        function test(){
            console.log(this.name);
        }
        test();
    }
}
a.say();

执行结果是 undefined,而不是 'A'。 这是为什么?

一个简单的理解方法:

1、凡是通过function 定义的函数里面的 this 指向,一定是该函数调用时所指向的对象。

test() 等价为 window.test()

所以 test() 执行时 this 指向 window。

2、箭头函数里面的 this 指向,一定是该箭头函数在定义时所指向的执行上下文。

以上就是对函数 this 指向的一些归纳,利用这些方法,能让你精准地判断 this 指向,即使写一百层复杂嵌套函数,也能轻松判断出来。

(本文完)