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;
}