Js 中new bind call源码

146 阅读3分钟

new源码

在执行new的时候都做了些什么呢? 在平常的学习中使用new返回的都是实例对象,因此new在执行过成中主要做了三件是1、创建对象,让该对象为函数原型,2、执行类函数并把改变this指向,3、返回类函数执行后的结果

function _new(fun,...args){
//默认创建一个实例,而且是属于当前这个类的一个实例,由于new出来的实例对象都是指向当前类的原型,因此obj.__proto__=fun.prototype,但是IE浏览器大部分不支持修改__proto__因此
let obj=Object.create(fun.prototype){
//改变this的指向及执行类函数
    let result=fun.call(obj);
}
if((result!=null&&typeof result==='object')||typeof result==='function'){
    return result;
}
  return obj; 
}

bind源码

bind是改变bind前面函数中的this指向,他与call和apply的区别在于,bind是提前绑定不执行,而call和apply是在绑定的同时执行了点前面的函数。bind与call和apply另一点不同是:bind绑定函数this指向后,函数将被永远绑定在其第一个参数对象上, 而无论其在什么情况下被调用。

~function anonymous(proto){
    function bind(content){
    //content为要绑定的对象
        if(content==undefined){
            content=window;
        }
        //获取传递的是实参集合,去除第一项
        var args=[].slice.call(arguments,1);//改变slice中this的指向,原本slice中的this指向[]现在指向arguments
        var _this=this;//调用bind函数前面的函数,比如fn.bind(obj),这里的this->fn,匿名函数中的this指向window
        //以上操作是利用了立即执行函数的保存机制
        return function anonymous(){
            //ev是用于兼容事件绑定,事件绑定时会传递dom事件
            var amargs=[].slice.call(arguments,0)
            _this.apply(content,args.concat(amargs))
            
        };   
    }
    proto.bind=bind
}(Function.prototype)
let obj={
    fn(x,y){
        console.log(this,x,y)
    }
}
setTime(obj.fn.bind(window),1000)//1s后先执行bind返回的anonymous,在anonymous中执行obj.fn,把之前存储的args/content传递给它

call的源码

call改变函数中的this指向,并且立即执行

~function anonymous(proto){
    function call(content=window,...args){
        content===null?content=window:null
        let type=typeof content;
        if(type!='object'&&type!='Function'&&type!='Sysmbole'){
            switch(type){
                case 'number':
                context=new Number(context);
                break;
                case 'string':
                context=new String(context);
                break;
                case 'boolean':
                context=new Boolean(context);
                break;
            }
        }
        context.$fn=this;
        let result=context.$fn(...args)
        return result;
    }
    proto.call=call
}(Function.prototype)

JQ中的类型检测$.type()源码解读

js中的数据类型检测有4种,第一种typeof:typeof是前端开发最长用的数据类型检测方法,但是他只使用于检测基本数据类型,引用数据类型返回的都是object; 常见的面试题:typeof typeof {}的值是什么,typeof的运算规则是从右往左运算,先算typeof {}=>'object' typeof 'object' 返回string; 第二种方法是instanceof:instanceof的语法为 [] instanceof Array;其作用是用于检测[] 是不是Array的实例,但是instanceof 存在一定的问题,instanceof检测机制是:所有出现在原型链上的类,检测结果都是true。而且在改变原型链指向时也会导致检测结果不正确,如下示例

function Fn() {}
Fn.prototype.__proto__ = Array.prototype;
<!--改变Fn原型链指向-->
let f = new Fn();
//f并不是数组但是最后检测结果为true
console.log(f instanceof Array); //true
// f的原型链:f=>Fn.prototype=>Array

另一种数据检测类型是constructor其原理同instanceof。 数据类型检测最有效的方式是Object.prototype.toString.call(要检测的对象);是通过调用Object原型上的toString方法同时通过call改变toString中的this指向

function type(obj) {
    var classType = [];
    'Boolean Number String Array Symbol Function Date RegExp Object Error'.split(' ').forEach(function anonymous(item) {
        classType['[Object' + item + ']'] = item.toLowerCase();
    });
    if (obj == null) {
        return obj + '';
    }
    return typeof obj === 'object' || typeof obj === 'function'
        ? classType[Object.prototype.toString.call(obj)] || 'object'
        : typeof obj;
}