array.map
Array.prototype.MyMap = function(fn, context){
var arr = Array.prototype.slice.call(this);
var mappedArr = [];
for (var i = 0; i < arr.length; i++ ){
mappedArr.push(fn.call(context, arr[i], i, this));
}
return mappedArr;
}
array.reduce
Array.prototype.myReduce = function(fn, initialValue) {
var arr = Array.prototype.slice.call(this);
var res, startIndex;
res = initialValue ? initialValue : arr[0];
startIndex = initialValue ? 0 : 1;
for(var i = startIndex; i < arr.length; i++) {
res = fn.call(null, res, arr[i], i, this);
}
return res;
}
call/apply
Function.prototype.myCall = function(context = window, ...args) {
let func = this;
let fn = Symbol("fn");
context[fn] = func;
let res = context[fn](...args);
delete context[fn];
return res;
}
Object.create
function create(proto) {
function F() {};
F.prototype = proto;
F.prototype.constructor = F;
return new F();
}
bind
Function.prototype.bind = function(context, ...args) {
let self = this;
let fBound = function() {
return self.apply(this instanceof fBound ? this : context || window, args.concat(Array.prototype.slice.call(arguments)));
}
fBound.prototype = Object.create(this.prototype);
return fBound;
}
new
function myNew(fn, ...args) {
let instance = Object.create(fn.prototype);
let res = fn.apply(instance, args);
return typeof res === 'object' ? res: instance;
}
instanceof
function myInstanceof(left, right) {
let proto = Object.getPrototypeOf(left);
while(true) {
if(proto == null) return false;
if(proto == right.prototype) return true;
proto = Object.getPrototypeof(proto);
}
}
promise
const PENDING = "pending";
const FULFILLED = "fulfilled";
const REJECTED = "rejected";
class Promise{
constructor(excutorCallBack){
this.status = 'pending';
this.value = undefined;
this.fulfillAry = [];
this.rejectedAry = [];
let resolveFn = result => {
if(this.status !== 'pending') return;
let timer = setTimeout(() => {
this.status = 'fulfilled';
this.value = result;
this.fulfillAry.forEach(item => item(this.value));
}, 0);
};
let rejectFn = reason => {
if(this.status !== 'pending')return;
let timer = setTimeout(() => {
this.status = 'rejected';
this.value = reason;
this.rejectedAry.forEach(item => item(this.value))
})
};
try{
excutorCallBack(resolveFn, rejectFn);
} catch(err) {
rejectFn(err);
}
}
then(fulfilledCallBack, rejectedCallBack) {
typeof fulfilledCallBack !== 'function' ? fulfilledCallBack = result => result:null;
typeof rejectedCallBack !== 'function' ? rejectedCallBack = reason => {
throw new Error(reason instanceof Error? reason.message:reason);
} : null
return new Promise((resolve, reject) => {
this.fulfillAry.push(() => {
try {
let x = fulfilledCallBack(this.value);
x instanceof Promise ? x.then(resolve, reject ):resolve(x);
}catch(err){
reject(err)
}
});
this.rejectedAry.push(() => {
try {
let x = this.rejectedCallBack(this.value);
x instanceof Promise ? x.then(resolve, reject):resolve(x);
}catch(err){
reject(err)
}
})
}) ;
}
catch(rejectedCallBack) {
return this.then(null, rejectedCallBack);
}
static all(promiseAry = []) {
let index = 0,
result = [];
return new Promise((resolve, reject) => {
for(let i = 0; i < promiseAry.length; i++){
promiseAry[i].then(val => {
index++;
result[i] = val;
if( index === promiseAry.length){
resolve(result)
}
}, reject);
}
})
}
static race(promiseAry) {
return new Promise((resolve, reject) => {
if (promiseAry.length === 0) {
return;
}
for (let i = 0; i < promiseAry.length; i++) {
promiseAry[i].then(val => {
resolve(val);
return;
}, reject);
}
})
}
static resolve (value) {
if (value instanceof Promise) return value
return new Promise(resolve => resolve(value))
}
static reject (value) {
return new Promise((resolve, reject) => reject(value))
}
}
module.exports = Promise;
new
function create(constructor, ...args) {
const obj = Object.create(constructor.prototype)
const res = constructor.apply(obj, args)
return res instanceof Object ? res : obj
}
jsonStringify
function stringify(jsonObj) {
var result = '',
curVal;
if (jsonObj === null) {
return String(jsonObj);
}
switch (typeof jsonObj) {
case 'number':
case 'boolean':
return String(jsonObj);
case 'string':
return '"' + jsonObj + '"';
case 'undefined':
case 'function':
return undefined;
}
switch (Object.prototype.toString.call(jsonObj)) {
case '[object Array]':
result += '[';
for (var i = 0, len = jsonObj.length; i < len; i++) {
curVal = JSON.stringify(jsonObj[i]);
result += (curVal === undefined ? null : curVal) + ",";
}
if (result !== '[') {
result = result.slice(0, -1);
}
result += ']';
return result;
case '[object Date]':
return '"' + (jsonObj.toJSON ? jsonObj.toJSON() : jsonObj.toString()) + '"';
case '[object RegExp]':
return "{}";
case '[object Object]':
result += '{';
for (i in jsonObj) {
if (jsonObj.hasOwnProperty(i)) {
curVal = JSON.stringify(jsonObj[i]);
if (curVal !== undefined) {
result += '"' + i + '":' + curVal + ',';
}
}
}
if (result !== '{') {
result = result.slice(0, -1);
}
result += '}';
return result;
case '[object String]':
return '"' + jsonObj.toString() + '"';
case '[object Number]':
case '[object Boolean]':
return jsonObj.toString();
}
}
json parse
class Lexer {
constructor() {
this.chunk = '';
}
lex(input) {
this.chunk = input;
this.tokens = [];
while(!this.readEOF()) {
let consumed = this.readWhiteSpace()
|| this.readString()
|| this.readNumber()
|| this.readBoolean()
|| this.readNull()
|| this.readLiteral()
this.chunk = this.chunk.slice(consumed);
}
return this.tokens;
}
pushToken(type, value) {
this.tokens.push([type, value]);
}
readEOF() {
if (!this.chunk) {
this.pushToken('EOF', '');
return true;
};
}
readWhiteSpace() {
return this.chunk.match(/^\s*/)[0].length;
}
readString() {
let match = this.chunk.match(/^"(?:[^"\\\x00-\x1F\x7F\x80-\x9F]|\\["\\/bfnrt]|\\u[0-9a-fA-F]{4})*"/);
if (match) {
this.pushToken('String', match[0]);
return match[0].length;
}
}
readNumber() {
let match = this.chunk.match(/^-?[1-9]*\d+(?:\.\d+)?(?:[eE][+-]?\d+)?/);
if (match) {
this.pushToken('Number', match[0]);
return match[0].length;
}
}
readBoolean() {
let match = this.chunk.match(/^(?:true|false)/);
if (match) {
this.pushToken('Boolean', match[0].toLowerCase());
return match[0].length;
}
}
readNull() {
let match = this.chunk.match(/^null/);
if (match) {
this.pushToken('Null', match[0]);
return match[0].length;
}
}
readLiteral() {
const value = this.chunk.charAt(0);
this.pushToken(value, value);
return value.length;
}
}
class Parser {
constructor() {
this.tokens = [];
}
parse(input) {
this.i = 0;
this.tokens = new Lexer().lex(input);
const value = this.getValue();
if (!value) throw new TypeError('failed to parse JSON, expect value');
return value;
}
format(input, indent = ' ') {
const ast = this.parse(input);
return this._format(ast, indent);
}
_format(node, indent) {
switch(node.type) {
case 'String':
return JSON.stringify(JSON.parse(node.value));
case 'Number':
case 'True':
case 'False':
case 'Null':
return node.value;
}
let [begin, end] = node.type === 'Object' ? ['{', '}'] : ['[', ']'];
let output = begin;
const innerMembers = node.value;
if (!innerMembers.length) return output + end;
output += '\n';
innerMembers.forEach((item, index, arr) => {
output += indent;
if (node.type === 'Object') output += item.key.value + ': ';
const value = node.type === 'Object' ?
this._format(item.value, indent).replace(/\n/g, '\n' + indent) :
this._format(item, indent).replace(/\n/g, '\n' + indent);
output += value;
if (index !== arr.length - 1) output += ',\n';
});
return output += '\n' + end;
}
getValue() {
return this.readString() || this.readNumber() || this.readObject() || this.readArray() || this['true']() || this['false']() || this['null']();
}
readString() {
const [tag, value] = this.tokens[this.i];
if (tag === 'String') {
this.i++;
return { type: 'String', value };
}
}
readNumber() {
const [tag, value] = this.tokens[this.i];
if (tag === 'Number') {
this.i++;
return { type: 'Number', value };
}
}
readObject() {
const [tag] = this.tokens[this.i];
if (tag === '{') {
this.i++;
const members = this.readMembers() || [];
const [tag] = this.tokens[this.i];
if (tag !== '}') throw new TypeError('failed to parse object, expect "}"');
this.i++;
return { type: 'Object', value: members };
}
}
readMembers() {
let pair = this.readPair();
if (!pair) return [];
let members = [ pair ];
while (true) {
const [tag] = this.tokens[this.i];
if (tag !== ',') break;
this.i++;
pair = this.readPair();
members.push(pair);
}
return members;
}
readPair() {
const string = this.readString();
if (!string) throw new TypeError('failed to parse pair, expect string');
const [tag] = this.tokens[this.i];
if (tag !== ':') throw new TypeError('failed to parse pair, expect colon');
this.i++;
const value = this.getValue();
if (!value) throw new TypeError('failed to parse pair, expect value');
return { key: string, value };
}
readArray() {
const [tag] = this.tokens[this.i];
if (tag === '[') {
this.i++;
const elements = this.readElements() || [];
const [tag] = this.tokens[this.i];
if (tag !== ']') throw new TypeError('failed to parse object, expect "]"');
this.i++;
return { type: 'Array', value: elements };
}
}
readElements() {
let value = this.getValue();
if (!value) return [];
let elements = [ value ];
while (true) {
const [tag] = this.tokens[this.i];
if (tag !== ',') break;
this.i++;
value = this.getValue();
elements.push(value);
}
return elements;
}
'true'() {
const [tag, value] = this.tokens[this.i];
if (tag === 'Boolean' && value === 'true') {
this.i++;
return { type: 'True', value };
}
}
'false'() {
const [tag, value] = this.tokens[this.i];
if (tag === 'Boolean' && value === 'false') {
this.i++;
return { type: 'False', value };
}
}
'null'() {
const [tag, value] = this.tokens[this.i];
if (tag === 'Null') {
this.i++;
return { type: 'Null', value };
}
}
}