头图

前言

相信很多人在初学JavaScript的时候都对this的指向问题感觉到比较迷惑。它不像PHP,Java语言中的this有很明确的指向,也不会让人容易搞混。
在JavaScript中this就是函数调用的上下文,在JavaScript中有四种函数调用:

  1. 函数调用,例如alert('hello world')
  2. 方法调用,例如console.log('hello world')
  3. 构造函数调用,例如new RegExp('\d')
  4. 间接调用,例如alert.call(undefined,'hello world')

每种调用方式都定义了自己的上下文,所以this的表现也是不尽相同的。
另外,strict mode严格模式也会影响可执行上下文。
理解this的关键在于,对于函数执行以及它是如何来影响上下文的有一个清晰的视角。
请熟悉一下几个概念:

  1. 函数调用指的就是执行构成函数体的代码,说白了,就是直接调用一个函数,比如调用parseInt函数,调用的方式就是parseInt('15'),一个普普通通的调用,简单明了,没有任何副作用。
  2. 执行上下文,就是函数体内this的值。
  3. 函数的作用域就是函数体内能够访问到的变量和函数。

函数调用

函数调用的一个简单的例子:

function sayHello() {
  console.log('hello');
}

sayHello(); // 输出:hello

没有任何拖泥带水的东西,简单。

另外立即执行函数IIFE也是函数调用的一种,如:

(function (name) {
  console.log('hello ' + name);
})('tt'); // 输出:hello tt

在函数调用中,this总是指向全局对象,浏览器中就是window对象。

function sayHello() {
  console.log('hello'); // this==window
}

sayHello(); // 输出:hello
(function (name) {
  console.log('hello ' + name);
})('tt'); // 输出:hello tt,  this==window
测试
const obj = {
  name: 'tt',
  sayHello() {
    console.log(this);
    // 这里的this是什么?
    function sayBye() {
      console.log(this);
      //这里的this是什么?
      console.log('Bye');
    }
    return sayBye();
  }
};


obj.sayHello();

根据上面讲过的规则,思考下,this分别是什么,然后在浏览器中查看,看看你是否已经掌握。

分析:这里的sayHello是属于对象obj的一个方法,所以在sayHello函数中,属于方法调用的范畴而不是函数调用的范畴,所以this肯定当然是只想obj了,再看看sayBye函数,sayBye函数就是一个普通的函数调用,所以this当然就是只想window了,外层sayHello函数中的this指向丝毫没有影响到sayBye函数的this指向,且也无法影响,毫无疑问。
进阶:有人想问了,如果我非想让sayBye函数中的this输出的是obj对象呢?有办法,代码如下:
const obj = {
  name: 'tt',
  sayHello() {
    function sayBye() {
      console.log(this);
      console.log('Bye');
    }
    return sayBye.bind(obj); // 思考下,这里能否用apply,call?
  }
};

obj.sayHello()()
灵魂深度拷问
const obj = {
  name: 'tt',
  sayHello() {
    function sayBye() {
      console.log(this);
      console.log('Bye');
    }
    sayBye.bind(obj);
    return sayBye();
  }
};


obj.sayHello()

上述代码的this输出什么?
>.< what the fuck!
解答:毫无疑问,输出的仍然是window,为啥?bind的用法,是什么?bind方法会创建一个新函数,当这个新函数被调用时,它的this值是传递给bind方法的第一个参数。上述代码是bind了,但是你没返回bind后生成的新函数,所以,跟没bind一个样儿。
正确写法相信小伙伴们已经知道如何修改了,上代码:

const obj = {
  name: 'tt',
  sayHello() {
    function sayBye() {
      console.log(this);
      console.log('Bye');
    }
    return sayBye.bind(obj);
  }
};

obj.sayHello()();
const obj = {
  name: 'tt',
  sayHello() {
    function sayBye() {
      console.log(this);
      console.log('Bye');
    }
    return sayBye.apply(obj);
  }
};

obj.sayHello()

未完待续...


hero
525 声望2 粉丝

A Linux lover.