this指向以及call、bind、apply的重写

38 阅读1分钟

this指向问题:

  1. 默认情况下,this指向window;
  2. 严格模式下,this值为undefined;
  3. 在事件回调函数中,this指向事件源;
  4. 箭头函数本身没有this,会向最外层查找,如果找不到就指向window;
  5. 在构造函数中,this指向构造函数创建的对象实例;
  6. 在Vue2框架中,this指向组件实例;
  7. 在对象的方法中,this指向当前对象;

如何改变this指向: 使用call、bind、apply;

call的重写:

var a = 123;
    function f1(...arg) {
        const a = this.a;
        const obj = {
            src: this,
            a,
            arg: [...arg]
        }
        return obj;
    }

    const obj = {
        a: 1
    }

    Function.prototype.callFn = function(reidrectObj, ...arg) {
        const symbol = Symbol('_fn')
        reidrectObj[symbol] = this;
        const result = reidrectObj[symbol](...arg);
        Reflect.deleteProperty(reidrectObj, symbol);
        return result;
    }

    console.log(f1.callFn(obj, 8))
    /*
        输出结果:
            {
                a: 1,
                arg: [8],
                src: {
                    a: 1
                }
            } 
    */

    console.log(f1(9))
    /*
        输出结果:
            {
                a: 123,
                arg: [9],
                src: window { window: Window, self: Window, document: document, name: '', location: Location, ... }
            }
    */

bind的重写:

var a = 123;
    function f1(...arg) {
        const a = this.a;
        const obj = {
            src: this,
            a,
            arg: [...arg]
        }
        return obj;
    }

    const obj = {
        a: 1
    }

    Function.prototype.bindFn = function (reidrectObj) {
        const symbol = Symbol('_fn')
        reidrectObj[symbol] = this;
        return reidrectObj[symbol];
    }

    console.log(f1.bindFn(obj)(123, 456), obj)
    /*
        输出结果:
            {
                a: 123,
                arg: [123,456],
                src: window { window: Window, self: Window, document: document, name: '', location: Location, ... }
            }
    */

apply的重写:

 var a = 123;
    function f1(...arg) {
        const a = this.a;
        const obj = {
            src: this,
            a,
            arg: [...arg]
        }
        return obj;
    }

    const obj = {
        a: 1
    }

    Function.prototype.applyFn = function(reidrectObj, arg = []) {
        const symbol = Symbol('_fn')
        const v = Array.isArray(arg) ? arg : [];
        let argList = [];
        if(Array.isArray(arg)) {
            argList = arg;
        } else {
            if(typeof arg === 'object') {
                if (!arg) {
                    throw new Error('CreateListFromArrayLike called on non-object');
                }
                argList = Array.from(arg);
            }
        }
        reidrectObj[symbol] = this;
        const result = reidrectObj[symbol](...argList);
        Reflect.deleteProperty(reidrectObj, symbol);
        return result;
    }

    console.log(f1.applyFn(obj, [1,2,3]))
    /*
        输出结果:
            {
                a: 1,
                arg: [1, 2, 3],
                src: {
                    a: 1
                }
            } 
    */

    console.log(f1([9]))
    /*
        输出结果:
            {
                a: 123,
                arg: [[9]],
                src: window { window: Window, self: Window, document: document, name: '', location: Location, ... }
            }
    */