instanceof的实现
function myInstanceof(left, right) {let rightProto = right.prototype;let leftProto = left._proto_;// 判断实例对象的类型是否等于类型的原型while (true) {if (rightProto === null) return false;if (leftProto === rightProto) return true;leftProto = leftProto.prototype;}}
new的实现
function New(Constructor, ...args){let obj = {}; // 创建一个新对象Object.setPrototypeOf(obj, Constructor.prototype); // 连接新对象与函数的原型return Constructor.apply(obj, args) || obj; // 执行函数,改变 this 指向新的对象}function Foo(a){this.a = a;}New(Foo, 1); // Foo { a: 1 }// 第二种function _new() {let target = {}; //创建的新对象//第一个参数是构造函数let [constructor, ...args] = [...arguments];//执行[[原型]]连接;target 是 constructor 的实例target.__proto__ = constructor.prototype;//执行构造函数,将属性或方法添加到创建的空对象上let result = constructor.apply(target, args);if (result && (typeof (result) == "object" || typeof (result) == "function")) {//如果构造函数执行的结构返回的是一个对象,那么返回这个对象return result;}//如果构造函数返回的不是一个对象,返回创建的新对象return target;}//第三种function _new2(constructor, ...args) {if (typeof constructor !== 'function') {throw new TypeError('Type Error')}let obj = Object.create(constructor.prototype);const res = constructor.apply(obj, args);const isObject = typeof res === 'object';const isFunction = typeof res === 'function';return isObject || isFunction ? res : obj;}
Ajax封装
function ajax(type, url, data, success, fail) {var xhr = null;if (widnow.XMLHttpRequest) {xhr = new XMLHttpRequest();} else {xhr = new ActiveXObject();}if (typeof data === 'object') {var dataStr;for (var key in data) {dataStr += key + '=' + data[key] + '&';}data = dataStr.replace(/&$/, '');}type = type.toUpperCase();//随机数,清缓存var random = Math.random();if (type === 'GET') {if (data) {xhr.open('GET', url + '?' + data, true);} else {xhr.open('GET', url + '?t='+ random, true);}} else {xhr.open('POST', url, true);xhr.setRequestHeader("Content-type", 'application/x-www-form-urlencoded');xhr.send(dataStr);}xhr.onreadystatechange = function () {if (xhr.readyState === 4) {if(xhr.status === 200) {success && success(xhr.responseText);} else {fail && fail(xhr.status);}}}}// Promise版const getJSON = function(url) {return new Promise((resolve, reject) => {const xhr = XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject('Mscrosoft.XMLHttp');xhr.open('GET', url, false);xhr.setRequestHeader('Accept', 'application/json');xhr.onreadystatechange = function() {if (xhr.readyState !== 4) return;if (xhr.status === 200 || xhr.status === 304) {resolve(xhr.responseText);} else {reject(new Error(xhr.responseText));}}xhr.send();})}
浅拷贝与深拷贝
Object.assign与slice()都是浅拷贝,JSON.parse(JSON.stringify(obj))是深拷贝- JSON.stringify的几个缺点
1.如果obj里面有时间对象,则JSON.stringify后再JSON.parse的结果,时间将只是字符串的形式,而不是对象的形式
2.如果obj里有RegExp(正则表达式的缩写)、Error对象,则序列化的结果将只得到空对象
3、如果obj里有函数,undefined,则序列化的结果会把函数或 undefined丢失
4、如果obj里有NaN、Infinity和-Infinity,则序列化的结果会变成null
5、JSON.stringify()只能序列化对象的可枚举的自有属性,例如 如果obj中的对象是有构造函数生成的, 则使用JSON.parse(JSON.stringify(obj))深拷贝后,会丢弃对象的constructor
6、如果对象中存在循环引用的情况也无法正确实现深拷贝
- 浅拷贝
```javascript
// 简易例子
function cloneObject(source) {
let target = {};
for(let prop in source) {
if(source.hasOwnProperty(prop)){
} } return target; }target[prop] = source[prop];
// 对象merge export default merge(target) { for( let i = 1; i < arguments; i++){ let source = arguments[i]; for( let prop in source){ if(source.hasOwnProperty(prop)) { let value = source[prop]; if(value != undefined) { target[prop] = value; } } } } }
// 实现Object.assign if (type of Object._assign != ‘function’) { Object.defineProperty(Object, ‘assign2’, { value: function (target) { if (target == null) { throw new TypeError(‘Cannot not undefined or null to object’); }
target = Object(object);for (let i = 1; i < arguments.length; i++) {let source = arguments[i];if (source != null) {for (let prop in source) {if (source.hasOwnProperty(prop)) {let value = source[prop]if (value != undefined) {target[prop] = value}}}}}}})
}
- 深拷贝```javascript// 简易function deepClone(source) {let target = {};for (let prop in source) {if(typeof source[prop] === 'object') {target[prop] = deepClone(source[prop]);} else {target[prop] = source[prop];}}return target;}// 考虑数组与对象情况function clone(Obj) {var buf;if (Obj instanceof Array) {buf = []; // 创建一个空的数组let i = Obj.length;while (i--) {buf[i] = clone(Obj[i]);}return buf;} else if (Obj instanceof Object){buf = {}; // 创建一个空对象for (let k in Obj) { // 为这个对象添加新的属性buf[k] = clone(Obj[k]);}return buf;}else{return Obj;}}// 最完整示例,包括对象循环引用function deepClone(obj, hash = new WeakMap()) {if (obj === null) return obj; // 如果是null或者undefined我就不进行拷贝操作if (obj instanceof Date) return new Date(obj);if (obj instanceof RegExp) return new RegExp(obj);// 可能是对象或者普通的值 如果是函数的话是不需要深拷贝if (typeof obj !== "object") return obj;// 是对象的话就要进行深拷贝if (hash.get(obj)) return hash.get(obj);let cloneObj = new obj.constructor();// 找到的是所属类原型上的constructor,而原型上的 constructor指向的是当前类本身hash.set(obj, cloneObj);for (let key in obj) {if (obj.hasOwnProperty(key)) {// 实现一个递归拷贝cloneObj[key] = deepClone(obj[key], hash);}}return cloneObj;}let obj = { name: 1, address: { x: 100 } };obj.o = obj; // 对象存在循环引用的情况let d = deepClone(obj);obj.address.x = 200;console.log(d);// 考虑symbol情况const cloneDeep1 = (target, hash = new WeakMap()) => {// 对于传入参数处理if (typeof target !== 'object' || target === null) {return target;}// 哈希表中存在直接返回if (hash.has(target)) return hash.get(target);const cloneTarget = Array.isArray(target) ? [] : {};hash.set(target, cloneTarget);// 针对Symbol属性const symKeys = Object.getOwnPropertySymbols(target);if (symKeys.length) {symKeys.forEach(symKey => {if (typeof target[symKey] === 'object' && target[symKey] !== null) {cloneTarget[symKey] = cloneDeep1(target[symKey]);} else {cloneTarget[symKey] = target[symKey];}})}for (const i in target) {if (Object.prototype.hasOwnProperty.call(target, i)) {cloneTarget[i] =typeof target[i] === 'object' && target[i] !== null? cloneDeep1(target[i], hash): target[i];}}return cloneTarget;}
防抖与节流
// 防抖function debounce(fn) {// 创建一个标记用来存放定时器的返回值let timeout = null;return function() {//每次当用户点击/输入的时候,把前一个定时器清除clearTimeout(timeout);// 然后创建一个新的 setTimeout,// 这样就能保证点击按钮后的 interval 间隔内// 如果用户还点击了的话,就不会执行 fn 函数timeout = setTimeout(() => {fn.apply(this, arguments);}, 1000);};}// 节流function throttle(fn) {// 通过闭包保存一个标记let canRun = true;return function() {// 在函数开头判断标志是否为 true,不为 true 则中断函数if(!canRun) {return;}// 将 canRun 设置为 false,防止执行之前再被执行canRun = false;// 定时器setTimeout( () => {fn.call(this, arguments);// 执行完事件(比如调用完接口)之后,重新将这个标志设置为 truecanRun = true;}, 1000);};}
数组方法
扁平化
const arr = [1, [2, [3, [4, 5]]], 6];// 1.使用flatconst res1 = arr.flat(Infinity);// 2.使用正则匹配const res3 = JSON.parse('[' + JSON.stringify(arr).replace(/\[|\]/g, '') + ']');// 3.使用reduceconst flatten = arr => {return arr.reduce((pre, cur) => {return pre.concat(Array.isArray(cur) ? flatten(cur) : cur);}, [])}const res4 = flatten(arr);// 4. 递归const res5 = [];const fn = arr => {for (let i = 0; i < arr.length; i++) {if (Array.isArray(arr[i])) {fn(arr[i]);} else {res5.push(arr[i]);}}}fn(arr);
数组去重
const arr = [1, 1, '1', 17, true, true, false, false, 'true', 'a', {}, {}];// 1.利用Setconst res1 = Array.from(new Set(arr));// 2.利用Mapconst unique5 = arr => {const map = new Map();const res = [];for (let i = 0; i < arr.length; i++) {if (!map.has(arr[i])) {map.set(arr[i], true)res.push(arr[i]);}}return res;}// 3.两次for循环const unique1 = arr => {let len = arr.length;for (let i = 0; i < len; i++) {for (let j = i + 1; j < len; j++) {if (arr[i] === arr[j]) {arr.splice(j, 1);// 每删除一个树,j--保证j的值经过自加后不变。同时,len--,减少循环次数提升性能len--;j--;}}}return arr;}// 4.使用indexOfconst unique2 = arr => {const res = [];for (let i = 0; i < arr.length; i++) {if (res.indexOf(arr[i]) === -1) res.push(arr[i]);}return res;}// 5.使用includesconst unique3 = arr => {const res = [];for (let i = 0; i < arr.length; i++) {if (!res.includes(arr[i])) res.push(arr[i]);}return res;}
filter实现
Array.prototype.filter = function(callback, thisArg) {if (this == undefined) {throw new TypeError('this is null or not undefined');}if (typeof callback !== 'function') {throw new TypeError(callback + 'is not a function');}const res = [];// 让obj成为回调函数的对象传递(强制转换对象)const obj = Object(this);// >>>0 无符号移位0位,保证len为number,且为正整数const len = obj.length >>> 0;for (let i = 0; i < len; i++) {// 检查i是否在O的属性(会检查原型链)if (i in obj) {// 回调函数调用传参if (callback.call(thisArg, obj[i], i, obj)) {res.push(obj[i]);}}}return res;}
map实现
Array.prototype.map = function(callback, thisArg) {if (this == undefined) {throw new TypeError('this is null or undefined');}if (typeof callback !== 'function') {throw new TypeError(callback + ' is not a function');}const res = [];const obj = Object(this);const len = obj.length >>> 0;for(let i = 0; i < len; i++) {if (i in obj) {res[i] = callback.call(thisArg, obj[i], i, this);}}return res;}
forEach实现
Array.prototype.forEach = function(callback, thisArg) {if (this == null) {throw new TypeError('this is null or not defined');}if (typeof callback !== "function") {throw new TypeError(callback + ' is not a function');}const obj = Object(this);const len = obj.length >>> 0;let k = 0;while (k < len) {if (k in obj) {callback.call(thisArg, obj[k], k, obj);}k++;}}
reduce实现
Array.prototype.reduce = function(callback, initialValue) {if (this === undefined) {throw new TypeError('this is null or not undefined');}if (typeof callback !== 'function') {throw new TypeError(callback + 'is not a function');}const obj = Object(this);const len = this.length;let accumulator = initialValue;let k = 0;// 如果无初始值则取第一个值if (accumulator === undefined) {while(k < len && !(k in obj)) {k++;}if(k >= len) {throw new TypeError('Reduce of empty array with no initial value');}accumulator = obj[k++];}while (k < len) {accumulator = callback.call(this, accumulator, obj[k], k, obj);k++;}return accumulator;}
apply与call的实现
Function.prototype.apply = function(context = window, args) {if (typeof this !== 'function') {throw TypeError('this is not a function');}context.fn = this;const res = context.fn(...args);delete context.fn;return res;}Function.prototype.call = function(context = window, ...args) {if (typeof this !== 'function') {throw TypeError('this is not a function');}context.fn = this;const res = context.fn(args);delete context.fn;return res;}
bind的实现
Function.prototype.bind = function(context, ...args) {if (typeof this !== 'function') {throw new Error('');}// 保存thisconst selfFn = this;return function() {// 考虑new情况if (this instanceof F) {return new self(...args, ...arguments)}return selfFn.apply(context, [...args, ...arguments]);}}
柯理化
// 利用==判断会调用toString方法const arr = [1,2,3];function add() {const _args = [...arguments];function fn() {_args.push(...arguments);return fn;}fn.toString = function() {console.log(_args);return _args.reduce((sum, item) => sum + item);}return fn;}fn1 = add(1);console.log(fn1(2));// 固定参数个数的柯理化function sum(a, b, c) {return a + b + c;function curry(fn) {return function curried(...args) {// function的length属性指函数所需形参的个数,如果参数有默认值则为第一个有默认值之前的参数个数if (args.length >= fn.length) {return fn.apply(this, args);} else {return function(...args2) {return curried.apply(this, args.concat(args2));}}}}const sum2 = curry(sum);console.log(sum2(1, 2)(3)); // 6// 非固定参数个数的珂理化// 非固定个数入参function curry2(fn) {return function curried(...args) {//args,累计保存的参数return function(...args2) {// args2,每次执行传入的参数if (args2.length) {return curried.apply(this, args.concat(args2))} else {return fn.apply(this, args);}}}}
instanceof实现
function _instanceof() {if (typeof left !== 'object' || left === null) return false;let proto = Object.getPrototypeOf(left);while(true) {if (proto === null) return false;if (proto === right.prototype) return true;proto = Object.getPrototypeOf(proto);}}
继承实现
function Parent() {this.name = 'parent';}function Child() {Parent.call(this);this.type = 'children';}Child.prototype = Object.create(Parent.prototype);Child.prototype.constructor = Child;
Object.assign实现
Object.defineProperty(Object, 'assign', {value: function(target, ...args) {if (target == null) {return new TypeError('Cannot convert undefined or null to object');}let obj = Object(target);for(let i = 0; i < args.length; i++) {if (args[i] !== null) {for(const key in args[i]) {if (Object.hasOwnProperty.call(obj, key)) {obj[key] = args[i][key];}}}}return obj;},enumerable: false, // 不可枚举writable: false, // 不可修改configurable: false, // 是否可使用delete,是否可重新定义属性特性})
Promise实现
/*** Promise 实现*/const PENDING = 'PENDING';const FULFILLED = 'FULFILLED';const REJECTED = 'REJECTED';class Promise {constructor(exector) {this.status = 'PENDING'; // 状态,初始等待状态this.value = undefined; // 值,便于后续then,catch访问this.reason = undefined; // 失败原因保存this.onFulfilledCallbacks = []; // 成功回调队列this.onRejectedCallbacks = []; // 失败回调队列const resolve = (value) => {// 等待中状态才能进行更改if (this.status === PENDING) {this.status = FULFILLED;this.value = value;this.onFulfilledCallbacks.forEach(fn => fn(this.value));}}const reject = (reason) => {// 等待中状态才能进行更改if (this.status === PENDING) {this.status = REJECTED;this.reason = reason;this.onFulfilledCallbacks.forEach(fn => fn(this.reason));}}try {// 立即执行并传入修改状态的两个方法exector(resolve, reject);} catch(e) {// 出现错误直接reject回去reject(e);}}then(onFulfilled, onRejected) {// 初始化两个回调onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;onRejected = typeof onRejected === 'function' ? onRejected :reason => {throw new TypeError(reason instanceof Error ? reason.message : reason)}// 保存this, 即当前Promise实例const self = this;// 返回一个新Promisereturn new Promise((resolve, reject) => {// 等待状态if (self.status === PENDING) {// 加入成功回调队列self.onFulfilledCallbacks.push(() => {try {setTimeout(() => {const result = onFulfilled(self.value);// 处理链式传递resolvePromise(result, resolve, reject);})} catch(e) {reject(e)}})// 加入失败回调队列self.onRejectedCallbacks.push(() => {try {setTimeout(() => {const result = onRejected(self.reason);// 处理链式传递resolvePromise(result, resolve, reject);})} catch(e) {reject(e)}})}})}catch(onRejected) {this.then(null, onRejected);}static resolve(value) {if (value instanceof Promise) {return value;} else {return new Promise((resolve, reject) => resolve(value));}}static reject(reason) {return new Promise((resolve, reject) => {reject(reason);})}static all(promiseArr) {const len = promiseArr.length;let values = new Array(len);let count = 0;return new Promise((resolve, reject) => {for(let i = 0; i < len; i++) {// 使用Promise.resolve处理,保证每个都是Promise实例Promise.resolve(promise[i]).then(value => {count++;values[i] = value;if (count === len) {resolve(values);}}, err => reject(err))}})}static race(promiseArr) {return new Promise((resolve, reject) => {promiseArr.forEach(promiseItem => {Promise.resolve(promiseItem).then(value => resolve(value), err => reject(err));})})}}// 处理链式调用then, 传递返回值resultfunction resolvePromise(result, resolve, reject) {// 1. 返回是Promise类型,执行它的then// 2. 返回不是Promise, 执行当前新Promise的resolve, 将值传递下去if (result instanceof Promise) {result.then(resolve, reject);} else {resolve(result);}}
参考资料
promise实现—前端进阶之道
从零开始实现一个promise
