Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JS源码实现 #40

Closed
caoxinhui opened this issue May 21, 2020 · 0 comments
Closed

JS源码实现 #40

caoxinhui opened this issue May 21, 2020 · 0 comments

Comments

@caoxinhui
Copy link
Owner

caoxinhui commented May 21, 2020

参考文献

实现双向绑定

JSON.parse

function jsonParse(opt) {
  return eval(`(${opt})`)
}

function jsonParse(opt) {
  return new Function(`return ${opt}`)()
}

defineProperty 实现

<input class="input" type="text">
<span class="inputText"></span>
<script>
    const data = {
        text:'default'
    }
   const input = document.getElementsByClassName('input')[0];
    const span = document.getElementsByClassName('inputText')[0];
    Object.defineProperty(data,'text',{
        set(v) {
            input.value = v;
            span.innerHTML = v
        }
    });
    input.addEventListener('keyup',function (e) {
        data.text = e.target.value
    })
</script>

proxy 实现

<input class="input" type="text">
<span class="inputText"></span>
<script>
    const data = {
        text: 'defalt'
    };
    const input = document.getElementsByClassName('input')[0];
    const span = document.getElementsByClassName('inputText')[0];
    const handler = {
        set(target, key, value) {
            target[key] = value;
            input.value = value;
            span.innerHTML = value;
            return value
        }
    };
    const proxy = new Proxy(data, handler);
    input.addEventListener('keyup', function (e) {
        proxy.text = e.target.value
    })
</script>

防抖

function debounce(fn,delay) {
    let timer ;
    return function () {
        const context = this;
        clearTimeout(timer);
        setTimeout(()=>{
            fn.apply(context,arguments)
        },delay)
    };
}
container.addEventListener('scroll',debounce(action,1000))

节流

function throttle(fn, delay) {
  var prevTime = Date.now();
  return function() {
    var curTime = Date.now();
    if (curTime - prevTime > delay) {
      fn.apply(this, arguments);
      prevTime = curTime;
    }
  };
}
// 使用
var throtteScroll = throttle(function() {
  console.log('throtte');
}, 1000);
container.onscroll = throtteScroll;

async/await 实现

使用 generator 函数实现

const getData = () => new Promise(resolve => setTimeout(() => resolve('data'), 1000))
// async/await 功能
async function test() {
    const data = await getData();
    console.log(data);
    const data2 = await getData();
    console.log(data2);
    return 'success'
}

test().then(res => console.log(res));

/********** 使用 generator 函数实现 async/await ************/
function * testG() {
    const data = yield getData();
    console.log(data);
    const data2 = yield getData();
    console.log(data2);
    return 'success'
}


function asyncToGenerator(generatorFunc) {
    return function () {
        const gen = generatorFunc.apply(this, arguments);
        return new Promise(((resolve, reject) => {
            function step(key, arg) {
                let generatorResult;
                try {
                    generatorResult = gen[key](arg)
                } catch (e) {
                    return reject(e)
                }
                const {value, done} = generatorResult;
                if (done) {
                    return resolve(value)
                } else {
                    return Promise.resolve(value).then(val => step('next', val), err => step('throw', err))
                }
            }

            step('next')
        }))
    }
}


const hello =asyncToGenerator(testG)();
hello.then(value=>console.log(value));

实现promise.race

let promise1 = new Promise((resolve, reject) => {
    setTimeout(resolve, 200, '200ms')
})
let promise2 = new Promise((resolve, reject) => {
    setTimeout(resolve, 300, '300ms')
})
let promise3 = new Promise((resolve, reject) => {
    setTimeout(resolve, 400, '400ms')
})


Promise.race1 = function (promises) {
    return new Promise((resolve, reject) => {
        for (let i = 0; i < promises.length; i++) {
            Promise.resolve(promises[i]).then(data => {
                resolve(data)
                return
            }, error => reject(error))
        }
    })
}

Promise.race1([promise1, promise2, promise3]).then(data => console.log(data))

promise.race 实现超时函数

function TimeoutPromise(promise, ms) {
    const delayPromise = ms => {
        return new Promise(function (resolve) {
            setTimeout(resolve, ms)
        })
    }

    const timeout = delayPromise(ms).then(function () {
        throw new Error('operation time out after ' + ms + ' ms')
    })
    return Promise.race([promise, timeout])
}


function testPromise() {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve()
            console.log('resolve emit')
        }, 3000)
    })
}

TimeoutPromise(testPromise(),5000)

使用 promise 函数实现

function asyncFunc(value) {
    return new Promise(((resolve, reject) => {
        setTimeout(() => {
            resolve(value * 2)
        }, 3000)
    }))
}

async function main1(value) {
    let d = new Date().getTime();
    console.log('starting');
    let result1 = await asyncFunc(value);
    let result2 = await asyncFunc(result1);
    console.log('ending, ' + result2);
    console.log(new Date().getTime() - d)
}


async function main2(value) {
    let d = new Date().getTime();
    console.log('starting...');
    asyncFunc(value).then(res=>{
        let result1= res;
        return asyncFunc(result1)
    }).then(res=>{
        let result2 = res;
        console.log('ending... ' + result2);
        console.log(new Date().getTime() - d)
    })
}

实现 promise.all

function promiseAll(promises) {
    return new Promise(function (resolve, reject) {
        if (!Array.isArray(promises)) {
            return reject(new TypeError('arguments must be an array'))
        }
        let resolvedCounter = 0
        let promiseNum = promises.length
        let resolvedValues = new Array(promiseNum)
        for (let i = 0; i < promiseNum; i++) {
            Promise.resolve(promises[i]).then(function (value) {
                resolvedCounter++
                resolvedValues[i] = value
                if (resolvedCounter === promiseNum) {
                    return resolve(resolvedValues)
                }
            }, function (reason) {
                return reject(reason)
            })
        }
    })

}

实现promise.race

Promise.race1 = function (promises) {
    return new Promise((resolve, reject) => {
        for (let i = 0; i < promises.length; i++) {
            Promise.resolve(promises[i]).then(data => {
                resolve(data)
            }, error => {
                reject(error)
            })
        }
    })
}

let promise1 = new Promise((resolve, reject) => {
    setTimeout(resolve, 200, '100')
})

let promise2 = new Promise((resolve, reject) => {
    setTimeout(resolve, 100, '200')
})
let promise3 = new Promise((resolve, reject) => {
    setTimeout(resolve, 200, '300')
})


let promises = [promise1, promise2, promise3]
Promise.race1(promises).then(data => console.log(data))

实现promise.retry

Promise.retry = function (fn, num) {
    function executeFn() {
        return new Promise((resolve, reject) => {
            resolve(fn())
        }).then(res => {
            return Promise.resolve(res)
        }).catch(e => {
            num--;
            if (num < 0) {
                return Promise.reject(e)
            } else {
                return executeFn()
            }
        })
    }
    return executeFn()
};

function getData() {
    let num = Math.floor((Math.random() * 10));
    return new Promise((resolve, reject) => {
        if (num === 1) {
            resolve(num)
        } else {
            reject(num)
        }
    })
}


Promise.retry(getData, 3).then(res => console.log(res)).catch(err => console.log('失败'));

实现 promise

参考地址

function Promise(executor) {
    var self = this;
    self.status = 'pending';
    self.data = undefined;
    self.onResolvedCallback = [];
    self.onRejectedCallback = [];
    executor(resolve, reject);

    function resolve(value) {
        if (self.status === 'pending') {
            self.status = 'resolved';
            self.data = value;
            for (let i = 0; i < self.onRejectedCallback.length; i++) {
                self.onRejectedCallback[i](value)
            }
        }
    }

    function reject(reason) {
        if (self.status === 'pending') {
            self.status = 'rejected';
            self.data = reason;
            for (let i = 0; i < self.onRejectedCallback.length; i++) {
                self.onRejectedCallback[i](reason)
            }
        }
    }

    try {
        executor(resolve, reject)
    } catch (e) {
        reject(e)
    }

}


Promise.prototype.then = function (onResolved, onRejected) {
    var self = this;
    var promise2;
    onResolved = typeof onResolved === 'function' ? onResolved : function (v) {
        return v
    };
    onRejected = typeof onRejected === 'function' ? onRejected : function (r) {
        return r
    };
    if (self.status === 'resolved') {
        return promise2 = new Promise(function (resolve, reject) {
            try {
                const x = onResolved(self.data);
                if (x instanceof Promise) {
                    x.then(resolve, reject)
                }
                resolve(x)
            } catch (error) {
                reject(error)
            }

        })
    }
    if (self.status === 'rejected') {
        return promise2 = new Promise(function (resolve, reject) {
            try {
                var x = onRejected(self.data)
                if (x instanceof Promise) {
                    x.then(resolve, reject)
                }
            } catch (error) {
                reject(error)
            }
        })
    }
    if (self.status === 'pending') {
        return promise2 = new Promise(function (resolve, reject) {
            self.onResolvedCallback.push(function (value) {
                try {
                    const x = onResolved(self.data);
                    if (x instanceof Promise) {
                        x.then(resolve, reject)
                    }
                } catch (e) {
                    reject(e)
                }
            });
            self.onRejectedCallback.push(function (reason) {
                try {
                    const x = onRejected(self.data);
                    if (x instanceof Promise) {
                        x.then(resolve, reject)
                    }
                } catch (e) {
                    reject(e)
                }

            })
        })
    }
};


Promise.prototype.catch = function (onRejected) {
    return this.then(null, onRejected)
};

柯里化

const curry = fn =>
    (judge = (...args) =>
        args.length >= fn.length
            ? fn(...args)
            : (...arg) => judge(...args, ...arg));

const sum = (a, b, c, d) => a + b + c + d;
const currySum = curry(sum);

currySum(1)(2)(3)(4); // 10
currySum(1, 2)(3)(4); // 10
currySum(1)(2, 3)(4); // 10

Object.create 实现原理

Object.create = function (prototype, properties) {
    if (typeof prototype !== "object") {
        throw TypeError();
    }

    function Ctor() {
    }

    Ctor.prototype = prototype;
    var o = new Ctor();
    if (prototype) {
        o.constructor = Ctor;
    }
    if (properties !== undefined) {
        if (properties !== Object(properties)) {
            throw TypeError();
        }
        Object.defineProperties(o, properties);
    }
    return o;
};

instanceof 实现

instanceof 运算符用于检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上。

原理: L 的 proto 是不是等于 R.prototype,不等于再找 L.proto.proto 直到 proto 为 null

function instance_of(L, R) {
    var O = R.prototype;
    L = L.__proto__;
    while (true) {
        if (L === null) return false;
        // 这里重点:当 O 严格等于 L 时,返回 true
        if (O === L) return true;
        L = L.__proto__;
    }
}

splice 实现

new 操作的实现

  • 创建一个空对象,并把 this 指向空对象
  • 继承了函数的原型
  • 属性和方法被加入到 this 引用的对象中
  • 新创建的对象由 this 引用,最后隐式返回 this
function new(Function) {
    let obj = {
    }
    obj.__proto__ = Function.prototype
    let res = Function.call(obj)
    if(typeof(res) ==="function" || typeof(res) ==="object"){
        return res
    }
    return obj
}

单例实现

class Storage {
    constructor(){
        if(!Storage.instance){
            Storage.instance = this
        }
        return Storage.instance
    }
}

call

Function.prototype.call2 = function (context) {
    var context = context || window
    context.fn = this;

    var args = [];
    for(var i = 1, len = arguments.length; i < len; i++) {
        args.push('arguments[' + i + ']');
    }

    var result = eval('context.fn(' + args +')');

    delete context.fn
    return result;
}


// 测试一下
var value = 2;

var obj = {
    value: 1
}

function bar(name, age) {
    console.log(this.value);
    return {
        value: this.value,
        name: name,
        age: age
    }
}

bar.call2(null); // 2

console.log(bar.call2(obj, 'kevin', 18));

apply

Function.prototype.apply = function (context, arr) {
    var context = Object(context) || window;
    context.fn = this;

    var result;
    if (!arr) {
        result = context.fn();
    } else {
        var args = [];
        for (var i = 0, len = arr.length; i < len; i++) {
            args.push('arr[' + i + ']');
        }
        result = eval('context.fn(' + args + ')')
    }

    delete context.fn
    return result;
}

bind

Function.prototype.bind2 = function (context) {

    if (typeof this !== "function") {
      throw new Error("Function.prototype.bind - what is trying to be bound is not callable");
    }

    var self = this;
    var args = Array.prototype.slice.call(arguments, 1);

    var fNOP = function () {};

    var fBound = function () {
        var bindArgs = Array.prototype.slice.call(arguments);
        return self.apply(this instanceof fNOP ? this : context, args.concat(bindArgs));
    }

    fNOP.prototype = this.prototype;
    fBound.prototype = new fNOP();
    return fBound;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant