面試題:實現call、apply、bind
阿新 • • 發佈:2019-06-16
面試題:實現call、apply、bind
實現bind
module.exports = function(context, ...args) { let withArgs = args.length != 0; //是否傳參 let isConstructor; try { new this(...args); //是建構函式則不會因為new執行報錯 isConstructor = true; } catch (error) { //不是建構函式 isConstructor = false; } if (isConstructor) { if (typeof context === "object" && context !== null) //context是有效物件 return withArgs ? () => Object.assign(context, new this(...args)) //若帶參,返回的函式不需要處理接收引數 : (...args) => Object.assign(context, new this(...args)); //若不帶參,返回的函式需要處理接收引數 else throw new Error("Illegal context"); //context是無效物件 } else { return ()=>this(...args); } };
實現call
在實現了bind後,只需要將call轉換給bind處理就可以了
module.exports = function(context, ...args){
return this.newBind(context, ...args)()
}
實現apply
實現了call後,只需要處理下引數,轉換給call處理就可以了
module.exports = function(context, args){ return args instanceof Array?this.newCall(context, ...args):this.newCall(context) }
使用
const newBind = require("./bind") const newCall = require("./call") const newApply = require("./apply") Function.prototype.newBind = newBind //將bind掛載到Function原型,使得任何例項可以像使用bind一般使用newBind Function.prototype.newCall = newCall //將call掛載到Function原型,使得任何例項可以像使用call一般使用newCall Function.prototype.newApply = newApply //將apply掛載到Function原型,使得任何例項可以像使用apply一般使用newApply
在掛載到原型上後,就可以正常使用了
測試
1、bind的測試
require(".") //匯入模組
const obj = {
q: "1"
}
const Parent = function(a, b){
this.a = a;
this.b = b
}
//一、使用bind的函式是建構函式,context是有效物件
//測試bind帶參,執行函式不帶參的情況
try {
console.log(Parent.newBind(obj,3,2)())
} catch (error) {
if(error.toString()=="Illegal context") console.log("err")
else console.log("Failed")
}
//測試bind帶參,執行函式帶參的情況 => 執行函式的引數不生效
try {
console.log(Parent.newBind(obj,3,2)(3,4))
} catch (error) {
if(error.toString()=="Illegal context") console.log("err")
else console.log("Failed")
}
//測試bind不帶參的情況,執行函式不帶參的情況 => 執行函式的引數應為undefined
try {
console.log(Parent.newBind(obj)())
} catch (error) {
if(error.toString()=="Illegal context") console.log("err")
else console.log("Failed")
}
//測試bind帶參,執行函式帶參的情況 => 執行函式的帶參應生效
try {
console.log(Parent.newBind(obj)(3,4))
} catch (error) {
if(error.toString()=="Illegal context") console.log("err")
else console.log("Failed")
}
//二、使用bind的函式是建構函式,context是無效物件
//測試bind帶參,執行函式不帶參的情況 => 捕獲報錯輸出ok
try {
console.log(Parent.newBind(null,3,2)())
} catch (error) {
console.log("ok")
}
//測試bind帶參,執行函式帶參的情況 => 捕獲報錯輸出ok
try {
console.log(Parent.newBind(null,3,2)(3,4))
} catch (error) {
console.log("ok")
}
//測試bind不帶參的情況,執行函式不帶參的情況 => 捕獲報錯輸出ok
try {
console.log(Parent.newBind(null)())
} catch (error) {
console.log("ok")
}
//測試bind帶參,執行函式帶參的情況 => 捕獲報錯輸出ok
try {
console.log(Parent.newBind(null)(3,4))
} catch (error) {
console.log("ok")
}
//三、使用bind的函式不是建構函式
console.log(Math.pow.newBind(obj, 3, 2)())
console.log(Math.pow.newBind(null, 3, 2)())
console.log(Math.pow.newBind(1, 3, 2)())
console.log("測試完成")
2、call的測試
require(".") //匯入模組
const obj = {
q: "1"
}
const Parent = function(a, b){
this.a = a;
this.b = b
}
//一、使用call的函式是建構函式,context是有效物件
//測試call帶參
try {
console.log(Parent.newCall(obj,3,2))
} catch (error) {
if(error.toString()=="Illegal context") console.log("err")
else console.log("Failed")
}
//測試call不帶參的情況 => 執行函式的引數應為undefined
try {
console.log(Parent.newCall(obj))
} catch (error) {
if(error.toString()=="Illegal context") console.log("err")
else console.log("Failed")
}
//二、使用call的函式是建構函式,context是無效物件
//測試call帶參 => 捕獲報錯輸出ok
try {
console.log(Parent.newCall(null,3,2))
} catch (error) {
console.log("ok")
}
//測試call不帶參的情況 => 捕獲報錯輸出ok
try {
console.log(Parent.newCall(null))
} catch (error) {
console.log("ok")
}
//三、使用call的函式不是建構函式
console.log(Math.pow.newCall(obj, 3, 2))
console.log(Math.pow.newCall(null, 3, 2))
console.log(Math.pow.newCall(1, 3, 2))
console.log("測試完成")
3、apply的測試
require(".") //匯入模組
const obj = {
q: "1"
}
const Parent = function(a, b){
this.a = a;
this.b = b
}
//一、使用apply的函式是建構函式,context是有效物件
//測試apply帶參
try {
console.log(Parent.newApply(obj,[3,2]))
} catch (error) {
if(error.toString()=="Illegal context") console.log("err")
else console.log("Failed")
}
//測試apply不帶參的情況 => 執行函式的引數應為undefined
try {
console.log(Parent.newApply(obj))
} catch (error) {
console.log(error);
if(error.toString()=="Illegal context") console.log("err")
else console.log("Failed")
}
//二、使用apply的函式是建構函式,context是無效物件
//測試apply帶參 => 捕獲報錯輸出ok
try {
console.log(Parent.newApply(null,[3,2]))
} catch (error) {
console.log("ok")
}
//測試apply不帶參的情況 => 捕獲報錯輸出ok
try {
console.log(Parent.newApply(null))
} catch (error) {
console.log("ok")
}
//三、使用apply的函式不是建構函式
console.log(Math.pow.newApply(obj, [3, 2]))
console.log(Math.pow.newApply(null, [3, 2]))
console.log(Math.pow.newApply(1, [3, 2]))
console.log(Math.pow.newApply(1, 3, 2)) //第二個引數不為陣列,結果應異常
console.log("測試完成")
經過測試,實現call、apply、bind基本功能是ok的
github地址
源