JS手写代码系列(一)

132 阅读2分钟

theme: 常用api的原生实现

Function.prototype.apply()实现

Function.prototype.myapply = function(context=window,args){
	if(typeof this!== function){
		throw this+'is not a function'
	}
	const _this = context;  
	let fn = Symbol('fn');
	_this.fn = this;
	const res = _this.fn(...args);
	delete _this.fn;
	return res;
}

Function.prototype.call()

Function.prototype.mycall = function(context = window,...args){
	if(typeof this !== 'function'){
		throw this + 'is not a function';
	}
	const _this = context;
	const fn =Symbol('fn');
	_this.fn = this;
	const res = _this.fn(...arg);
	delete _this.fn;
	return res;
}

Function.prototype.bind()

Function.prototype.mybind = function(context = window,args){
	if(typeof this!== function){
		throw this+"is not a function";
	}
	const _this = context;
	let self = this;
	return function F(){
		if(this instanceof F){              //考虑new的情况
			return new self(...args,...arguments);
		}
		return self.apply(_this,[...args,...arguments])
	}
}

实现函数柯里化

功能性版:

实现add(1)(2)(3)(4)=10 add(1,2)(3)(4)=10

function add(){
	let arg = [...arguments];    		//存储第一次传进来的参数
	return fn(){
		arg.push(...arguments)		//后续传入的参数加入数组
		return fn;			//返回fn调用toString方法
	}
	fn.toString = function(){		//重写toString方法
		return arg.reduce((sum,cur)=>sum+cur);
	}
	return fn;
}

getOwnPropertyNames()

function getOwnNames(o){
	if(o!==Object(o)){
		throw TypeError('Object.getOwnPropertyNames calles on non-object')
	})
	let result=[];
	for(i in o){
		if(Object.prototype.hasOwnProperty.call(o,i)){
			result.push(i);
		}
	}
	return result;
}

原理:Object.getOwnPropertyNames()取得对象自身的可枚举属性,不包括原型对象。for-in取得对象和原型对象的可枚举属性,使用hasOwnProperty过滤掉原型对象的属性

instanceof

function instance_of(L,R){
	let o = R.prototype;
	let p = L.__proto__;
	while(true){
		if(p===null) return false;
		if(p===o) return true;
		p=p.__proto__;
	}
}

原理:

let arr=[];
arr instanceof Array;   true
arr instanceof Objec;   true
arr instanceof Function false
固定右边构造函数的原型,在左边对象的__proto__层层寻找,直到__proto__值等于构造函数原型或者指向null

new

function myNew(){
	let obj = new Object();
	let Constructor = Array.prototype.shift.call(arguments);
	obj.__proto__ = Constructor.prototype;
	let res = Constructor.apply(obj,arguments);      //shift改变了arguments,此时arguments是传入的构造函数参数列表
	return typeof res === 'object'?res:obj;
}

Object.create()实现

function myCreate(o){
	function F(){};
	F.prototype=o;
	return new F();
}

原理:以传入对象为构造函数的原型,创建一个新的对象

Object.is()

Object.defineProperty{Object,'is',{
	value:function(x,y){
		if(x===y){    //对于+0和-0
			return x!==0||1/x===x/y;
		}
		else{  对于NaN !== NaN
			return x!==x&&y!==y;
		}
	},
	configure:true,
	enumberable:false,
	writable:true
}}

原理:Object.is()用来严格比较俩个参数是否相等,和===极度相似。唯一区别:

  • +0===-0 true,Object.is(+0,-0) false
  • NaN === NaN false ,Object.is(NaN,NaN) true

解决的问题:js缺乏一种运算,在所有环境中,只要俩个值是一样的,他们就应该相等,比如NaN。ES6提出"Same-value equality"算法解决这个问题。

核心代码原理:

DFmcgs.png

Array.isArray()

Array.myIsArray = function(o){
	return  Object.prototype.toString.call(Object(o))==='[object Array]'; //Object()的作用:确保call绑定的对象是 对象类型,而不是基本数据
}