1.手写ajax基本过程
var xhr;
if(window.XMLHttpRequest){
//code for IE7+,Firefox,Chrome,Opera,Safari
xhr = new XMLHttpRequest();
}else{
// code for IE6, IE5
xhr = new ActiveXObject("Microsoft.XMLHTTP");
}
var xhr = new XMLHtpRequest(); //创建对象
xhr.open('post','demo.html',true)
xhr.send();
xhr.onreadystatechange = function(){
if(xhr.readyState === 4 && xhr.status === 200){
/*
0:请求还没有建立(open执行前)
1:请求建立了还没发送(执行了open)
2:请求正式发送(执行了send)
3:请求已受理,有部分数据可以用,但还没有处理完成
4:请求完全处理完成
*/
alert(xhr.responseText);
}
}
2.手写函数柯里化
函数柯里化,是将有多个参数的函数,即多元函数分为n个一元函数
function curry(fn, ...args){
//如果所传入的参数长度大于原函数的参数长度,那么就直接返回原函数
if([...args].length >= fn.length){
return fn(...args);
}else{
//反之,则返回一个参数长度为n - [...args].length的fn,并以递归方式依次传入剩下的参数,
return (...params) => {
return curry(fn, ...args, ...params);
}
}
}
3.手写call,apply,bind
相同:三者都是改变函数的调用对象(即改变this指向),注意是对函数使用!
call和bind的不同:唯一不同的是call接收的是一系列参数,apply接收的是参数数组
call和apply的不同:唯一不同是call和bind都是直接执行函数,apply是返回一个新的函数。
简述:能够让a对象,使用b对象的方法,并将this指针指向A。
Function.prototype.Mycall = function(context, ...params){
//创建一个_this使其等同调用对象。
const _this = typeof context === object ? context || window : window;
const key = Symbol();
//将this(此时的this指向的是有该方法的对象b)设置为_this的属性
_this[key] = this;
const result = _this[key](...params) //此时t函数内this指向的就是调用者A了
delete _this[key];
return result;
}
Function.prototype.MyApply = function(context, params){
return this.Mycall(context, ...params);
//也可写成,因为此时this === function.Prototype;
return function.Prototype.Mycall(context, ...params);
}
Function.prototype.MyBind = function(context, ...params){
//注,其返回的是一个新的函数,因此需要创建临时内部指针_this
const _this = this;
return function(...args){
return _this.Mycall(context, ...[...parmas, ...args]);
}
}
4.手写new
function myNew(){
//1.创建一个对象obj
var obj = new Object();
//2.将该对象的__proto__指向构造函数的prototype
Constructor = [].shift.call(arguments);
obj.__proto__ = Constructor.prototype;
//绑定this
Constructor.apply(obj, arguments);
}
function person(name,age){
this.name = name;
this.age = age;
this.sex = 'male';
}
var newn = myNew(person, 'hahaha', '20');
5.手写reduce
Array.prototype.myReduce = function(fn,initialValue){
var arr = [].slice.call(this);
if(initalValue){ //如果有初始值,则将它插入到数组第一个位置
arr.unshift(initalValue);
}
var result = arr[0];
for(let i = 1; i < arr.length; i++){
if(!arr.hasOwnProperty(i)){ //防止稀疏数组(也就是值为undefined的下标)
continue;
}
result = fn(null, result, arr[i], i, this);
}
}
6.手写map
map:对数组的每一个元素操作,并最终返回一个操作后的数组。
Array.prototype.myMap = function(fn, context){
var arr = [].slice.call(this);
var arrMap = [];
for(let i = 0; i < arr.length; i++){
if(!arr.hasOwnproperty){
continue;
};
arrMap.push(fn.call(context, arr[i], i, this));
}
return arrMap;
}
7.手写异步并发限制请求
function asyncPool(max, array, callBack){
let i = 0;
const running = []; //当前正在执行的任务列表
const enqueue = function(){
//递归,边界考虑,如果i等于array长度,则所有任务都已经放入running。
if(i === array.length){
return Promise.resolve();
}
//取出一个任务,然后再添加至running
const item = heavyWorker(array[i++]);
running.push(item);
item.then(()=>{ //当它执行完成后,则从running中删除掉
running.splice(running.indexOf(item), 1);
});
//一旦running的长度大于max,则调用promise.race
//当running中的有一个任务执行完毕,则用p继续调用enqueue去加入下一个任务。
let p = Promise.resolve();
if(running.length >= max){
p = Promise.race(running);
}
return p.then(() => enqueue());
}
//此时running可能做多还剩下max个任务,且之后已经没有新的任务了,
//所以用promise.all等到running中所有的任务执行完毕,再执行callback。
//切记必须等到enqueue执行完后再执行,所以写在enqueue().then里面。
enqueue().then(()=>{
Promise.all(running).then(()=>{
callBack();
})
});
}
asyncPool(3, tasks, ()=>{console.log('finish')});
8.手写Promise.all和Promise.race
Promise.all接收一个promise对象数组,如果数组内所有对象都resolve时,
新对象的状态变为fulfilled,所有对象的resolve的value值依次添加组成一个新的数组,
作为新对象resolve的value。
一旦数组内对象有一个reject时,新对象状态变为rejected,返回的值也是该对象reject的reason。
function promiseAll(arr){
if(!Array.isArray(arr)){
console.log('must be an array');
}
//返回promise实例
return new Promise((resolve, reject)=>{
let count = 0;
let res = new Array(arr.length);
for(let i = 0; i< arr.length; i++){
Promise.resolve(heavyWorker(arr[i]).then((value)=>{
count++;
res[i] = value;
if(count === arr.length){
return resolve(res);
}
},rej => reject(rej)));
}
})
}
console.log(promiseAll(tasks));
promise.race同样接收一个promise对象数组,只要对象数组内的一个对象的resolve时
新状态则为fullfilled,返回的值即为该对象resolve的value。
function promiseRace(arr){
if(!Array.isArray(arr)){
console.log('must be an array');
}
return new Promise((resolve,reject)=>{
arr.forEach((e)=>{
Promise.resolve(heavyWorker(e)).then(data => {
return resolve(data);
},err => {
reject(err);
})
})
})
}
console.log(promiseRace(tasks));
9.递归版深拷贝
你变它变,浅拷贝;都指向同一个地址
你变它不变,深拷贝;两个不同的地址
function deepClone(obj){
let res = Array.isArray(obj) ? []: {};
for(let key in obj){
if(obj[key] && typeof obj[key] === 'object'){
res[key] = deepClone(obj[key])
}else{
res[key] = obj[key];
}
}
return res;
}
let obj1 = deepClone(obj);
obj1.name = '8888';
console.log(obj1);