this的指向是动态的,只有在函数调用时才能够确定(跟函数的调用模式相关),函数申明时并不能确定this的指向
1函数调用
let function fn(){
console.log(this)
}
fn()
//this->Window
2方法调用
let obj{
fn:function(){
console.log(this)
}
}
obj.fn() //this->obj
let function fn(){
console.log(this)
}
let obj{
fn:fn
}
obj.fn()
//this->obj
obj['fn']()
//this->obj
setTimeout是Window中的一个方法,
是Window.setTimeout(fn(),50)简写形式
所以this其实还是指向调用他的对象Window
setTimeout(function () {
console.log(this);//Window
}, 50);
事件中的this指向当前元素,浏览器让当前元素调用了function
3构造函数调用
function Person(name, age) {
this.name = name
this.age = age
}
let p = new Person('zs', 20)
console.log(p); //Person {name: "zs", age: 20}
//this->Person的实例p
4借用(call,apply,bind)
call()的作用有两个,一是调用函数,二是更改函数的this指向
function fn() {
console.log(1);
console.log(this);
}
let zs = {
money: 10
}
fn.call() // 1 Window
fn.call(zs) // 1 {money: 10}
call()的第一个参数设定this的指向,后面的参数为fn的实参
因为其更改this指向的特性,可以实现借用方法
let zs = {
money: 10,
liaomei: function () {
console.log('走,哥有' + this.money + '块,我们去酒吧撩妹');
}
}
let ls = {
money: 1000
}
zs.liaomei() //走,哥有10块,我们去酒吧撩妹
zs.liaomei.call(ls) //走,哥有1000块,我们去酒吧撩妹
//借用之后ls还是没有liaomei方法
function fn(m, n) {
console.log(this);
console.log(m + n);
}
fn(1, 2) // 3 Window
fn.call({name: 'zs'}, 10, 20) // 30 {name: "zs"}
fn.apply({name: 'ls'}, [100, 200]) // 300 {name: "zs"}
//注意apply的第二个参数,必须是数组
//apply使用场景较少,参数已经放在数组或伪数组里才使用
比如求数组最大值
arr = [1, 2, 3, 4, 5, 6, 7]
let res1 = Math.max(1, 2, 3, 4, 5, 6, 7)
let res2 = Math.max(arr)
let res3 = Math.max.apply(arr, arr)
console.log(res1); // 7
console.log(res2); // NaN Math.max参数要求为一项一项的数值
console.log(res3); // 7
//借用max方法,第一个arr参数改变this指向借用,第二个arr参数apply展开平铺
bind方法仅改变函数的指向,并返回一个和原函数一模一样的函数,不调用函数(不常用)
let user = {
uname: 'zs',
pwd: '123456',
login: function () {
let fn = function () {
console.log('用户' + this.uname + '的密码为' + this.pwd);
}
setInterval(fn, 1000); //fn中this的指向为Window
}
}
user.login() // 用户undefined的密码为undefined
let user1 = {
uname: 'zs',
pwd: '123456',
login: function () {
let fn = function () {
console.log('用户' + this.uname + '的密码为' + this.pwd);
}.bind(this) //仅改变了函数内this的指向,返回给fn
//bind(this)中的this->user1
setInterval(fn, 1000);
}
}
user1.login() // 用户zs的密码为123456
衍伸
借用构造函数继承
function Person(name, age, gender) {
this.name = name
this.age = age
this.gender = gender
}
function Chinese(name, age, gender, skin) {
Person.call(this, name, age, gender) // this指向Chinese的实例
this.skin = skin || 'yellow'
}
let zs = new Chinese('张三', 20, 'male')
console.log(zs); //Chinese {name: "张三", age: 20, gender: "male", skin: "yellow"}