1.手寫promise
// exector 執(zhí)行器
function Promise1(exector) {
var that = this;
this.status = "pedding"; //設(shè)置狀態(tài)
this.resolveParams = ""; //resolve返回的值
this.rejectParams = ""; //存儲reject 返回的值
this.resolveFn = []; //存儲then中成功的回調(diào)函數(shù)
this.rejectFn = []; //存儲then中失敗的回調(diào)函數(shù)
function resolve(value) {
//只有在pedding狀態(tài)才執(zhí)行 防止多次點擊
if (that.status == "pedding") {
that.status = "resolved";
that.resolveParams = value;
that.resolveFn.forEach(fn => fn(value))
}
}
function reject(value) {
//只有在pedding狀態(tài)才執(zhí)行 防止多次點擊
if (that.status == "pedding") {
that.status = "rejected";
that.rejectParams = value;
that.rejectFn.forEach(fn => fn(value))
}
}
//執(zhí)行器捕獲異常
try {
exector(resolve, reject);
} catch (e) {
reject(e)
}
}
Promise1.prototype.then = function (resolve1, reject1) {
var that = this;
//同步執(zhí)行成功回調(diào)函數(shù)
if (this.status == "resolved") {
resolve1(that.resolveParams)
}
//同步執(zhí)行失敗回調(diào)函數(shù)
if (this.status == "rejected") {
reject1(that.rejectParams)
}
//異步情況時 保存回調(diào)函數(shù)
if (this.status == "pedding") {
this.resolveFn.push((val) => {
resolve1(val)
})
this.rejectFn.push((val) => {
reject1(val)
})
}
}
//測試
function test() {
return new Promise1((resolve, reject) => {
setTimeout(() => {
let val = Math.random();
if (val > 0.5) {
resolve('成功')
} else {
reject('失敗')
}
}, 100)
})
}
test().then(res => {
console.log(res)
}, (err) => {
console.log(err)
})
2.數(shù)組和對象深拷貝
1.JSON.parse(JSON.stringify())
2.手寫簡易版
function deepCopy(obj) {
if (typeof obj !== "object"||!obj) {
return obj;
}
const result= Array.isArray(obj) ? [] : {};
for (let key in obj) {
result[key] = typeof obj[key] !== "object" ? obj[key] : deepCopy(obj[key]);
}
return result;
}
3.完整版
/**
* deep clone
* @param {[type]} parent object 需要進行克隆的對象
* @return {[type]} 深克隆后的對象
*/
const clone = parent => {
// 判斷類型
const isType = (obj, type) => {
if (typeof obj !== "object") return false;
const typeString = Object.prototype.toString.call(obj);
let flag;
switch (type) {
case "Array":
flag = typeString === "[object Array]";
break;
case "Date":
flag = typeString === "[object Date]";
break;
case "RegExp":
flag = typeString === "[object RegExp]";
break;
default:
flag = false;
}
return flag;
};
// 處理正則
const getRegExp = re => {
var flags = "";
if (re.global) flags += "g";
if (re.ignoreCase) flags += "i";
if (re.multiline) flags += "m";
return flags;
};
// 維護兩個儲存循環(huán)引用的數(shù)組
const parents = [];
const children = [];
const _clone = parent => {
if (parent === null) return null;
if (typeof parent !== "object") return parent;
let child, proto;
if (isType(parent, "Array")) {
// 對數(shù)組做特殊處理
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);
}
// 處理循環(huán)引用
const index = parents.indexOf(parent);
if (index != -1) {
// 如果父數(shù)組存在本對象,說明之前已經(jīng)被引用過,直接返回此對象
return children[index];
}
parents.push(parent);
children.push(child);
for (let i in parent) {
// 遞歸
child[i] = _clone(parent[i]);
}
return child;
};
return _clone(parent);
};
3.繼承的實現(xiàn) 原型鏈繼承
子類實例化出來的對象擁有父類的屬性和方法
子類實例化出來的對象屬于子類,也屬于父類
原型鏈繼承金三句:
-
讓子類實例化出來的對象擁有父類的屬性
Person.apply(this,arguments) -
讓子類擁有父類的所有方法
Student.prototype=Object.create(Person.prototype)谨读; -
找回丟失的構(gòu)造器
Student.prototype.constructor=Student;
//定義一個父類
function Person(name,age){
this.name=name;
this.age=age;
}
Person.prototype.run=function(){
console.log(this.name+'正在散步')
}
//定義一個子類
function Student(name,age,score){
this.score=score;
//讓子類實例化出來的對象擁有父類的屬性 apply 和call都可以
Person.apply(this,arguments)
}
//讓子類擁有父類的所有方法
Student.prototype=Object.create(Person.prototype);
//找回丟失的構(gòu)造器
Student.prototype.constructor=Student;
Student.prototype.read=function(){
console.log(this.name+'正在看書')
}
let student1 = new Student('張三',20,100);
console.dir(student1 );
console.log(student1 instanceof Student); //true
console.log(student1 instanceof Person); //true
Object.create 原理
function create(proto) {
function F(){}
F.prototype = proto;
return new F();
}
4.new 操作符實現(xiàn)
- 它創(chuàng)建了一個全新的對象拳氢。
- 它會被執(zhí)行[[Prototype]](也就是proto)鏈接蒋譬。
- 它使this指向新創(chuàng)建的對象徐裸。羊初。
- 通過new創(chuàng)建的每個對象將最終被[[Prototype]]鏈接到這個函數(shù)的prototype對象上。
如果函數(shù)沒有返回對象類型Object(包含F(xiàn)unctoin, Array, Date, RegExg, Error)舶衬,那么new表達式中的函數(shù)調(diào)用將返回該對象引用埠通。
function New(Fn) {
let obj = {}
let arg = Array.prototype.slice.call(arguments, 1)
obj.__proto__ = Fn.prototype
obj.__proto__.constructor = Fn
Fn.apply(obj, arg)
return obj
}
5.實現(xiàn)instanceOf
function instance_of(left, R) {
//L 表示左表達式,R 表示右表達式
var O = R.prototype; // 取 R 的顯示原型
left= left.__proto__; // 取left 的隱式原型
while (true) {
if (left === null) return false;
if (O === left){
// 這里重點:當(dāng) O 嚴(yán)格等于left 時逛犹,返回 true
return true;
}
left= left.__proto__;
}
}
6.解析 URL Params 為對象
function parseParam(url) {
const paramsStr = /.+\?(.+)$/.exec(url)[1]; // 將 ? 后面的字符串取出來
const paramsArr = paramsStr.split('&'); // 將字符串以 & 分割后存到數(shù)組中
let paramsObj = {};
// 將 params 存到對象中
paramsArr.forEach(param => {
if (/=/.test(param)) { // 處理有 value 的參數(shù)
let [key, val] = param.split('='); // 分割 key 和 value
val = decodeURIComponent(val); // 解碼
val = /^\d+$/.test(val) ? parseFloat(val) : val; // 判斷是否轉(zhuǎn)為數(shù)字
if (paramsObj.hasOwnProperty(key)) { // 如果對象有 key植阴,則添加一個值
paramsObj[key] = [].concat(paramsObj[key], val);
} else { // 如果對象沒有這個 key,創(chuàng)建 key 并設(shè)置值
paramsObj[key] = val;
}
} else { // 處理沒有 value 的參數(shù)
paramsObj[param] = true;
}
})
return paramsObj;
}
7.實現(xiàn)一個call
// 模擬 call bar.mycall(null);
//實現(xiàn)一個call方法:
Function.prototype.myCall = function(context) {
//此處沒有考慮context非object情況
context.fn = this;
let args = [];
for (let i = 1, len = arguments.length; i < len; i++) {
args.push(arguments[i]);
}
context.fn(...args);
let result = context.fn(...args);
delete context.fn;
return result;
};