本篇内容主要讲解“JS中一些重要的api实现分析”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“JS中一些重要的api实现分析”吧!
核心要点:
1.回调函数的参数有哪些,返回值如何处理。
2.不修改原来的数组。
Array.prototype.MyMap = function(fn, context){
var arr = Array.prototype.slice.call(this);//由于是ES5所以就不用...展开符了
var mappedArr = [];
for (var i = 0; i < arr.length; i++ ){
if(!arr.hasOwnProperty(i))continue;
mappedArr.push(fn.call(context, arr[i], i, this));
}
return mappedArr;
}
核心要点:
1、初始值不传怎么处理
2、回调函数的参数有哪些,返回值如何处理。
Array.prototype.myReduce = function(fn, initialValue) {
var arr = Array.prototype.slice.call(this);
var res, startIndex;
res = initialValue ? initialValue : arr[0];
startIndex = initialValue ? 0 : 1;
for(var i = startIndex; i < arr.length; i++)
{
res = fn.call(null, res, arr[i], i, this);
}
return res;
}
思路: 利用this的上下文特性。
//实现apply只要把下一行中的...args换成args即可Function.prototype.myCall =
function(context = window, ...args) { let func =
this; let fn =
Symbol("fn"); context[fn] = func; let res = context[fn](...args);//重点代码,利用this指向,相当于context.caller(...args) delete context[fn]; return res;}
function create(proto) {
function F() {};
F.prototype = proto;
return new F();
}
核心要点:
1.对于普通函数,绑定this指向
2.对于构造函数,要保证原函数的原型对象上的属性不能丢失
Function.prototype.bind = function(context, ...args) {
let self = this;//谨记this表示调用bind的数
let fBound = function() {
//this instanceof fBound为true表示构造函数的情况。new func.bind(obj)
return self.apply(this instanceof fBound ? this : context || window, args);
}
fBound.prototype = Object.create(this.prototype);//保证原函数的原型对象上的属性不丢失
return fBound;
}
大家平时说的手写bind,其实就这么简单:)
核心要点:
创建一个全新的对象,这个对象的__proto__要指向构造函数的原型对象
执行构造函数
返回值为object类型则作为new方法的返回值返回,否则返回上述全新对象
function myNew(fn, ...args) {
let instance = Object.create(fn.prototype);
let res = fn.apply(instance, args);
return typeof res === 'object' ? res: instance;
}
核心要点:原型链的向上查找。
function myInstanceof(left, right) {
let proto = Object.getPrototypeOf(left);
while(true) {
if(proto == null) return false;
if(proto == right.prototype) return true;
proto = Object.getPrototypeof(proto);
}
}
核心要点: 用闭包和Proxy属性拦截
function proxy(func) {
let instance;
let handler = {
constructor(target, args) {
if(!instance) {
instance = Reflect.constructor(fun, args);
}
return instance;
}
}
return new Proxy(func, handler);
}
方式其实很多,之前我做过系统整理,有六种方法,请参考:
JS数组扁平化(flat)方法总结
核心要点:
如果在定时器的时间范围内再次触发,则重新计时。
const debounce = (fn, delay) => {
let timer = null;
return (...args) => {
clearTimeout(timer);
timer = setTimeout(() => {
fn.apply(this, args);
},
delay);
};
};
核心要点:
如果在定时器的时间范围内再次触发,则不予理睬,等当前定时器完成,才能启动下一个定时器。
const throttle = (fn, delay = 500) => {
let flag = true;
return (...args) => {
if (!flag) return;
flag = false;
setTimeout(() => {
fn.apply(this, args);
flag = true;
}, delay);
};
};
以下为简易版深拷贝,没有考虑循环引用的情况和Buffer、Promise、Set、Map的处理,如果一一实现,过于复杂,面试短时间写出来不太现实,如果有兴趣可以去这里深入实现:
深拷贝终极探索。
const clone =
parent => { // 判断类型 const isType = (target, type) => `[object ${type}]` === Object.prototype.toString.call(target) // 处理正则 const getRegExp = re => { let flags =
""; if (re.global) flags +=
"g"; if (re.ignoreCase) flags +=
"i"; if (re.multiline) flags +=
"m"; return flags; }; const _clone =
parent => { if (parent ===
null)
return null; if (typeof
parent !==
"object")
return parent; let child, proto; if (isType(parent,
"Array")) { // 对数组做特殊处理 child = []; }
else if (isType(parent,
"RegExp")) { // 对正则对象做特殊处理 child =
new RegExp(parent.source, getRegExp(parent)); if (parent.lastIndex) child.lastIndex =
parent.lastIndex; }
else if (isType(parent,
"Date")) { // 对Date对象做特殊处理 child =
new Date(parent.getTime()); }
else { // 处理对象原型 proto = Object.getPrototypeOf(parent); // 利用Object.create切断原型链 child = Object.create(proto); } for (let i in
parent) { // 递归 child[i] = _clone(parent[i]); } return child; }; return _clone(parent);};
到此,相信大家对“JS中一些重要的api实现分析”有了更深的了解,不妨来实际操作一番吧!这里是亿速云网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!
亿速云「云服务器」,即开即用、新一代英特尔至强铂金CPU、三副本存储NVMe SSD云盘,价格低至29元/月。点击查看>>
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。
原文链接:http://blog.itpub.net/69946034/viewspace-2658011/