this指向
this 是 函数中 天生就有的 一个属性
是 js 程序 自动设定生成的
所谓的this指向
this本质上是 指针操作
this的指针指向谁 this就是谁
就可以通过 this 操作谁
this指向分类
普通函数
除了箭头函数之外 其他所有的函数语法形式 都开始 普通函数语法形式
按照 js程序规定的 设定 函数的this指向
JavaScript中this指向的规定非常复杂
实际项目中 函数的this指向 是一个非常复杂的结果 实在不行 就 console.log( this ) 输出看看
情况1
this指向是 window对象
实际操作通用一般没啥用
声明式函数 赋值式函数 数组的forEach 定时器 延时器....
情况2
this指向是 事件源标签对象
在 事件处理函数中 this指向 是 事件源标签对象
也就是 绑定事件的标签对象
情况3
this指向是 数组/对象
存储在数组或者对象中的函数
this指向 是存储这个函数的 数组/对象
// 情况1 this指向是 window对象
// 声明式函数
function fun1 (){
// this是函数天生就有的属性
// 在函数内部可以直接输出查看函数当前的this指向
console.log( this );
}
fun1();
// 匿名函数
const fun2 = function(){
console.log( this );
}
fun2();
const arr = [100,200,300,400,500,600];
// 使用匿名函数的形式 给 forEach的回调函数赋值
arr.forEach( function( item ){ console.log( item , this ) } );
// 定时器 延时器
setInterval( function(){ console.log( this ) } , 1000 );
setTimeout( function(){ console.log( this ) } , 1000 );
// 存储在 数组中的函数
const arr = [100,200,300,function(){ console.log( this ) }];
// 调用执行存储在数组中的函数
arr[3]();
console.log( arr );
// 存储在 对象中的函数
const obj = {
name:'张三',
age:18,
sex:'男',
ff:function(){ console.log( this ) }
};
// 调用存储在对象中的函数
obj.ff() ;
console.log( obj );
箭头函数
箭头函数的this指向
箭头函数 本身 没有this指向
箭头函数的this指向 是 父级程序的this指向
如果箭头函数没有父级程序 或者 父级程序没有this指向
箭头函数的this指向 是 window
//情况1 事件处理函数的this指向
// 获取div标签对象 绑定点击事件
const oDiv = document.querySelector('div');
// 使用 匿名函数 给 div标签绑定点击事件
// 事件处理函数 是 匿名函数 this指向是 事件源标签对象
// 也就是div标签对象
oDiv.addEventListener( 'click' , function(){ console.log( this ) });
// 使用 箭头函数 给 div标签绑定点击事件
// 事件处理函数 是 箭头函数 this指向是 window
// 箭头函数的this指向是父级程序
// 当前 事件绑定语法 没有 父级程序
// 箭头函数this指向是 window
oDiv.addEventListener( 'click' , () => { console.log( this ) });
// 存储在对象中的箭头函数
const obj = {
name:'张三',
age:18,
sex:'男',
// 在对象中存储匿名函数
// 匿名函数的this指向是 存储这个函数的对象obj
f1:function(){
console.log( this );
// 在函数f1中声明一个 赋值式函数
// 赋值式函数 当前使用的是 匿名函数语法形式
// this指向是window
const f3 = function(){ console.log( this ) };
f3();
// 在函数f1中声明一个 赋值式函数
// 赋值式函数 当前使用的是 箭头函数语法形式
// this指向 是 父级程序的this指向
// 父级程序是 函数f1
// 函数f1 有 this指向 指向存储函数f1的对象obj
// 箭头函数f4 this指向就是 父级程序函数f1的this指向
// 就是 对象obj
const f4 = ()=>{ console.log( this ) };
f4();
},
// 在对象中存储箭头函数
// 箭头函数的this指向是 父级程序
// 当前箭头函数的父级程序是 对象obj
// 对象obj 没有 this指向
// 箭头函数f2 的 this指向 是 window
f2:()=>{ console.log( this ) },
};
obj.f1();
obj.f2();
改变 this 指向
箭头函数
箭头函数 不能改变this指向
箭头函数本身没有this指向 箭头函数的this指向是父级程序的this指向
普通函数
函数执行时
在 执行函数时 改变this指向
函数.call( 参数1 , 其他参数 );
参数1 新的this指向
其他参数 原始函数执行时需要输入的实参
如果原始函数需要输入多个实参
按照顺序一个一个的设定实参
函数.apply( 参数1 , 其他参数 );
参数1 新的this指向
其他参数 原始函数执行时需要输入的实参
以 数组 形式 设定原始函数需要的实参
如果原始函数需要输入多个实参
按照顺序一个一个的设定数组中存储的数据 作为 原始函数的实参
call()语法 和 apply()语法
只是 原始函数实参设定方式不同
执行效果 执行原理 都是完全相同
const obj1 = {
name:'张三' ,
age:18,
sex:'男',
addr:'北京',
// 匿名函数 this指向是 存储这个函数的对象obj
ff:function( a , b , c ){
// 匿名函数中 this指向 是 存储这个函数的对象obj
// this.name 也就是 obj.name 也就是 数据张三
console.log( this.name );
console.log( this.age );
console.log( this.sex );
console.log( this.addr );
console.log( a );
console.log( b );
console.log( c );
}
}
// 正常调用 对象obj1 中 存储的函数ff
// 因为 函数ff 的 this 指向是 存储函数ff的对象obj1
// 调用的 this.name this.age 等数据 都是 obj1 中 对应的数据
obj1.ff( 100 , 200 , 300 );
// 设定的 对象obj2
const obj2 = {
name:'李四' ,
age:20,
sex:'女',
addr:'广州',
};
// 通过 call 语法 在调用对象obj1中存储的函数ff时
// 强行 改变 对象obj1中存储的函数ff的this指向
// 让 函数ff 的this指向变成 对象obj2
// 函数ff中的程序 this.name this.age 等 调用的就是 obj2中 对应的数据
obj1.ff.call( obj2 , 'aaa' , 'bbb' , 'ccc' );
// 设定的 对象obj3
const obj3 = {
name:'王五' ,
age:22,
sex:'保密',
addr:'上海',
};
obj1.ff.apply( obj3 , [ 'ddd' , 'eee' , 'fff'] );
函数封装时
函数封装时 改变this指向
- 使用
bind语法声明封装一个新的函数 - 新函数和原始函数完全相同 只是 this指向 不同
function fun( a,b,c ){
console.log( this );
console.log( a,b,c );
}
fun( 100,200,300 );
const obj = { name:'张三' , age:18 , sex:'男' };
// 声明一个新函数
// 使用bind语法 声明一个新的函数
// 新的函数 代码程序内容 和 原始函数fun完全相同
// 只是 this指向 不同
// 声明一个新函数f1 新函数f1的程序代码和原始函数fun完全相同
// 只是this指向变成了 设定的对象obj
// 在声明封装新函数时 没有绑定原始函数的实参
const f1 = fun.bind( obj );
// 调用函数时 可以输入实参
f1( 'aaa' , 'bbb' , 'ccc' );
// 在声明封装函数时 绑定了原始函数的实参
const f2 = fun.bind( obj , '北京' , '上海' , '广州' );
// 直接调用函数 不用在输入实参了
f2();
// 绑定了实参 没办法再改变实参了
f2(300,400,500);