前言
相信很多人在初学JavaScript的时候都对this的指向问题感觉到比较迷惑。它不像PHP,Java语言中的this有很明确的指向,也不会让人容易搞混。
在JavaScript中this就是函数调用的上下文,在JavaScript中有四种函数调用:
- 函数调用,例如alert('hello world')
- 方法调用,例如console.log('hello world')
- 构造函数调用,例如new RegExp('\d')
- 间接调用,例如alert.call(undefined,'hello world')
每种调用方式都定义了自己的上下文,所以this的表现也是不尽相同的。
另外,strict mode
严格模式也会影响可执行上下文。
理解this的关键在于,对于函数执行以及它是如何来影响上下文的有一个清晰的视角。
请熟悉一下几个概念:
- 函数调用指的就是执行构成函数体的代码,说白了,就是直接调用一个函数,比如调用
parseInt
函数,调用的方式就是parseInt('15')
,一个普普通通的调用,简单明了,没有任何副作用。 - 执行上下文,就是函数体内
this
的值。 - 函数的作用域就是函数体内能够访问到的变量和函数。
函数调用
函数调用的一个简单的例子:
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()
未完待续...
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。