前端this指向问题总结

1、this的五种情况分析(this是执行主题,就是谁把他执行的,和在哪创建在哪执行都没关系)
  • 函数执行:看方法执前边是否有点,如果没有点指向window(严格模式下指向undefined)。有点,点前边是谁,this就指向谁。
const fn=function func(){
    console.log(this);
}
const obj={
    name: 'ling',
    fn:fn,
}
fn();// this是window
obj.fn();// this是obj
  • 给某个元素的某个事件行为绑定方法,当事件行为触发,方法中的this是当前元素本身,排除attachEvent。
document.body.addEventListener('click', function(){
    console.log(this); // this是body
})
  • 构造函数体中的this是当前类的实例。

  • 箭头函数没有执行主题,所用到的this都是所处上下文的this。

const demo={
    name: 'demo',
    fn(){
        console.log(this); //点前边是demo执向demo
        setTimeout(function(){
            console.log(this); // 函数执行前边没点,执向window
        }, 1000);
        setTimeout(()=>{
            console.log(this);// 指向上级demo
		}), 1000);
    }
}
demo.fn();
  • 可以基于Function.prpototype上的call/apply/bind去改变this指向。
function func(this, x, y){
    console.log(this, x, y);
}
let obj={
    name: 'ling',
}
func通过原型链__proto__找到Function.prototype.call。去执行call。call作用就是将func的this改为第一个参数。并且把params实参传给func,让func函数立即执行。
func.call(obj, 1, 2);

apply和call类似,只不过传参是数组。

bind方法则和二者不太一样:

  • bind修改this不会立即执行。
  • 把传进来信息obj,和参数存储起来,闭包。
  • 执行bind返回一个新函数例如,proxy。
document.body.addEventListener('click', fnc.bind(obj, 1, 2, 3));

把proxy绑定给元素的事件,当事件触发执行是返回的proxy,在proxy内部再去执行func,并把this和参数都改为上边存储的值。(把传进来信息obj,和参数存储起来,闭包。)

2、手写call、bind

手写call,改变this,就是函数执行前边有点,点前边有东西。并且不影响原本属性,使用symbol唯一key来处理。原理就是点定this机制。

Function.prototype.call=function call(context, ...params){
    const self=this; // 此处this是call前函数
    const key=Symbol('key');
    let result;
    context[key]=self;
    result=context[key](...params); // 函数执行,函数前边点是context传进来改变this值。
    delete context[key]; // 处理结束不影响原函数,删除该属性。
    return result;
}
const obj={name: '123'}
function func(num1, num2){
    console.log(this, num1, num2); //{name: 123}, 1, 2
};
func.call(obj, 1,2,3);// call前有func,此时this是func函数。

此时绑定基本数据类型值是存在问题的,做如下优化。

Function.prototype.call=function call(context, ...params){
    const self=this; // 此处this是call前函数
    const key=Symbol('key');
    let result;
    context==null?context=window:null;
    !/^(object|function)$/i.test(typeof context)?context=Object(context):null;//处理基本数据类型,改为对象
    context[key]=self;
    result=context[key](...params); // 函数执行,函数前边点是context传进来改变this值。
    delete context[key]; // 处理结束不影响原函数,删除该属性。
    return result;
}
  • 手写bind
Function.ptototype.bind=function bind(context, ...params){
    const self=this;
    return function proxy(...arg){//arg是proxy执行时候可能存在参数,event
        self.apply(context, params.concat(arg));
    }
}
  • 柯里化函数思想:就是将上下文需要用到的参数,提前存起来,就是柯里化函数思想,比如bind实现时候,需要先将this也即是执行函数存起来。
3、掌握this的好玩应用,像鸭子

就是类数组和数组差不多,但是数组东西无法使用,比如slice,forEach等

[].forEach.call(arguments, item=>{console.log(item)});
//相当于Array.prototype.forEach
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值