this
的五种不一样情形在默认的,纯粹的函数调用时,视做全局性调用,此时的this指向全局对象Global,在浏览器环境下,也即window对象。json
window.x = 'Jackie' function func() { console.log(this.x) } func() // Jackie
在严格模式("use strict"
)下,会禁止this
指向全局对象,此时的this
会是undefined
。数组
此时this
指向调用这个方法的对象。浏览器
var x = 'Property of Window' var obj = {} obj.x = 'Property of obj' obj.f = function () { console.log(this.x) } obj.f() // Property of obj // 值得注意的状况 var f = obj.f f() // Property of Window
call
、apply
和bind
的显式绑定call
、apply
和bind
均可以改变一个函数的this
指向。app
call
和apply
call
和apply
会将它们的调用对象的this
指向它们的第一个参数。函数
function f () { console.log(this.x) } var x = 'Property of Window' var obj = { x: "Property of obj" } f.apply(obj) // "Property of obj"
当传入的第一个参数为undefined,或者不传入参数时,在非严格模式下,自动会将this
指向全局对象Global,在浏览器里是window
对象,严格模式下则会是undefined
:this
function f () { console.log(this) } f.apply() // window f.apply(undefined) // window function ff () { 'use strict' console.log(this) } ff.apply() // undefined ff.apply(undefined) // undefined
call
和apply
没有本质区别。惟一的区别在于:prototype
call()
方法接受的是若干个参数的列表,而apply()
方法接受的是一个包含多个参数的数组。指针
bind
bind
和前面二者也并未有什么本质的区别,只不过bind
将第一个参数绑定当调用函数的this
上,并将这个函数返回(不执行)。code
function f () { console.log(this.x) } var x = 'Property of Window' var obj = { x: "Property of obj" } var ff = f.bind(obj) ff() // "Property of obj"
当一个函数被当作构造函数,用new
关键字新建一个对象的时候,这个函数内部的this
以及原型链上的this
都会指向这个新建的对象。对象
function Jackie(para) { this.para = para console.log(this) } Jackie.prototype.log = function(){ console.log(this) } Jackie('hehe') // Window var p = new Jackie('haha') // Jackie {para: "haha"} p.log() // Jackie {para: "haha"}
JavaScript中超时调用的代码都是在全局做用域中执行的,所以函数中this的值会指向window对象,在严格模式下也同样。由于超时调用的代码都会有一个隐式绑定:setTimeout(f, time) == setTimeout(f.bind(window), time)
。
"use stric" var x = 'Property of Window' var obj = {} obj.x = 'Property of obj' obj.ff = function () { setTimeout( function () { console.log(this.x) }, 100) } obj.ff() // Property of Window // 能够这么解决问题 obj.fff = function () { var that = this setTimeout( function () { console.log(that.x) }, 100) } obj.fff() // Property of obj
事件监听函数中的this
指向监听对象。
var one = document.getElementById('one') one.onclick = function () { console.log(this) }; one.click() // <div id="one"></div>
箭头函数中this
的指向,在函数定义时即绑定完毕,且后续没法更改。
var obj = { x: 1 } var f1 = () => { console.log(this) } f1.apply(obj) // Window var f2 = function () { var f3 = () => { console.log(this) } return f3 } var f4 = f2.apply(obj) f4() // Object {x: 1}
一个更神奇的例子,超时调用的代码在定义时,绑定了this
的指向。
function foo() { setTimeout(() => { console.log('id:', this.id); }, 100); } var id = 21; foo.call({ id: 42 }); // id: 42
var obj = {x: 0, name: 'obj'} var robj = {x: -1, name: 'robj'} var factory = function (x) { this.x = x console.log(this) } var factoryBind = factory.bind(obj) robj.factory = factoryBind robj.factory(2) // Object {x: 2, name: "obj"},做为方法的绑定的优先级低于bind的显式绑定 factoryBind.call(robj, 3) // Object {x: 3, name: "obj"},call的优先级低于bind console.log(robj) // Object {x: -1, name: "robj", factory: function},未对robj进行修改 console.log(obj) // Object {x: 3, name: "obj"},修改的是obj,由于this指针指向未变化 var p = new factoryBind(4) // factory {x: 4} console.log(p) // factory {x: 4} console.log(obj) // Object {x: 3, name: "obj"},构造函数绑定的优先级高于bind的显式绑定
能够见得,优先级从高到低:
new
,构造绑定
bind
,显式绑定
call
/apply
,显示绑定
做为方法绑定
默认绑定