1. this基础
除去不常用的with和eval,this的指向大致可以分为4种
- 作为对象的方法调用
- 作为普通函数调用
- 构造器调用
- Function.prototype.call 或者 Function.prototype.apply调用
1.1 作为对象的方法调用 - this 指向该对象
var obj = {
a: 1,
getA: function() {
console.log(this === obj)
}
}
obj.getA() // true
1.2 作为普通函数调用 - this 总是指向全局对象
window.name = 'globalName'
var getName = function() {
return this.name
}
console.log(getName()) // globalName
window.name = 'globalName'
var myObject = {
name: 'test',
getName: function() {
return this.name
}
}
var getName = myObject.getName
console.log(getName()) // globalName
1.3 构造器调用
通常情况下: this 指向返回的这个对象
如果构造器显示的返回了一个object类型的对象,那么此次结果最终会返回这个对象,而不是this
var MyClass = function() {
this.name = 'sven'
}
var obj1 = new MyClass()
console.log(obj1.name) // 'sven'
var MyClass = function() {
this.name = 'sven'
return { //显示的返回了一个object类型的对象
name1: 'sven111'
}
}
var obj1 = new MyClass()
console.log(obj1.name) // sven111
1.4 Function.prototype.call 或 Function.prototype.apply 调用 - 动态地改变传入函数的this
var obj2 = {
name: 'sven',
getName: function() {
return this.name
}
}
var obj3 = {
name: 'anne'
}
console.log(obj2.getName()) // sven
console.log(obj2.getName.call(obj3)) // anne
2. call和apply
- apply 使用率更高,因为不用考虑数量
call(null, a, b, c)
apply(null, [a, b, c])
- 在 call 或者 apply的时候,如果第一个参数是null,函数体的this会指向默认的宿主对象,在浏览器中则是window
- 有时候使用call或者apply的目的不在于指定this指向,而是另有用途,比如借用其他对象的方法,那么可以传入null来代替某个具体的对象
console.log('Math.max.apply(null, [1, 2, 3, 4, 5])', Math.max.apply(null, [1, 2, 3, 4, 5])) // 5
console.log('[].shift.apply()', [].shift.call([1, 2, 3, 4, 5])) // 1
- call 和 apply 的用途
- 改变this指向
- Function.prototype.bind
- 借用其他对象的方法
2.1 改变this的指向
var test1 = {
name: 'sven'
}
var test2 = {
name: 'anne'
}
window.name = 'window'
var getName1 = function() {
console.log(this.name)
}
getName1() // window
getName1.call(test1) // sven
getName1.call(test2) // anne
2.2 Function.prototype.bind
Function.prototype.bind = function() {
var self = this, // 保存原函数
context = [].shift.call(arguments), // 需要绑定的this上下文
args = [].slice.call(arguments) // 剩余参数转成数组
return function() {
return self.apply(context, [].concat.call(args, [].slice.call(arguments)))
// 执行新的函数的时候,会把之前传入的context当做形函数体内的this
// 并且组合两次分别传入的参数,作为形函数的参数
}
}
var applyObj = {
name: 'sven'
}
var func = function(a, b, c, d) {
console.log('this.name', this.name)
console.log('qqqqqqq', [a, b, c, d])
}.bind(applyObj, 1, 2)
func(3, 4) // this.name sven qqqqqqq [1, 2, 3, 4]
2.3 借用其他对象的方法
- 借用构造函数:通过这种技术,可以实现一些类似继承的效果
- 借用一些object的方法
var ObjA = function(name) {
this.name = name
}
var ObjB = function() {
ObjA.apply(this, arguments)
}
ObjB.prototype.getName = function() {
return this.name
}
var b = new ObjB('test')
console.log('b', b.getName()) // test
// Array.prototype.push
var pushTest = function() {
Array.prototype.push.call(arguments, 1)
console.log('arguments', arguments)
}
pushTest(3, 4) // [3, 4, 2, 1]