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-其他API原理 #10

Open
zhuziqingdemao opened this issue May 1, 2021 · 0 comments
Open

JS-其他API原理 #10

zhuziqingdemao opened this issue May 1, 2021 · 0 comments
Labels
javascript 手写代码 手写编程题目

Comments

@zhuziqingdemao
Copy link
Owner

zhuziqingdemao commented May 1, 2021

其他API

new

  function myNew(context,...args) {
      if(typeof context !== 'function') {
          throw new Error('newOperator function the first param must be a function')
      }
      let obj = Object.create(context.prototype); // 原型链连接
      const res = context.apply(obj,args);
      if((typeof res === 'object' && res !== null) || typeof res === 'function') return res;
      return obj;
  }

Object.create()、 new Object()、 {}

  • 字面量和new关键字创建的对象是Object的实例,原型指向Object.prototype,继承内置对象Object
  • Object.create(arg, pro)创建的对象的原型取决于arg,arg为null,新对象是空对象,没有原型,不继承任何对象;arg为指定对象,新对象的原型指向指定对象,继承指定对象

apply

Function.prototype.myAppy = function(context, args) {
    context = context || window; // 没有定义为window执行上下文
    context.fn = this;

    const result = eval('context.fn(...args)');

    delete context.fn;
    return resresult 
}

call

Function.prototype.myCall - function(context, ...args) {
    context = context || window; // 没有定义为window执行上下文
    context.fn = this;

    const res = eval('content.fn(...args)');

    delete context.fn;
    return res;
}

bind

函数柯里化

function curry(func,...args) {
    args.length >= func.length ? func(...args) : (..._args)=> curry(func,...args,...args);
}

函数组合

function compose(...fns) {
    return function(x) {
        return fns.reverse().reduce(function(arg,fn,index) {
            return fn(arg)
        },x)
    }
}

trim 消除先后空格

function trim(str) {
    return str.replace(/^\s\s*/,'').replace(/\s\s*$/,'')
}
function tirm(str) {
    return str.replace(/^\s+/,'').replace(/\s+$/,'');
}

大数相加

拷贝

浅拷贝

// array
[...arr]
arr.concat();
arr.slice(0)
// object
function shallowClone(obj) {
    if(typeof obj === 'object' && obj !== null) {
        const cloneTarget = Array.isArray(obj) ? [] : {};
        for(let prop in obj) {
            if(obj.hasOwnPrototype(prop)) {
                cloneTarget[prop] = obj[prop];
            }
        }
    } else {
        return obj;
    }
}

obj = Object.assign({},obj,{name: 'zhangsan'})

深拷贝

function handleFunc(func) {
    if(!func.prototype) return func;
    const bodyReg = /(?<={)(.|\n)+(?=})/m;
    const paramsReg = /(?<=\().+(?=\)\s+{)/;
    const func = func.toString();
    const params = paramsReg.exec(func);
    const body = bodyReg.exec(func);
    if(params) {
        return new Function(body, params[0].split(','))
    } else {
        return new Function(body[0])
    }
}
function handleNotTraverse(target,tag){
    const ctor = target.constructor;
    switch (tag) {
        case regexpTag:
            return handleReg(target)
        case funcTag:
            return handleFunc(target)
        case symbolTag:
            return new Object(Symbol.prototype.valueOf.call(target))
        default:
            return new ctor(target);
    }
}

function getType(target) {
    return Object.prototype.toString.call(target)
}
function deepCopy(target, map) {
    if(!isObject(target)) return target;
    const type = getType(target);
    let cloneTarget;

    if(!canTraver[type]) {
        return handleNotTraverse(target)
    } else {
        // 保证对象的原型不丢失
        let ctor = target.constructor;
        cloneTarget = new ctor();
    }

    if(map.get(target)) return map.get(target);

    map.set(target,true);

    if(type === mapTag) {
        target.forEach((item, key) => {
            cloneTarget.set(deepCopy(key,map), deepCopy(item,map))
        })
    }
    
    if(type === setTag) {
        target.forEach((item) => {
            cloneTarget.add(deepCopy(item, map))
        })
    }

    // 处理数组和对象
    for(let prop in target) {
        if(target.hasOwnPrototype(prop)) {
            cloneTarget[prop] = deepCopy(target[prop], map)
        }
    }

    return cloneTarget;
}

模板引擎

手动实现tmplate的模板引擎

以下模板作为demo

<%for ( var i = 0; i < users.length; i++ ) { %>
    <li>
        <a href="<%=users[i].url%>">
            <%=users[i].name%>
        </a>
    </li>
<% } %>

将模板替换为字符串,然后执行这段字符串,通过eval/Function
<% 转化为');
%>转化为p.push('
<%=xxx%>转化为');p.push(xxx);p.push('

第一版

// 第一版,使用eval执行函数
function _templ(str,data) {
    let string = "var p = [];p.push('"+
    str
    .replace(/[\r\t\n]/g,"")
    .replace(/<%=(.*?)%>/g,"');p.push($1);p.push('")
    .replace(/<%/g,"');")
    .replace(/%>/g,"p.push('")
    +"');"

    eval(string);
    return p.join('');
}

第二版
可以使用Function构造函数,达到一样的效果

function tmpl(str, data) {
    var str = document.getElementById(str).innerHTML;

    var fn = new Function("obj",

    "var p = []; p.push('" +

    str
    .replace(/[\r\t\n]/g, "")
    .replace(/<%=(.*?)%>/g, "');p.push($1);p.push('")
    .replace(/<%/g, "');")
    .replace(/%>/g,"p.push('")
    + "');return p.join('');");

    return fn(data);
};

不过值得注意的是:其实 tmpl 函数没有必要传入 data 参数,也没有必要在最后 return 的时候,传入 data 参数,即使你把这两个参数都去掉,代码还是可以正常执行的。

这是因为:

使用Function构造器生成的函数,并不会在创建它们的上下文中创建闭包;它们一般在全局作用域中被创建。当运行这些函数的时候,它们只能访问自己的本地变量和全局变量,不能访问Function构造器被调用生成的上下文的作用域。这和使用带有函数表达式代码的 eval 不同。

第三版
使用white 省略多余的属性值

// 第三版
function tmpl(str, data) {
    var str = document.getElementById(str).innerHTML;

    var fn = new Function("obj",

    // 其实就是这里多添加了一句 with(obj){...}
    "var p = []; with(obj){p.push('" +

    str
    .replace(/[\r\t\n]/g, "")
    .replace(/<%=(.*?)%>/g, "');p.push($1);p.push('")
    .replace(/<%/g, "');")
    .replace(/%>/g,"p.push('")
    + "');}return p.join('');");

    return fn(data);
};

第四版
如果我们使用的变量obj,发生了改变
这样子导致了每次实例化的时候都要重新的new Function
我们使tmpl返回一个函数,接受我们传递的变量

function tmpl(str, data) {
    var str = document.getElementById(str).innerHTML;

    var fn = new Function("obj",

    "var p = []; with(obj){p.push('" +

    str
    .replace(/[\r\t\n]/g, "")
    .replace(/<%=(.*?)%>/g, "');p.push($1);p.push('")
    .replace(/<%/g, "');")
    .replace(/%>/g,"p.push('")
    + "');}return p.join('');");

    var template = function(data) {
        return fn.call(this, data)
    }
    return template;
};

// 使用时
var compiled = tmpl("user_tmpl");
results.innerHTML = compiled(data);

大数相加

function lagerNumberSum(num1, num2) {
    let flag = 0;

    let res = '';

    const str1 = num1.toString(), str2 = num2.toString();
    let i = str1.length - 1, j = str2.length - 1;

    while(i >= 0 || j >= 0) {
        const x = str1[i] ? str1[i++] : 0;
        const y = str2[j] ? str2[j++] : 0;

        let sum = x + y + flag;

        if(sum > 9) {
            flag = 1;
            sum -= 10;
        } else {
            flag = 0;
        }
        res = sum + res;
    }

    if(flag) {
        res = flag + res;
    }

    return res;
}
@zhuziqingdemao zhuziqingdemao changed the title 手写JS方法 深入数组 May 9, 2021
@zhuziqingdemao zhuziqingdemao changed the title 深入数组 JS-其他API原理 May 9, 2021
@zhuziqingdemao zhuziqingdemao added the 手写代码 手写编程题目 label May 9, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
javascript 手写代码 手写编程题目
Projects
None yet
Development

No branches or pull requests

1 participant