this apply call bind new
重要的话说三遍:
this永远指向最后调用它的对象
this永远指向最后调用它的对象
this永远指向最后调用它的对象
this的指向
EXAMPLE 1
var name = "windowsName"
function a() {
var name = "Cherry"
console.log(this.name) // windowsName
}
a()
a()是在全局作用域window下调用, 相当于window.a(), 所以this指向window.
EXAMPLE 2
var name = "windowsName"
var a = {
name: "Cherry",
fn: function() {
console.log(this.name) // Cherry
console.log("this: ", this)
}
}
window.a.fn() // 最后调用的对象是a
最后是由a对象调用fn(), 所以此时this指向a
EXAMPLE 3
var name = "windowsName"
var a = {
// name: "Cherry",
fn: function() {
console.log(this.name) // undefined
console.log('this: ', this); // a
}
}
window.a.fn()
最后调用fn()的对象是a,a里面没有name属性, 所以为undefined
EXAMPLE 4
var name = "windowsName"
var a = {
name: null,
fn: function() {
console.log(this.name) // "windowsName"
console.log("this: ", this) "window"
}
}
var f = a.fn
f()
a对象虽然将fn方法赋值给变量f了, 但是并没有调用, 最后是window对象调用的, 所以this指向window.(再来一次, this指向永远指向最后调用它的对象)
EXAMPLE 5
var name = "windowsName"
function fn() {
var name = "Cherry"
innerFunction()
function innerFunction() {
console.log(this.name) // windowsName
}
}
fn()
fn()最后是由window调用的 所以为window对象, 并且里面的innerFunction作为函数调用, 没有挂载在任何对象上, 这里的this就是指向window的.
改变this指向
- 通过ES6箭头函数
- 在函数内部使用
_this = this - 使用 apply \ call \ bind
- new
ES6箭头函数
- setTimeOut不使用箭头函数的问题
var name = "windowsName"
var a = {
name: "Cherry",
func1: function() {
console.log(this.name)
},
func2: function() {
setTimeout(function() {
console.log(this)
this.func1()
}, 100)
}
}
a.func2() // this.func1 is not a function
setTimeOut是由window来调用, window全局作用域里找不到func1这个方法, 所以为undefined.
- 使用箭头函数解决
箭头函数的this, 始终指向外层包裹箭头函数的第一个非箭头函数的this指向
var name = "windowsName"
var a = {
name: "Cherry",
func1: function() {
console.log(this.name)
},
func2: function() {
setTimeout(() => {
console.log(this) //Cherry
this.func1()
}, 100)
}
}
a.func2()
这个例子中, 箭头函数指向了外层的第一个非箭头函数func2. func2是由a对象调用的, 所以this指向了a对象.
划重点: 箭头函数中没有this指向, 必须通过查找作用域链来决定其值, 如果箭头函数被非箭头函数包含, 则this绑定的是最后一个非箭头函数的this, 否则为undefined.
使用_this
var name = "windowsName"
var a = {
name: "Cherry",
func1: function() {
console.log(this.name)
},
func2: function() {
var _this = this
console.log('_this: ', _this); // 这里的this是调用func的对象a, 为了防止在setTimeOut中被window调用而导致将this指向为window
setTimeout(function() {
_this.func1()
}, 100)
}
}
a.func2() // Cherry
这里的this是调用func()的对象a, 为了防止在setTimeOut中被window调用而导致将this指向为window
apply call bind
apply
var a = {
name: "Cherry",
func1: function() {
console.log(this.name)
},
func2: function() {
setTimeout(
function() {
this.func1()
console.log('this: ', this);
}.apply(a), // fn.apply(a)
100
)
}
}
a.func2() // Cherry
fun.apply(thisArg, [argsArray])
apply第二个可选参数为类数组
call
var a = {
name: "Cherry",
func1: function() {
console.log(this.name)
},
func2: function() {
setTimeout(
function() {
this.func1()
console.log('this: ', this);
}.apply(a), // fn.call(a)
100
)
}
}
a.func2() // Cherry
fun.call(thisArg[, arg1[, arg2[, ...]]])
call接受若干个参数列表
bind
var a = {
name: "Cherry",
func1: function() {
console.log(this.name)
},
func2: function() {
setTimeout(
function() {
this.func1()
console.log('this: ', this);
}.bind(a)(),
100
)
}
}
a.func2() // Cherry
fun.bind(thisArg[, arg1[, arg2[, ...]]])
bind接收参数和call一样, 但是bind返回一个函数, 需要手动调用
apply call bind
apply
apply() 方法调用一个具有给定this值的函数,以及作为一个数组(或类似数组对象)提供的参数。 (MDN)
第一个参数指定this指向, 指定null时会自动指向全局对象,(浏览器中就是window对象)
语法:
func.apply(thisArg, [argsArray])
const numbers = [1,2,3,4,5,6]
let max = Math.max.apply(null, numbers) // 6
let max = Math.max(...numbers) // 6
var a ={
name : "Cherry",
fn : function (a,b) {
console.log( a + b)
}
}
var b = a.fn;
b.apply(a,[1,2]) // 3
注意最后调用的参数方式
call
和apply基本一致, 第一个参数指定this指向, 指定null时会自动指向全局对象,(浏览器中就是window对象), 后面的可选参数, 传入参数不一样, call方法接受的若干个参数列表, apply接受一个包含多个参数的类数组
const numbers = [1,2,3,4,5,6]
let max = Math.max.call(null, 1, 2, 3, 4, 5, 6) // 6
let max = Math.max(...numbers) // 6
var a ={
name : "Cherry",
fn : function (a,b) {
console.log( a + b)
}
}
var b = a.fn;
b.call(a,1,2) // 3
注意最后调用的参数方式
bind
bind的方法和call的传参方式一样
第一个参数指定this指向, 指定null时会自动指向全局对象,(浏览器中就是window对象)
但是bind()方法创建一个新的函数, 所以必须手动调用
var a ={
name : "Cherry",
fn : function (a,b) {
console.log( a + b)
}
}
var b = a.fn;
b.bind(a,1,2)() // 3
new一个对象的过程
function person(arg1, arg2) {
this.firstName = arg1;
this.lastName = arg2;
}
let a = new person("phenix", "peng")
a.lastname; // peng
new关键字 创建一个实例对象的过程:
- 首先会创建一个空对象
obj - 将
obj的隐式原型__proto__指向构造函数的protoType显示原型对象 - 使用
call()方法改变this指向, 指向新创建的对象obj - 看第三步返回的是不是一个
Object对象, 如果非, 就返回新创建的对象obj, 如果是就返回这个对象.
伪代码如下:
new person {
var obj = {};
obj.__proto__ = person.prototype;
var result = person.call(obj,"Li","Cherry");
return typeof result === 'obj'? result : obj;
}
在new的过程中, call改变了this的指向.
总结
this指向
- ES5
- this永远指向最后调用它的对象
- this永远指向最后调用它的对象
- this永远指向最后调用它的对象
- ES6箭头函数
- 箭头函数没有this指针, 永远指向包裹着箭头函数的外层的第一个非箭头函数的this指向
apply call bind
- 可以用来改变this指向
- 第一个参数都是this指向
- 后面可选参数, 传参方式不一样, apply传类数组, call和bind是参数列表
- bind返回了一个函数, 需要手动调用
new
- new会改变this指向
- new对象的四步过程
- 创建空对象
- 原型指向构造函数的protoType
- 通过call改变this指向, 指向刚创建的对象
- 返回对象