**this 只有在执行的时候才能被确认,定义时无法确认。**函数执行时,this总是指向调用该函数的对象(即:判断this所在的函数属于谁)
1、作为对象属性执行
函数有所属对象,则指向所属对象
Var myObject = {
value: 100
}
myObject.getValue = function () {
console.log(this.value);
console.log(this)
return this.value;
}
console.log(myObject.getValue());
这里的getValue属于对象 myObject,所以this 就指向了 myObject,执行结果:
var name = '李四'
var person = {
name: '张三',
getName () {
console.log(this.name); // 这个this是啥不知道,因为还没调用
}
}
person.getName(); // 此时的this为person,作为对象属性执行,输出 张三
2、作为构造函数执行
使用构造器new 一个对象时,this就指向新对象:
function foo (name) {
this.name = name // 此时的this === {}
}
var f = new foo('张三') // foo {name: "张三"}
3、作为普通函数执行
函数没有所属对象时,就指向全局对象(window或global)
var myObject = {
value:100;
}
myObject.getValue = function () {
var foo = function () {
console.log(this.value);
console.log(this)
}
foo();
return this.value
}
console.log(myObject.getValue())
在这里,foo属于全局对象,所以foo函数打印的this.value为undefined。
setTimeout 和 setInterval 也属于全局对象的,所以这两个函数体内的this 是指全局的。
var myObject = {
value: 100
}
myObject.getValue = function () {
setTimeout(function () {
console.log(this.value)
console.log(this)
}, 0)
return this.value
}
console.log(myObject.getValue());
执行结果:
所以,如果要得到想要的结果,就要这样写:
var myObject = {
value: 100
}
myObject.getValue = function () {
let self = this
setTimeout(function () {
console.log(self.value)
console.log(self)
}, 0)
return this.value
}
console.log(myObject.getValue());
执行结果如下:
es6 中箭头函数的妙用(this绑定的是定义时所在的作用域,而不是运行时所在的作用域;箭头函数其实没有自己的this,所以箭头函数内部的this就是外部的this),如下:
var myObject = {
value: 100
}
myObject.getValue = function () {
setTimeout(() => {
console.log(this.value)
console.log(this)
}, 0)
return this.value
}
console.log(myObject.getValue());
执行结果同上。
var name = '李四';
var person = {
name: '张三',
getName () {
console.log(this.name)
}
}
var per = person.getName();
per();
// 此时输出李四而不是张三,this已经是window了,在全局作用域中定义了name变量,自然输出全局的name
// 而不是person的name
4、setTimeout 中this的指向
function method() {
alert(this.value); // 输出 42 第二个this
}
function Foo() {
this.value = 42;
setTimeout(this.method, 500); // 这里this指向window 第一个this
}
Foo();
var obj = {
name: 'hutaoer',
say: function() {
var self = this;
setTimeout(function(){
alert(self); // 输出 object ,指向obj
alert(this); // 第二个this,指向window,我心永恒,从未改变
alert(self.name) // 输出 hutaoer
}, 0)
}
}
obj.say();
一、setTimeout中的延迟执行代码中的this 永远 都指向window
二、
setTimeout(this.method, time)
这种形式中的this,即上文中提到的第一个this,是根据上下文来判断的,默认为全局作用域,但不一定总是处于全局下,具体问题具体分析。三、setTimeout(匿名函数, time)这种形式下,匿名函数中的变量也需要根据上下文来判断,具体问题具体分析。
5、call,apply,bind可以改变this的指向
var p1 = {
name: '张三',
getName(age, job) {
console.log(this.name, age, job);
}
};
var p2 = {
name: '李四'
};
p1.getName.call(p2, 18, '前端工程师'); // 输出 李四18前端工程师
p1.getName.apply(p2, [18, '前端工程师']); // 输出 李四18前端工程师
p2.getName = p1.getName.bind(p2);
p2.getName(18, '前端工程师'); // 输出 李四18前端工程师
var myObject = {
value: 100
}
var foo = function () {
console.log(this)
console.log(this.value)
console.log('...........')
}
foo();
foo.apply(myObject)
foo.call(myObject)
var newFoo = foo.bind(myObject) // bind返回的是一个函数
newFoo();
foo 本来指向全局对象window,但是call,apply 和 bind 将this绑定到了myObject 上,所以,foo里面的this就指向了myObject。执行结果:
call、bind、apply区别:
call、bind、apply 这三个函数的第一个参数都是 this 的指向对象,第二个参数的差别:
call
的参数是直接放进去的,第二第三第n个参数全都是逗号分隔,直接放到后面 obj.myFun.call(db, '好好', ...., 'string')
;
apply
的所有参数必须放在一个数组里面传进去 obj.myFun.apply(db, ['好好', ...., 'string'])
;
bind
除了返回的是函数外,它的参数和 call 一样。
三者的参数不限定是 string 类型,允许是各种类型,包括函数、object等。
记忆技巧
函数调用
JS(ES5)里有三种函数调用的形式:
func(p1, p2)
obj.child.method(p1, p2)
func.call(context, p1, p2)
记住,第三种调用形式才是正常调用形式,其他两种都是语法糖,可以等价的变为call 形式:
func(p1, p2) // 等价于
func.call(undefined, p1, p2)
obj.child.method(p1, p2) // 等价于
obj.child.method.call(obj, p1, p2)
至此,函数调用只有一种形式:我们称此为 [ 转换代码 ]
func.call(context, p1, p2)
这样,this就好解释了。
this就是 call 一个函数时传的 context。
function func () {
console.log(this)
}
func()
用转换代码转一下
function func () {
console.log(this)
}
func.call(undefined) // func.call()
所以this 就是undefined,但是浏览器有一条规则:
如果传的context是 null 或 undefined,那么window 对象就是默认的context(严格模式下默认context 是 undefined)
如果希望this 不是 window,
func.call(obj) // this -> obj
obj.child.method(p1, p2)
var obj = {
foo: function() {
console.log(this)
}
}
obj.foo()
转换
obj.foo.call(obj)
所以,this 就是 obj。
实例:
var obj = {
foo: function() {
console.log(this)
}
}
var bar = obj.foo()
obj.foo() // 转换 : obj.foo.call(obj) ,this 就是obj
bar() // 转换:bar.call() ,this 就是 window
[ ] 语法
function fn () {console.log(this)}
var arr = [fn, fn2]
arr[0]()
可以把 arr[0]() 想象成 arr.0(),后者语法错误,但是形式与转换代码里的 obj.child.method(p1, p2) 一致,所以
arr[0]()
假想成 arr.0()
转换 arr.0.call(arr)
所以 this 就是指 arr
箭头函数
实际上箭头函数没有 this,如果在箭头函数里发现了 this,就直接当作箭头函数外的 this 即可。箭头函数内外 this 就是同一个。