不分块了,太容易乱了,写到哪算哪吧
1.手写 call/apply/bind
- call
- 参数:(obj,...args)
- 特点:支持多个参数
Function.prototype.myCall = function(obj,...args){
//将obj的上下文存入context
const context = obj;
//设置一个独一无二的Symbol变量,避免覆盖原obj对象中方法
const func = Symbol;
//将Function(也就是xxx.myCall中xxx函数存储进func中)
context[func] = this;
//myCall调用获取结果,此刻是在obj内调用对象,满足call
const res = context[func](...args);
//返回结果
return res;
}
- apply
- 与myCall写法差不多,区别仅在与传入的参数,call支持传入多个参数,而apply仅支持传入obj与arg(数组)
- 参数:(obj,args)
//与myCall区别不大,仅在args方面有区别
Function.prototype.myApply = function(obj,args){
const context = obj;
const func = Symbol();
context[func] = this;
const res = context[func](args);
return res;
}
- bind
- 区别:与call、apply不同的是,bind返回的是一个函数,手写时,内部用到call或apply
- 参数:arguments
Function.prototype.myBind = function(){
//第一步:将参数转换为数组
const args = Array.prototype.slice.call(arguments);
//第二步:获取args中的对象上下文(位于args数组第一位)
const context = args.shift();
//第三步:保存本函数的this
const self = this;
//第四步:返回一个函数,函数中调用该函数
return function(){
return self.apply(context,args);
}
}
//使用示例:
function con(a,b){
console.log(this,a,b)
}
(con.myBind({name:"Tom"},1,2))();
2.Ajax
- 通过
XMLHttpRequest实现
const doAjax = function(url){
return new Promise((resolve,reject)=>{
const xhr = new XMLHttpRequest();
//xhr配置
xhr.open('GET',url,false)//false表示非异步
xhr.setRequestHeader("Accept","application/json");
//Ajax状态改变时运行回调
xhr.onreadystate = function(){
if( xhr.readystate !== 4 ) return; //状态码不为4说明请求不成功
//请求成功
if( xhr.status === 200 || xhr.status === 304){
resolve(xhr.responseText);
}else{
reject(new Error(xhr.responseText))
}
}
})
xhr.send();
}
3.new关键字
原理:创建一个空对象 → 将空对象的隐式原型__proto__指向构造函数的原型prototype → 让空对象进行继承 → 返回结果(若无返回值,则返回对象,否则返回res)
function myNew(func,...args){
let obj = {};
//修改原型链
obj.__proto__ = func.prototype;
const res = func.call(obj,...args);
if( typeof res === "object" || typeof res === "function" ) return res;
return obj;
}