一. 全局执行
二. 函数中执行
- 非严格模式中
1 2 3 4 5
| function func () { console.log(this); } func();
|
- 严格模式
1 2 3 4 5 6
| "use strict"; function func() { console.log(this); } func();
|
三. 作为对象的方法调用
当一个函数被当作一个对象的方法调用的时候,this 指向当前的对象 obj
1 2 3 4 5 6 7 8
| var obj = { name: 'kk', func: function() { console.log(this.name); } } obj.func();
|
如果把对象的方法赋值给一个变量,调用该方法时,this 指向 Window:
1 2 3 4 5 6 7 8 9
| var obj = { name: 'kk', func: function() { console.log(this); } } var test = obj.func; test();
|
四. 作为构造函数使用
在 JS 中,为了实现类,我们需要定义一些构造函数,在调用一个构造函数的时候加上 new 这个关键字:
1 2 3 4 5 6 7
| function Person(name) { this.name = name; console.log(this); } var p1 = new Person('hk');
|
如果构造函数当做普通函数来调用, this则指向Window
1 2 3 4 5 6
| function Person(name) { this.name = name; console.log(this); } var p1 = Person('hk');
|
五. 在定时器中使用
1 2 3 4
| setInterval(function() { console.log(this); }, 1000)
|
如果没有特殊指向,setInterval 和setTimeout 的回调函数中 this 的指向都是 Window 。这是因为 JS 的定时器方法是定义在 Window 下的。
六. 箭头函数
全局环境下调用
1 2 3 4 5
| let func = () => { console.log(this); } func();
|
作为对象的一个函数调用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| var obj = { name: 'hh', func: function () { console.log(this); } } obj.func();
var obj = { name: 'hh', func: () => { console.log(this); } } obj.func();
|
特殊情况:结合定时器调用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| var obj = { name: 'hh', func: function() { setTimeout(function() { console.log(this); }, 0) } } obj.func();
var obj = { name: 'hh', func: function() { setTimeout(() => { console.log(this); }, 0) } } obj.func();
|
若在对象的函数中,普通函数作为定时器延时执行的函数调用,this 指向 Window;箭头函数作为定时器延时执行的函数调用, this 指向定义时所在的对象,也就是 func 中的 this,即 obj。
箭头函数中 this 的值取决于该函数外部非箭头函数的 this 的值,且不能通过 call() 、 apply() 和 bind() 方法来改变 this 的值。
七. call, apply, bind
call
1
| fun.call(thisArg[, arg[, arg2[, ...]]]);
|
它会立即执行函数, 第一个函数是指执行函数中的上下文, 后面的参数是执行函数需要传入的参数
apply
1
| fun.apply(thisArg, [argsArray]);
|
它也会立即执行函数,第一个参数是指定执行函数中 this 的上下文,第二个参数是一个数组,是传给执行函数的参数(与 call 的区别)
bind
1
| var foo = fun.bind(thisArg[, arg[, arg2[, ...]]]);
|
它不会执行函数,而是返回一个新的函数,这个新的函数被指定了 this 的上下文,后面的参数是执行函数需要传入的参数
例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| function Person(name, age) { this.name = name; this.age = age; console.log(this); } var obj = { name: 'hk', age:18 }; Person.call(obj, 'mm', 10);
Person.apply(obj, ['mm', 10]);
var p1 = Person.bind(obj, 'mm', 10); var p2 = new p1();
|
示例中,call、apply 和 bind 的 this 都指向了 obj,都能正常运行;call、apply 会立即执行函数,call 和 apply 的区别就在于传递的参数,call 接收多个参数列表,apply 接收一个包含多个参数的数组;bind 不是立即执行函数,它返回一个函数,需要执行 p2 才能返回结果,bind 接收多个参数列表。
应用: 改变this的指向
使用es6的箭头函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| var name = 'hk'; var obj = { name: 'hh', func1: function() { console.log(this.name); }, func2: function() { setTimeout(function() { this.func1(); }, 1000); } }; obj.func2();
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| var name = 'hk'; var obj = { name: 'hh', func1: function() { console.log(this.name); }, func2: function() { setTimeout(() => { this.func1(); }, 1000); } }; obj.func2();
|
在函数内部使用_this = this 略
使用call/apply/bind
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| var name = 'hk'; var obj = { name: 'hh', func1: function() { console.log(this.name); }, func2: function() { setTimeout(function() { this.func1(); }.call(obj), 1000); }, func3: function() { setTimeout(function() { this.func1(); }.apply(obj), 1000); }, func4: function() { setTimeout(function() { this.func1(); }.bind(obj)(), 1000); } }; obj.func2(); obj.func3(); obj.func4();
|
new 实例化一个对象