Skip to content

Commit

Permalink
feat(js): add hand-write
Browse files Browse the repository at this point in the history
  • Loading branch information
seognil committed Aug 16, 2020
1 parent d24cef1 commit 8719dfa
Show file tree
Hide file tree
Showing 10 changed files with 399 additions and 9 deletions.
41 changes: 41 additions & 0 deletions js/prototype.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// * 只要理解了 ES 的继承中:
// * 继承类的 prototype 是基类的实例
// * 实例没有 prototype
// * 实例的 __proto__ 是类的 prototype

class Base {}

class Ext extends Base {}

const inst = new Ext();

console.log([
// @ts-ignore
inst.__proto__ === Object.getPrototypeOf(inst),
// @ts-ignore
inst.prototype === undefined,

Object.getPrototypeOf(inst) === Ext.prototype,
]);

console.log([
//
Object.getPrototypeOf(Ext.prototype) === Base.prototype,
]);

console.log([
Base.prototype.constructor === Base,
Ext.prototype.constructor === Ext,
Object.prototype.constructor === Object,
Function.prototype.constructor === Function,
]);

console.log([
// * 一等公民 一等公民

Object.getPrototypeOf(Object) === Function.prototype,

Object.getPrototypeOf(Function) === Function.prototype,

Object.getPrototypeOf(Function.prototype) === Object.prototype,
]);
36 changes: 36 additions & 0 deletions js/reimplement/array/filter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// * ================================================================================ original

{
const result = [1, 2, 3, 4].filter((e, i, a) => {
const keep = Boolean(e % 2);
console.log(e, i, a, keep);
return keep;
});

console.log(result);
}

console.log('--------');

// * ================================================================================ our

{
const filter = <T>(fn: (e: T, i: number, a: T[]) => Boolean | undefined, arr: T[]): T[] => {
const result: T[] = [];
for (let i = 0; i < arr.length; i++) {
fn(arr[i], i, arr) && result.push(arr[i]);
}
return result;
};

const result = filter(
(e, i, a) => {
const keep = Boolean(e % 2);
console.log(e, i, a, keep);
return keep;
},
[6, 7, 8, 9],
);

console.log(result);
}
28 changes: 28 additions & 0 deletions js/reimplement/array/flap.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// * 不 TS 了,有点麻烦……

// * ================================================================================ original

{
const data = [1, [[2], [[3]]]];
console.log(data.flat());
console.log(data.flat(2));
console.log(data.flat(Infinity));
}

console.log('--------');

// * ================================================================================ our

{
const flat = (arr, depth = 1) => {
if (!Array.isArray(arr)) return arr;
if (depth <= 0) return [...arr];

return arr.reduce((a, e) => [...a, ...(Array.isArray(e) ? flat(e, depth - 1) : [e])], []);
};

const data = [1, [[2], [[3]]]];
console.log(flat(data));
console.log(flat(data, 2));
console.log(flat(data, Infinity));
}
27 changes: 27 additions & 0 deletions js/reimplement/array/for-each.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// * ================================================================================ original

{
[1, 2, 3].forEach((e, i, a) => {
console.log(e, i, a);
});
}

console.log('--------');

// * ================================================================================ our

{
const forEach = <T, K>(fn: (e: T, i: number, a: T[]) => void, arr: T[]): void => {
for (let i = 0; i < arr.length; i++) {
fn(arr[i], i, arr);
}
};

forEach(
(e, i, a) => {
console.log(e, i, a);
return 'hello' + e;
},
[6, 7, 8],
);
}
34 changes: 34 additions & 0 deletions js/reimplement/array/map.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// * ================================================================================ original

{
const result = [1, 2, 3].map((e, i, a) => {
console.log(e, i, a);
return 'hello' + e;
});

console.log(result);
}

console.log('--------');

// * ================================================================================ our

{
const map = <T, K>(fn: (e: T, i: number, a: T[]) => K, arr: T[]): K[] => {
const result: K[] = [];
for (let i = 0; i < arr.length; i++) {
result.push(fn(arr[i], i, arr));
}
return result;
};

const result = map(
(e, i, a) => {
console.log(e, i, a);
return 'hello' + e;
},
[6, 7, 8],
);

console.log(result);
}
43 changes: 43 additions & 0 deletions js/reimplement/array/reduce.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// * ================================================================================ original

{
const data = [1, 2, 3];
const result = data.reduce((a, e, i) => a + e);
console.log(data, result);
}

{
const data = [1, 2, 3];
const result = data.reduce((a, e, i) => a + e, 1000);
console.log(data, result);
}

console.log('--------');

// * ================================================================================ our

{
const reduce = <T, K = T>(arr: T[], fn: (a: K, e: T, i: number) => K, a?: K): K => {
if (arr.length === 0 && a === undefined)
throw new Error('Reduce of empty array with no initial value');

const startIndex = a === undefined ? 1 : 0;
let result = (a === undefined ? arr[0] : a) as K;
for (let i = startIndex; i < arr.length; i++) {
result = fn(result, arr[i], i);
}
return result;
};

{
const data = [6, 7, 8];
const result = reduce(data, (a, e, i) => a + e);
console.log(data, result);
}

{
const data = [6, 7, 8];
const result = reduce(data, (a, e, i) => a + e, 1000);
console.log(data, result);
}
}
50 changes: 50 additions & 0 deletions js/reimplement/bind.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// * ================================================================================ original

{
const obj = {
val: 'inner',
fn(...args: any[]) {
console.warn(...args, this);
},
};

obj.fn(333);

const rawFn = obj.fn;
rawFn(666);

const bindedFn = obj.fn.bind({ val: 'outer' });
bindedFn(999);

const bindedFn2 = bindedFn.bind({ val: 'more' });
bindedFn2(0);
}

console.log('--------');

// * ================================================================================ our

{
const bind = <T, K>(context: any, fn: (...args: T[]) => K) => (...args: T[]) =>
fn.apply(context, args);

// * ----------------

const obj = {
val: 'inner',
fn(...args: any[]) {
console.warn(...args, this);
},
};

obj.fn(333);

const rawFn = obj.fn;
rawFn(666);

const bindedFn = bind({ val: 'outer' }, obj.fn);
bindedFn(999);

const bindedFn2 = bind({ val: 'more' }, bindedFn);
bindedFn2(0);
}
49 changes: 49 additions & 0 deletions js/reimplement/call.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// * ================================================================================ original

{
const obj = {
val: 'inner',
fn(...args: any[]) {
console.warn(...args, this);
},
};
obj.fn(333);

obj.fn.call({ val: 'outer' }, 666);
}

console.log('--------');

// * ================================================================================ our

{
const call = <T>(context: any, fn: Function, ...args: T[]) => {
let i = 0;
while (context[`__fn${i}`]) i++;
const shallowKey = `__fn${i}`;

Object.defineProperty(context, shallowKey, {
value: fn,
enumerable: false,
configurable: true,
});

const result = context[shallowKey](...args);

delete context[shallowKey];

return result;
};

// * ----------------

const obj = {
val: 'inner',
fn(...args: any[]) {
console.warn(...args, this);
},
};
obj.fn(333);

call({ val: 'outer' }, obj.fn, 666);
}
74 changes: 74 additions & 0 deletions js/reimplement/instanceof.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
// * ================================================================================ original
{
class A {}
class B extends A {}
class C extends B {}
class D extends B {}
class E extends A {}

/*
A <- B <- C
B <- D
A <- E
*/

// * ----------------

const inst = new C();

console.warn([
inst instanceof Object,
inst instanceof A,
inst instanceof B,
inst instanceof C,
inst instanceof D,
inst instanceof E,
]);
}
console.log('--------');

// * ================================================================================ our

// * 只要理解了 ES 的继承中,继承类的 prototype 是基类的实例

{
const instanceOf = (proto: any, inst: any) => {
let p = inst;
const p0 = proto.prototype;

if (p0 === undefined) throw TypeError(`instanceof ${proto} is not callable`);

while (p !== null) {
if (p === p0) return true;
p = Object.getPrototypeOf(p);
}
return false;
};

// * ----------------

class A {}
class B extends A {}
class C extends B {}
class D extends B {}
class E extends A {}

/*
A <- B <- C
B <- D
A <- E
*/

// * ----------------

const inst = new C();

console.warn([
instanceOf(Object, inst),
instanceOf(A, inst),
instanceOf(B, inst),
instanceOf(C, inst),
instanceOf(D, inst),
instanceOf(E, inst),
]);
}
Loading

0 comments on commit 8719dfa

Please sign in to comment.