美文网首页
JavaScript手写代码无敌秘籍

JavaScript手写代码无敌秘籍

作者: 阿羡吖 | 来源:发表于2020-04-28 16:16 被阅读0次

1实现一个new操作符

new操作符做了以下事情:

1、创建了一个全新的对象
2、会被执行[[Prototype]](也就是 _ proto _ )链接
3、使this指向新创建的对象
4、通过new创建的每个对象将最终被[[Prototype]]链接到这个函数的prototype对象上。
5、如果函数没有返回对象类型:object(包含 Function,Array,Date,RegExp,Error),那么new表达式中的函数调用将返回该对象引用

function New (func) {
    var res = {};
    if(func.prototype !== null){
        res.__proto__ = func.prototype;
    }
    var ret = func.apply(res, Array.prototype.slice(arguments, 1));
    if(typeof ret === "object" || typeof ret === "function") && ret !=== null){
        return rets;
    }
    return res;
}
var obj = New(A,1,2);
var obj = new A(1,2)

实现一个JSON.stringify

JSON.stringify(value[, replacer [, space]]):
Boolean | Number| String 类型会自动转换成对应的原始值。
undefined、任意函数以及symbol,会被忽略(出现在非数组对象的属性值中时),或者被转换成 null(出现在数组中时)。
不可枚举的属性会被忽略
如果一个对象的属性值通过某种间接的方式指回该对象本身,即循环引用,属性也会被忽略。

function jsonStringify(obj) {
    let type = typeof obj;
    if (type !== "object") {
        if (/string|undefined|function/.test(type)) {
            obj = '"' + obj + '"';
        }
        return String(obj);
    } else {
        let json = []
        let arr = Array.isArray(obj)
        for (let k in obj) {
            let v = obj[k];
            let type = typeof v;
            if (/string|undefined|function/.test(type)) {
                v = '"' + v + '"';
            } else if (type === "object") {
                v = jsonStringify(v);
            }
            json.push((arr ? "" : '"' + k + '":') + String(v));
        }
        return (arr ? "[" : "{") + String(json) + (arr ? "]" : "}")
    }
}
jsonStringify({x : 5}) // "{"x":5}"
jsonStringify([1, "false", false]) // "[1,"false",false]"
jsonStringify({b: undefined}) // "{"b":"undefined"}"

实现一个JSON.parse

JSON.parse(text[, reviver])
用来解析JSON字符串,构造由字符串描述的JavaScript值或对象。提供可选的reviver函数用以在返回之前对所得到的对象执行变换(操作)。

直接调用 eval
function jsonParse(opt) {
    return eval('(' + opt + ')');
}
jsonParse(jsonStringify({x : 5}))
// Object { x: 5}
jsonParse(jsonStringify([1, "false", false]))
// [1, "false", falsr]
jsonParse(jsonStringify({b: undefined}))
// Object { b: "undefined"}

避免在不必要的情况下使用 eval,eval() 是一个危险的函数, 他执行的代码拥有着执行者的权利。如果你用 eval()运行的字符串代码被恶意方(不怀好意的人)操控修改,您最终可能会在您的网页/扩展程序的权限下,在用户计算机上运行恶意代码。
它会执行JS代码,有XSS漏洞
如果你只想记这个方法,就得对参数json做校验。

var rx_one = /^[\],:{}\s]*$/;
var rx_two = /\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g;
var rx_three = /"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g;
var rx_four = /(?:^|:|,)(?:\s*\[)+/g;
if (
    rx_one.test(
        json
            .replace(rx_two, "@")
            .replace(rx_three, "]")
            .replace(rx_four, "")
    )
) {
    var obj = eval("(" +json + ")");
}
Function

核心:Function与eval有相同的字符串参数特性。
var func = new Function(arg1, arg2, ..., functionBody);
在转换JSON的实际应用中,只需要这么做。
var jsonStr = '{ "age": 20, "name": "jack" }'
var json = (new Function('return ' + jsonStr))();

evalFunction 都有着动态编译js代码的作用,但是在实际的编程中并不推荐使用。

实现一个callapply

call语法:
fun.call(thisArg, arg1, arg2, ...),调用一个函数, 其具有一个指定的this值和分别地提供的参数(参数的列表)。

apply语法:
func.apply(thisArg, [argsArray]),调用一个函数,以及作为一个数组(或类似数组对象)提供的参数。

Function.call按套路实现

call核心:
1、将函数设为对象的属性
2、执行&删除这个函数
3、指定this到函数并传入给定参数执行函数
4、如果不传入参数,默认指向为 window

为啥说是套路实现呢?因为真实面试中,面试官很喜欢让你逐步地往深考虑,这时候你可以反套路他,先写个简单版的:

//简单版
var foo = {
    value: 1,
    bar: function() {
        console.log(this.value)
    }
}
foo.bar() // 1
Function.prototype.call2 = function(content = window) {
    content.fn = this;
    let args = [...arguments].slice(1);
    let result = content.fn(...args);
    delete content.fn;
    return result;
}
let foo = {
    value: 1
}
function bar(name, age) {
    console.log(name)
    console.log(age)
    console.log(this.value);
}
bar.call2(foo, 'black', '18') // black 18 1

Function.apply的模拟实现

apply()的实现和call()类似,只是参数形式不同。直接贴代码吧

Function.prototype.apply2 = function(context = window) {
    context.fn = this
    let result;
    // 判断是否有第二个参数
    if(arguments[1]) {
        result = context.fn(...arguments[1])
    } else {
        result = context.fn()
    }
    delete context.fn
    return result
}

实现一个Function.bind()

bind()方法:
会创建一个新函数。当这个新函数被调用时,bind() 的第一个参数将作为它运行时的 this,之后的一序列参数将会在传递的实参前传入作为它的参数。(来自于 MDN )

此外,bind实现需要考虑实例化后对原型链的影响。

Function.prototype.bind2 = function(content) {
    if(typeof this != "function") {
        throw Error("not a function")
    }
    // 若没问参数类型则从这开始写
    let fn = this;
    let args = [...arguments].slice(1);
    
    let resFn = function() {
        return fn.apply(this instanceof resFn ? this : content,args.concat(...arguments) )
    }
    function tmp() {}
    tmp.prototype = this.prototype;
    resFn.prototype = new tmp();
    
    return resFn;
}

相关文章

  • JavaScript手写代码无敌秘籍

    1实现一个new操作符 new操作符做了以下事情: 1、创建了一个全新的对象2、会被执行[[Prototype]]...

  • 2019-04-03JavaScript手写代码无敌秘籍

    「中高级前端面试」JavaScript手写代码无敌秘籍 手写路径导航 实现一个new操作符 实现一个JSON.st...

  • 如何写出一个惊艳面试官的深拷贝?

    导读 最近经常看到很多JavaScript手写代码的文章总结,里面提供了很多JavaScript Api的手写实现...

  • 手写代码-Javascript篇

    1 Javascript 基础 1.1 手写Object.create 解析:Object.create() 方法...

  • 2019-01-24

    读 javascript 忍者秘籍 本文是作者阅读 javascript 忍者秘籍这本书过程中所记录零散知识和学习...

  • JavaScript -- 挥舞函数

    本文中的内容来自于 《JavaScript 忍者秘籍》。 函数存储 利用以下代码可以完成函数存储功能。 使用场景:...

  • 前端面试经典

    javaScript 理解MVVM等框架,手写伪代码。 ES6新特性,说说class 从编译角度谈谈变量提升 对象...

  • JavaScript深拷贝

    写在前面 如果本文对您有所帮助,就请点个关注吧! 手写JavaScript深拷贝 源代码 测试 测试结果

  • 程序员面试时手写代码的意义?

    一.手写代码和上机测试 我觉得,手写要写出思路,上机要能运行就够了 写代码 二.手写代码的意义和作用 手写代码是一...

  • 前端常见面试题(十)

    目录: 1,简述同步和异步的区别 2, 数组去重(手写代码) 3, 在JavaScript中什么是伪数组?如何将伪...

网友评论

      本文标题:JavaScript手写代码无敌秘籍

      本文链接:https://www.haomeiwen.com/subject/cfbywhtx.html