js 基础 new 操作 、call、apply、bind (一)

218 阅读1分钟

一、new 操作

(1) 创建一个新对象;

(2) 将构造函数的作用域赋给新对象(因此 this 就指向了这个新对象) ;

(3) 执行构造函数中的代码(为这个新对象添加属性) ;

(4) 返回新对象。

function Person(name,age){
   this.name = name ;
   this.age = age ;
}
function rewriteNew(sup,...param){
    //1.创建新对象
    var obj = {};
    //2.将空对象作为 this,调用构造函数并传入参数
    var result = sup.call(obj,...param);
    //3.将该对象__proto__指向构造函数原型对象,实现继承
    obj.__proto__ = sup.prototype;//Object.setPrototypeOf(obj,sup.prototype)
    //4.如果构造函数返回值为对象或者函数,则返回该对象或者函数,否则返回创建的新对象obj
    return  typeOf result === "object" || typeOf result === "function"?result:obj
};
var jack = rewriteNew(Person,'jack',12);
console.log(jack);//{name:jack,age:12};

二、call、apply、bind

作用:都是修改this指向

差异:

(1)call与apply 参数不同:

// call 从第二个。。。依次列出参数  apply 第二个参数是数组
obj.myFun.call(db,'成都','上海');
obj.myFun.apply(db,['成都','上海']);  

(2)call、apply 与bind 差异为call、apply 修改this指向并且执行函数,bind只修改this指向但不立即执行函数,bind参数与call 一致

obj.myFun.call(db)
obj.myFun.apply(db);
obj.myFun.bind(db)();

1、手写一个call 方法

es5 写法
 Function.prototype.myCall1 = function(context){
    context = context || window
    context.fn = this;
    var args = [];
    for(var i = 1,len = arguments.length; i < len; i++){
        args.push('arguments['+i+']');
    }
    var result = eval('context.fn('+args+')')
    return result;
 }
es6 写法
            Function.prototype.myCall2 = function(context){
                context = context || window
                context.fn = this;
                var args = [];
                for(var i = 1,len = arguments.length; i < len; i++){
                    args.push(arguments[i])
                }
                var result = context.fn(...args);
                delete context.fn
                return result;
            }

2、apply

            Function.prototype.myApply = function (context,arr){
                var context = context || window;
                context.fn = this;
                if(!arr){
                    result = context.fn()
                }else {
                    var args = [];
                    for(var i = 1, len = arr.length; i <len; i++){
                        args.push('arr['+i+']');
                    }
                    result = eval('context.fn('+args+')')
                }
                delete context.fn;
                return result;
            }

3、bind

Function.prototype.mybind = function(context){
    let that = this;
    let args1 = Array.prototype.slice.call(arguments,1);
    let bindFn = function(){
        let args2 = Array.prototype.slice.call(arguments);
        return that.apply(this instanceof bindFn?this:context,args1.concat(args2)); 
    }
    let Fn = function(){};
    Fn.prototype = this.prototype;
    bindFn.prototype = new Fn();
    return bindFn;
}