一、this
例子1
var name = "windowName"
function getName() {
var name = "jack"
console.log(this.name) // windowName
console.log("inner", this) // window
}
getName()
console.log("outer", this) // window
this.name
是windowName
,因为调用的对象是window,getName()
相当于 window.getName()
。如果使用严格模式的话,全局对象就是 <font color="red">undefined</font>
例子2
let name = "windowName"
let user = {
name: 'jack',
getName: function () {
console.log(this.name) // this 指向jack
}
}
user.getName()
getName
这个函数对象user
调用的,应证了那句话“this
永远指向最后调用它的那个对象”
例子3
var name = "windowName"
var user = {
name: null,
getName: function () {
console.log(this.name) // windowName
}
}
var fn = user.getName
fn()
因为把函数赋值给了fn,getName
并没有调用,最后还是相当于window
调用了这对方法,所以结果是 windowName
(<font color="red">
不要在严格模式下</font>
)
this
的指向并不是在创建的时候就可以确定的,在 es5 中,永远是this 永远指向最后调用它的那个对象。
二、改变this的指向
- 备份指针
- 箭头函数
- apply、call、bind
例子4
name = "windowName"
var user = {
name: null,
getName: function () {
console.log(this.name)
},
test: function () {
setTimeout(function () {
this.getName() // 报错 TypeError: this.getName is not a functionvar
}, 100)
}
}
user.test()
在不使用箭头函数的情况下,是会报错的,因为最后调用 setTimeout
的对象是 window
,但是在 window
中并没有 func1
函数。
(1)箭头函数
箭头函数的 this
始终指向函数定义时的 this
,而非执行时。
var name = "windowName"
var user = {
name: "jack",
getName: function () {
console.log(this.name) // this 指向jack
},
test: function () {
setTimeout(() => {
this.getName()
}, 100)
}
}
user.test()
箭头函数修正了this
的指向
(2)备份指针
var name = "windowName"
var user = {
name: "jack",
getName: function () {
console.log(this.name) // tack
},
test: function () {
var self = this // 备份指针
setTimeout(function () {
self.getName()
}, 100)
}
}
user.test()
(3)apply、call、bind
使用 apply、call、bind
函数也是可以改变 this
的指向的
使用apply
var user = {
name: "jack",
getName: function () {
console.log(this.name) // jack
},
test: function () {
setTimeout(function () {
this.getName()
}.apply(user), 100)
}
}
user.test()
使用call
var user = {
name: "jack",
getName: function () {
console.log(this.name) // jack
},
test: function () {
setTimeout(function () {
this.getName()
}.call(user), 100)
}
}
user.test()
使用bind
var user = {
name: "jack",
getName: function () {
console.log(this.name) // jack
},
test: function () {
setTimeout(function () {
this.getName()
}.bind(user)(), 100)
}
}
user.test()
(4)apply、call、bind 区别
apply()
方法调用一个函数, 其具有一个指定的this
值,以及作为一个数组(或类似数组的对象)提供的参数
语法
func.apply(thisArg, [argsArray])
- thisArg
可选的。在func
函数运行时使用的this
值。请注意,this
可能不是该方法看到的实际值:如果这个函数处于非严格模式下,则指定为null
或undefined
时会自动替换为指向全局对象,原始值会被包装。 - argsArray 可选的。一个数组或者类数组对象,其中的数组元素将作为单独的参数传给
func
函数。如果该参数的值为null
或undefined
,则表示不需要传入任何参数。从ECMAScript 5 开始可以使用类数组对象。 浏览器兼容性 请参阅本文底部内容。 - 返回值 调用有指定
this
值和参数的函数的结果。
(5)call 和 apply的区别
apply
和 call
基本类似,他们的区别只是传入的参数不同。
fun.call(thisArg[, arg1[, arg2[, ...]]])
call
方法接受的是若干个参数列表,而 apply
接收的是一个包含多个参数的数组。
例子 (apply)
var operation = {
sum: function (a, b) {
console.log(a + b) // 3
}
}
var a = operation.sum
a.apply(operation, [1, 2])
例子 (call)
var operation = {
sum: function (a, b) {
console.log(a + b) // 3
}
}
var a = operation.sum
a.call(operation, 1, 2)
(6)bind 和 apply、call 区别
还是刚刚的例子
var operation = {
sum: function (a, b) {
console.log(a + b) // 3
}
}
var a = operation.sum
a.bind(operation, 1, 2)()
(7)创建对象时候使用call
function Person(name, age) {
this.name = name
this.age = age
}
var person = new Person('jack', 18)
person.name // jack
简单的来看一下 new 的过程吧:
var person = new Person('jack', 18)
new Person {
var obj = {}
obj.__proto__ = myFunction.prototype;
var result = myFunction.call(obj,"jack","18");
return typeof result === 'obj'? result : obj;
}
- 创建一个空对象
- 将新创建的空对象的隐式原型指向其构造函数的显示原型
- 使用
call
改变this
的指向 - 如果无返回值或者返回一个非对象值,则将
obj
返回作为新对象;如果返回值是一个新对象的话那么直接直接返回该对象。