JavaScript 里的 this 关键字
由 new 调用?绑定到新创建的对象。
由 call、apply 或 bind 调用?绑定到指定的对象。
由上下文对象调用?绑定到那个上下文对象。
默认:在严格模式下绑定到 undefined,否则绑定到全局对象。
刚入门 JavaScript 的时候被 this 指向弄懵的我算一个。由于其运行期绑定的特性,JavaScript 中的 this 含义要丰富得多,它可以是全局对象、当前对象或者任意对象,这完全取决于函数的调用方式。JavaScript 函数调用方式有以下几种:作为对象方法调用,作为函数调用,作为构造函数调用,使用 apply 或 call 调用。本文章根据所有不同调用方式列出 this 的含义。
全局上下文
在浏览器运行环境中,this 指代全局对象,无论是否在严格模式下
window === this // true const _ = 'val' console.log(this._) // val
函数上下文
this 指向取决于函数是如何调用的。直接调用的情况下,this 指向全局。
function fn () { return this } fn() === window // true
在对象中调用方法时,this 指向该函数的对象。
const color = 'red' const obj = { color: 'blue', result () { console.log(this.color) } } obj.result() // 结果为blue
原型链与构造函数中的 this。当一个函数被作为一个构造函数来使用(使用 new 关键字),它的 this 与即将被创建的新对象绑定。
const x = 1 const y = 1 function example (x, y) { this.x = x this.y = y } example.prototype.count = function () { return this.x + this.y } const a = new example(2, 2) console.log(a.count()) // 4
call 与 apply
三种方法用于改变函数上下文,即改变函数运行时 this 的指向,举个例子
function info (name) { this.name = name } info.prototype.show = function () { console.log('my name is ' + this.name) } const myObj = new info('sakuya') myObj.show() // my name is sakuya const anthorObj = { name: 'maho' } myObj.show.call(anthorObj) // my name is maho myObj.show.apply(anthorObj) // my name is maho myObj.show.bind(anthorObj)() // my name is maho
call 与 apply 区别在于传入的参数,第一个参数都是要改变上下文的对象。而call从第二个参数开始以参数列表的形式展现,apply则是把除了改变上下文对象的参数放在一个数组里面作为它的第二个参数。
fn.call(obj, arg1, arg2, arg3...); fn.apply(obj, [arg1, arg2, arg3...]);
使用场景
数组,借助其他对象的方法实现目的
Math.max.apply(null, [14, 3, 77]) // 77 var arr1 = [0, 1, 2]; var arr2 = [3, 4, 5]; Array.prototype.push.apply(arr1, arr2); // [0, 1, 2, 3, 4, 5] // 可利用es6扩展运算符(spread)代替 Math.max(...[14, 3, 77]) arr1.push(...arr2) [...arr1, ...arr2]
数组,作为参数传入方法
function example(x, y, z){ console.log(x,y,z) } example.apply(null, [1, 2, 3]) // 1 2 3 // 可利用es6扩展运算符(spread)代替 function example(x, y, z){ console.log(x,y,z) } example(...[1, 2, 3]) // 1 2 3
也可利用call实现继承
function Superfn(){ this.colors = ["red", "blue", "green"]; } function Subfn(){ //继承了Superfn Superfn.call(this); }
bind
与 call、apply 相同之处在于改变函数上下文,不同之处在与 call、apply 是调用,而 bind 会完全创建一个具有相同函数体和作用域的函数,称为绑定函数
window.color = 'red' var o = { color: 'blue' } function sayColor() { alert(this.color) } var objectSayColor = sayColor.bind(o) objectSayColor() //blue
事件
当函数被用作事件处理函数时,它的this指向触发事件的元素。
箭头函数中的 this
箭头函数里的this是引用上一级的this。以下是几个需要注意的地方
- 函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象。
- 不可以当作构造函数,也就是说,不可以使用 new 命令,否则会抛出一个错误。
- 不可以使用arguments对象,该对象在函数体内不存在。如果需要可以用Rest参数代替。
- 不可以使用yield命令,因此箭头函数不能用作 Generator 函数。
如果是普通函数,执行时this应该指向全局对象 window,这时应该输出 21。但是,箭头函数导致 this 总是指向函数定义生效时所在的对象(本例是 {id: 42}
),所以输出的是42。
const id = 21 function foo() { setTimeout(() => { console.log('id:', this.id) }, 100); } foo.call({ id: 42 }) // id: 42
封装回调函数。以下代码的 init 方法中,使用了箭头函数,这导致这个箭头函数里面的 this,总是指向 handler 对象。否则,回调函数运行时,this.doSomething 这一行会报错,因为此时 this 指向 document 对象。
var handler = { id: '123456', init: function() { document.addEventListener('click', event => this.doSomething(event.type), false); }, doSomething: function(type) { console.log('Handling ' + type + ' for ' + this.id); } }
优先级
new 绑定 > 显式绑定 > 隐式绑定
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论