JS中this的六种常用情况分析(手写call/apply/bind)

this的取值是什么,是在函数执行的时候确认的,不是函数定义的时候确认的!!!

this执行主体,谁把它执行的(和在哪创建&在哪执行都没有必然的关系)

this的五种使用情况分析

一、在普通函数中执行

        函数在全局执行中的this指向Window,(在严格模式下是undefined

function fn1() {
    console.log(this);
}
fn1(); //输出Window

二、作为对象方法被调用

        函数在对象中作为对象方法被调用中this指向该对象本身

function fn1() {
    console.log(this);
}

const OBJ = {
    name: 'OBJ',
    fn1: fn1
}

OBJ.fn1(); // 输出对象:OBJ

三、作为元素的某个事件行为的绑定函数,当事件行为触发时

        给当前元素的某个事件行为绑定函数,当事件行为触发,函数中的this是当前元素本身(attachEvent()中的this是Window

document.body.addEventListener('click', function () {
    console.log(this);
});

//点击浏览器中的body
//输出<body>...</body>

四、构造函数体中的this

        构造函数体中的this指向的是当前类的实例

//案例一:
function Fn() {
    this.name = '构造函数';
    this.age = 10;
    console.log(this);
}
let f = new Fn;

//案例二:
Array.prototype.log = function () {
    console.log(this);
}

let a = [1,2,3];
a.log()

案例一输出:

 案例二输出:

 五、箭头函数中的this

        箭头函数并没有属于自己的this,它所谓的this是捕获其所在上级作用域中的this,作为自己的 this 值,并且由于没有属于自己的this,所以是不会被new调用的(箭头函数无法new),这个所谓的this也不会被改变。

function fn1() {
    console.log(this);//输出OBj

    setTimeout(function () {
        console.log(this);//因为在setTimeout()中,输出Window
    },1000)

    setTimeout(() => {
        //箭头函数没有自己的this,所以其this指向的是上级作用域中的this:OBJ
        console.log(this);
    },2000)
}

const OBJ = {
    name: 'OBJ',
    fn1: fn1
}

OBJ.fn1();

输出:

 六、通过 Function.prototype 上的 call / apply / bind 改变的this

        通过基于Function.prototype上的call/apply/bind可以去改变this指向

function func(x, y) {
    console.log(this, x, y);
}
let OBJ = {
    name: 'OBJ'
};
func(1, 2); //输出Window 1 2

func.call(OBJ, 10, 20); //输出OBJ 10 20

func.apply(OBJ, [10, 20]); //输出OBJ 10 20

func.bind(OBJ, 10, 20)(); //输出OBJ 10 20

call的实现过程及其原理

        func函数基于__proto__找到Function.prototype.call,把call方法执行

        在call方法内部「call执行的时候」  call(context,...params)

               1、 把func中的this改为obj

               2、 并且把params接收的值当做实参传递给func函数

               3、 并且让func函数立即执行

手写call源码:

Function.prototype.call = function call(context, ...params) {
    let self = this,
        key = Symbol('KEY'),
        result;

    // 检测context是否为null或undefined
    context == null ? context = window : context;
    //检验context是否为对象
    /^(object|function)$/i.test(typeof context) ? null : context = Object(context);
    
    context[key] = self;
    result = context[key](...params);
    delete context[key];
    return result;
}

apply的实现过程及其原理

        和上文的call类似,只是传参的时候需要传一个数组:apply(context,params(Array))

手写apply源码:

Function.prototype.call = function call(context, params) {
    let self = this,
        key = Symbol('KEY'),
        result;

    // 检测context是否为null或undefined
    context == null ? context = window : context;
    //检验context是否为对象
    /^(object|function)$/i.test(typeof context) ? null : context = Object(context);
    
    context[key] = self;
    result = context[key](...params);
    delete context[key];
    return result;
}

bind的实现过程及其原理

        func函数基于__proto__找到Function.prototype.bind,把bind方法执行

                1、 和call/apply的区别:并没有把func立即执行

                2、 把传递进来的OBJ/10/20等信息存储起来「闭包」

                3、 执行bind返回一个新的函数

手写bind源码:

Function.prototype.bind = function bind(context, ...params) {
    let self = this;

    // 检测context是否为null或undefined
    context == null ? context = window : context;
    //检验context是否为对象
    /^(object|function)$/i.test(typeof context) ? null : context = Object(context);

    return function () {
        self.call(context, ...params);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值