一、手寫call函數
Function.prototype.myCall = function (context, ...args) {
if (typeof this !== 'function') {
throw new TypeError('not a function');
}
if (context === undefined || context === null) {
// 如果傳入的上下文對象是undefined或null的話荤西,則直接使用window對象作為上下文對象
context = window;
} else {
context = Object(context);
}
var specialPrototype = Symbol('specialPrototype'); // 給上下文對象添加的臨時屬性
context[specialPrototype] = this; // 將this函數添加到上下文對象上
var result = context[specialPrototype](...args); // 調用上下文對象上的方法獲取執(zhí)行結果
delete context[specialPrototype]; // 刪除上下文對象上添加的臨時屬性
return result; // 返回函數執(zhí)行結果
}
二澜搅、手寫bind函數
Function.prototype.myBind = function (thisArg) {
if (typeof this !== 'function') {
throw new TypeError('not a function');
}
var that = this;
var args = Array.prototype.slice.call(arguments, 1);
var fn = function () {}
var fnBound = function () {
const _this = this instanceof fn ? this : thisArg;
const newArgs = args.concat(Array.prototype.slice.call(arguments));
return that.apply(_this, newArgs);
}
if (this.prototype) {
fn.prototype = this.prototype;
}
fnBound.prototype = new fn();
fnBound.prototype.constructor = this;
return fnBound;
};
三、手寫實現new功能的函數
function myNew(fn, ...args) {
// 創(chuàng)建一個空的對象,將實例化對象的原型指向構造函數的原型對象
const instance = Object.create(fn.prototype);
// 將構造函數的this指向實例化對象
const res = fn.apply(instance, args);
// 判斷返回值邪锌,如果函數返回值為基本數據類型時, 則new出的對象依然是創(chuàng)建出的對象
return res instanceof Object ? res : instance;
}
四勉躺、手寫reduce函數
Array.prototype.myReduce = function (fn, initialValue) {
// 判斷調用對象是否為數組
if (Object.prototype.toString.call(this) !== '[object Array]') {
throw new TypeError('not a array');
}
// 判斷調用數組是否為空數組
if (this.length === 0) {
throw new TypeError('empty array');
}
// 判斷傳入的第一個參數是否為函數
if (typeof fn !== 'function') {
throw new TypeError(`${fn} is not a function`);
}
// 回調函數參數初始化
var sourceArray = this;
var result, currentValue, currentIndex;
if (initialValue !== undefined) {
result = initialValue;
currentIndex = 0;
} else {
result = sourceArray[0];
currentIndex = 1;
}
// 開始循環(huán)
while (currentIndex < sourceArray.length) {
if (Object.prototype.hasOwnProperty.call(sourceArray, currentIndex)) {
currentValue = sourceArray[currentIndex];
result = fn(result, currentValue, currentIndex, sourceArray);
}
currentIndex++;
}
// 返回結果
return result;
}
五、手寫防抖函數
function debounce(fn, delay=300) {
if (typeof fn !== 'function') {
throw new TypeError(`${fn} is not a function`);
}
let timer = null;
return (...args) => {
if (timer) {
clearTimeout(timer);
}
timer = setTimeout(() => {
fn.apply(this, args);
}, delay);
}
}
六觅丰、手寫節(jié)流函數
function throttle(fn, duration=500) {
if (typeof fn !== 'function') {
throw new TypeError(`${fn} is not a function`);
}
let lastTime = new Date().getTime();le
return (...args) => {
const now = new Date().getTime();
if (now - lastTime >= duration) {
fn.apply(this, args);
lastTime = now;
}
}
}
七饵溅、手寫Promise類 (實現了Promise/A+ 的大部分規(guī)范)
// 定義promise的三個狀態(tài)值
var promiseStatus = {
PENDING: "pending",
FULFILLED: "fulfilled",
REJECTED: "rejected",
}
function MyPromise(task) {
if(typeof task !== "function") {
throw new TypeError(`${task} is not a function`);
}
this.status = promiseStatus.PENDING; // 設置初始狀態(tài)
this.value = undefined;
this.thenCallback = undefined;
this.catchCallback = undefined;
var _this = this; // 緩存this對象
var resolve = function(value) {
if (_this.status === promiseStatus.PENDING) {
_this.status = promiseStatus.FULFILLED;
_this.value = value;
if(value instanceof MyPromise) {
value.then(function(res) {
if (_this.thenCallback) {
_this.thenCallback(res);
} else if (_this.catchCallback) {
_this.catchCallback(res);
}
});
} else {
// 這里使用setTimeout來模擬異步任務,實際promise是微任務妇萄,回調函數會放在微任務隊列中
setTimeout(function() {
if (_this.thenCallback) {
_this.thenCallback(_this.value);
} else if (_this.catchCallback) {
_this.catchCallback(_this.value);
}
});
}
}
}
var reject = function(errValue) {
if (_this.status === promiseStatus.PENDING) {
_this.status = promiseStatus.REJECTED;
_this.value = errValue;
// 這里使用setTimeout來模擬異步任務蜕企,實際promise是微任務,回調函數會放在微任務隊列中
setTimeout(function() {
if (_this.catchCallback) {
_this.catchCallback(_this.value);
} else if (_this.thenCallback) {
_this.thenCallback(_this.value);
}
});
}
}
try {
task(resolve, reject);
} catch(err) {
reject(err);
}
}
MyPromise.prototype.then = function(onFulfilledCallback, onRejectedCallback) {
var _this = this;
// 返回promise對象冠句,保證鏈式調用
return new MyPromise(function(resolve, reject) {
if (typeof onFulfilledCallback === "function") {
_this.thenCallback = function(value) {
/**
* 因為在使用鏈式調用的時候可能第一個調用的不是then
* 所以我們在做檢測時會借助then來將catch的信息向下傳遞
* 所以我們檢測到觸發(fā)thenCallback的Promise對象的狀態(tài)是rejected時
* 我們就繼續(xù)調用下一個Promise對象的reject
*/
if (_this.status === promiseStatus.REJECTED) {
reject(value);
} else {
// 用戶傳入的方法執(zhí)行時都要用try包裹
try {
var res = onFulfilledCallback(value);
if(res instanceof MyPromise && res.status === promiseStatus.REJECTED) {
res.catch(function(errValue) {
reject(errValue);
});
} else {
resolve(res);
}
} catch(err) {
reject(err);
}
}
};
}
if (typeof onRejectedCallback === "function") {
_this.catchCallback = function(errValue) {
/**
* 因為在使用鏈式調用的時候可能第一個調用的不是catch
* 所以我們在做檢測時會借助catch來將then的信息向下傳遞
* 所以我們檢測到觸發(fā)catchCallback的Promise對象的狀態(tài)是fulfilled時
* 我們就繼續(xù)調用下一個Promise對象的resolve
*/
if (_this.status === promiseStatus.FULFILLED) {
resolve(errValue);
} else {
// 用戶傳入的方法執(zhí)行時都要用try包裹
try {
var res = onRejectedCallback(errValue);
if(res instanceof MyPromise && res.status === promiseStatus.REJECTED) {
res.catch(function(errValue) {
reject(errValue);
});
} else {
resolve(res);
}
} catch(err) {
reject(err);
}
}
}
}
});
}
MyPromise.prototype.catch = function(onRejectedCallback) {
return this.then(null, onRejectedCallback);
}
MyPromise.prototype.finally = function (onFinallyCallback) {
return this.then(function (res) {
onFinallyCallback();
return res;
}, function(err) {
onFinallyCallback();
throw new Error(err);
});
}
MyPromise.resolve = function(value) {
return new MyPromise(function(resolve, reject) {
resolve(value);
});
}
MyPromise.reject = function(errValue) {
return new MyPromise(function(resolve, reject) {
reject(errValue);
});
}
MyPromise.all = function (promiseArr) {
var resArr = [];
return new MyPromise(function(resolve, reject) {
promiseArr.forEach(function(item, index) {
item.then(function(res) {
resArr[index] = res;
var allResolve = promiseArr.every(function(_item) {
return _item.status === promiseStatus.FULFILLED;
})
if (allResolve) {
resolve(resArr);
}
}).catch(function(err) {
reject(err);
})
});
});
}
MyPromise.race = function (promiseArr) {
return new MyPromise(function(resolve, reject) {
promiseArr.forEach(function(item, index) {
item.then(function(res) {
resolve(res);
}).catch(function(err) {
reject(err);
});
});
});
}
MyPromise.allSettled = function (promiseArr) {
var resAll = [];
return new MyPromise(function (resolve, reject) {
promiseArr.forEach(function (item, index) {
item.then(function (res) {
const obj = {
status: promiseStatus.FULFILLED,
value: res,
}
resArr[index] = obj;
var allResolve = promiseArr.every(function(_item) {
return _item.status !== promiseStatus.PENDING;
});
if (allResolve) {
resolve(resArr);
}
}).catch(function (err) {
const obj = {
status: promiseStatus.REJECTED,
value: err,
}
resArr[index] = obj;
var allResolve = promiseArr.every(function (_item) {
return _item.status !== promiseStatus.PENDING;
});
if (allResolve) {
resolve(resArr);
}
});
})
});
}
八轻掩、手寫XMLHttpRequest發(fā)送請求
function request(method, url, params){
// 初始化實例
let xhr;
if (window.XMLHttpRequest) {
xhr = new XMLHttpRequest();
}else {
xhr = new ActiveXObject("microsoft.XMLHTTP");
}
method = method ? method.toUpperCase() : 'GET';
if (method === 'POST') {
xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
}
xhr.open(method , url, true);
xhr.onreadystatechange = function () {
// 只有readyState === 4 和 status === 200,才會正常返回數據
if (xhr.readyState === 4) {
if (xhr.status === 200) {
// 通過JSON.parse()把test.json里面的數據轉換為json對象
console.log(JSON.parse(xhr.responseText))
} else {
console.log('其他情況')
}
}
}
xhr.sent(method === 'GET' ? null : JSON.stringify(params));
}
九轩端、手寫深拷貝deepClone函數
function deepClone (value, map = new WeakMap()) {
let newValue = value;
if (value && typeof obj === 'object') {
// 使用map防止循環(huán)引用放典,檢查map中有沒有,如果有被記錄則直接返回
const oldValue = map.get(value);
if ( oldeValue ) {
return oldValue;
}
// 如果沒有被記錄基茵,則創(chuàng)建新的對象
newValue = value.constructor == Array ? [] : {};
// 記錄該引用
map.set(value, newValue);
for (let key in value) {
const item = value[key];
newValue[key]=item && typeof item === 'object' ? arguments.callee(item, map) : item;
}
}
return newValue;
}
十奋构、手寫一個比較完美的繼承
function inheritPrototype(subType, superType){
var protoType = Object.create(superType.prototype); //創(chuàng)建對象
protoType.constructor = subType; //增強對象
subType.prototype = protoType; //指定對象
}
function SuperType(name){
this.name = name;
this.colors = ["red", "blue", "green"];
}
SuperType.prototype.sayName = function(){
console.log('name', this.name);
}
function SubType(name, age){
SuperType.call(this, name);
this.age = age;
}
inheritPrototype(SubType, SuperType)
SubType.prototype.sayAge = function(){
console.log('age', this.age);
}
var instance = new SubType("Bob", 18);
instance.sayName();
instance.sayAge();
更多個人文章