JS中,eval, new Function, native处理JSON的性能比较

本文介绍了在JavaScript中解析JSON数据的三种常见方法:eval方式、new Function方式及使用JSON.parse的原生方法,并对这些方法进行了性能比较。

JSON作为JS中一种数据格式,应用非常广泛,在JS中,处理JSON的方法有三种,下面分别介绍这三种方式的使用方法及这三种方法的性能比较。

 

var jsonString;

 

一、eval 方式:

 

var str = eval('('+ jsonString +')');

1、为什么要加括号?

加上圆括号的目的是迫使eval函数在评估JavaScript代码的时候强制将括号内的表达式(jsonString)转化为对象,而不是作为语句(statement)来执行。
例如对象字面量{},如若不加外层的括号,那么eval会将大括号识别为JavaScript代码块的开始和结束标记,那么{}将会被认为是执行了一句空语句。

2、JSON格式的名字部分为什么要加引号?

因为eval函数会将{foo:”bar”}解释成合法的JavaScript语句,而非表达式。但是人们往往想要的是让eval将这段代码解释成一个对象。所以JSON格式会强制你去在名字的外侧加上引号再结合圆括号,这样eval就不会错误的将JSON解释成代码块。



 

二、new Function() 方式:

var str = new Function( "return " + jsonString )();

此刻用alert(str);得到的是一些 "[Object : Object]".若要看其中的值,则可以去掉Function后的"()",
即:var str = new Function( "return " + jsonString );

 

 

三、native

if ( typeof JSON !== "undefined" ) {

     var str = JSON.parse( jsonString ); 
}

 

性能比较的结论:

1、在IE6、IE7中选择 eval

2、在IE8中选择 native JSON

3、在Firefox2,3 中选择 new Function

4、在 Safri4中选择 eval

5、当选择其它浏览器时,eval 和 new Function 的性能一致。

 

 

 

let setProxyArr = function (proxyObjArr) { for (let i = 0; i < proxyObjArr.length; i++) { const handler = `{ get:function(target,property,receiver){ console.log("方法:","get","对象","${proxyObjArr[i]}","属性:", property,"属性类型:",typeof property,"属性值:",target[property],"属性值类型:",typeof target[property]); return Reflect.get(...arguments) }, set:function(target,property,value,receiver){ console.log("方法:","set","对象:","${proxyObjArr[i]}","属性:", property,"属性类型:",typeof property,"属性值:",value,"属性值类型:",typeof target[property]); return Reflect.set(...arguments); } }`; eval(`try{ ${proxyObjArr[i]}; ${proxyObjArr[i]} = new Proxy(${proxyObjArr[i]},${handler}); } catch (e){ ${proxyObjArr[i]} = {}; ${proxyObjArr[i]} = new Proxy(${proxyObjArr[i]},${handler}); }`); } } function watch(object) { const handler = { get: function (target, property, receiver) { if (property !== 'isNaN' && property !== 'encodeURI' && property !== "Uint8Array" && property !== 'undefined' && property !== 'JSON') { console.log("方法:", "get", "对象", target, "属性:", property, "属性类型:", typeof property, "属性值:", target[property], "属性值类型:", typeof target[property]); } return Reflect.get(...arguments) }, set: function (target, property, value, receiver) { console.log("方法:", "set", "对象:", target, "属性:", property, "属性类型:", typeof property, "属性值:", value, "属性值类型:", typeof target[property]); return Reflect.set(...arguments); } } // return object return new Proxy(object, handler) } const safeFunction = function safeFunction(func) { //处理安全函数 Function.prototype.$call = Function.prototype.call; const $toString = Function.toString; const myFunction_toString_symbol = Symbol('('.concat('', ')')); const myToString = function myToString() { return typeof this === 'function' && this[myFunction_toString_symbol] || $toString.$call(this); } const set_native = function set_native(func, key, value) { Object.defineProperty(func, key, { "enumerable": false, "configurable": true, "writable": true, "value": value }); } delete Function.prototype['toString']; set_native(Function.prototype, "toString", myToString); set_native(Function.prototype.toString, myFunction_toString_symbol, "function toString() { [native code] }"); const safe_Function = function safe_Function(func) { set_native(func, myFunction_toString_symbol, "function" + (func.name ? " " + func.name : "") + "() { [native code] }"); } return safe_Function(func) } //创建函数 const makeFunction = function makeFunction(name) { // 使用 Function 保留函数名 let func = new Function("v_log", ` return function ${name}() { v_log('函数${name}传参-->', arguments); }; `)(v_log); // 传递 v_log 到动态函数 safeFunction(func); func.prototype = myProxy(func.prototype, `方法${name}.prototype`); return func; } //Window Window = function Window() {} Window.prototype = {} safeFunction(Window) window = global; Object.setPrototypeOf(window, Window.prototype) window.top =window.Window = window.self = window window.chrome = {} window.loadts = '1758137904794' MouseEvent = function MouseEvent(){} safeFunction(window.MouseEvent) window.addEventListener = function addEventListener(){} safeFunction(window.addEventListener) window.DeviceMotionEvent = function (){} safeFunction(window.DeviceMotionEvent) delete Buffer delete __dirname delete __filename delete process delete global Document = function Document(){} safeFunction(Document) //Node Node = function Node(){} Node.prototype.removeChild = function (){} safeFunction(Node) safeFunction(Node.prototype.removeChild) //Element Element = function Element(){ Node.call(this) } safeFunction(Element) Element.prototype = Object.create(Node.prototype) Element.prototype.constructor = Element Element.prototype.getAttribute = function getAttribute(){} Element.prototype.removeChild = function removeChild(){} safeFunction(Element.prototype.getAttribute) safeFunction(Element.prototype.removeChild) //HTMLElement HTMLElement = function HTMLElement(){ Element.call(this) //在 HTMLElement 构造函数内部通过 Element.call(this) 调用了父类 Element 的构造函数,并将 this 绑定为 HTMLElement 的实例。 } safeFunction(HTMLElement) HTMLElement.prototype = Object.create(Element.prototype) HTMLElement.prototype.constructor = HTMLElement //HTMLHtmlElement HTMLHtmlElement = function HTMLHtmlElement(){ HTMLElement.call(this) this.tagName = 'HTML' } safeFunction(HTMLHtmlElement) HTMLHtmlElement.prototype = Object.create(HTMLElement.prototype) HTMLHtmlElement.prototype.constructor = HTMLHtmlElement //XMLHttpRequest XMLHttpRequest = function XMLHttpRequest(){} XMLHttpRequest.prototype.open = function (){} XMLHttpRequest.prototype.send = function (){} XMLHttpRequest.prototype.setRequestHeader = function (){} XMLHttpRequest.prototype.addEventListener = function (){} safeFunction(window.XMLHttpRequest) //requestIdleCallback requestIdleCallback = function (){} safeFunction(window.requestIdleCallback) //HtmlCollection function HTMLCollection(){ this._element = [watch(new HTMLHtmlElement())] } HTMLCollection.prototype[Symbol.iterator] = function() { // 获取文档根元素的子元素集合(迭代的目标) const elements = this._element; let index = 0; // 迭代索引 // 返回迭代器对象(必须包含next()方法) return { next: () => { // 当索引小于元素数量时,返回当前元素并递增索引 if (index < elements.length) { return { value: elements[index++], done: false }; } else { // 迭代结束 return { value: undefined, done: true }; } } }; }; safeFunction(HTMLCollection) //HTMLAllCollection function HTMLAllCollection() { this.length = 1048; } safeFunction(HTMLAllCollection) //HTMLBodyElement function HTMLBodyElement(){ HTMLElement.call(this); this.tagName = "BODY" } HTMLBodyElement.prototype = Object.create(HTMLElement.prototype) safeFunction(HTMLBodyElement) //HTMLDocument 用于实现document上的属性 function HTMLDocument() { } safeFunction(HTMLDocument) HTMLDocument.prototype.addEventListener = function addEventListener(){} safeFunction(HTMLDocument.prototype.addEventListener) HTMLDocument.prototype.getElementsByTagName = function getElementsByTagName(tagName){ console.log("HTMLDocument.prototype.getElementsByTagName的参数==>",tagName) if(tagName === "*"){ return watch(new HTMLCollection()) } } safeFunction(HTMLDocument.prototype.getElementsByTagName) HTMLDocument.prototype.all = watch(new HTMLAllCollection()) HTMLDocument.prototype.body = watch(new HTMLBodyElement()) HTMLDocument.prototype.documentElement = watch(new HTMLHtmlElement()) document = new HTMLDocument() document.cookie = "" //Permissions function Permissions (){ function createPermissionStatus(name) { return { name: name, // 权限名称(如 'geolocation') state: 'prompt', // 状态值:'granted' | 'denied' | 'prompt' onchange: null, // 事件回调占位 // 模拟事件监听方法(空实现) addEventListener: function() {}, removeEventListener: function() {} }; } this.query = function(permissionDesc) { const permName = permissionDesc?.name || 'unknown'; // 返回 Promise,resolve 出模拟的状态对象 return Promise.resolve(createPermissionStatus(permName)); }; this.request = function(permissionDesc) { const permName = permissionDesc?.name || 'unknown'; return Promise.resolve(createPermissionStatus(permName)); } } safeFunction(Permissions) //Navigator function Navigator() { } safeFunction(Navigator) Navigator.prototype.webdriver = false; Navigator.prototype.permissions = watch(new Permissions()); Navigator.prototype.userAgentData = watch(new NavigatorUAData()); Navigator.prototype.appName = 'Netscape' Navigator.prototype.userAgent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36' navigator = new Navigator() //NavigatorUAData function NavigatorUAData() { this["brands"] = [ { "brand": "Chromium", "version": "140" }, { "brand": "Not=A?Brand", "version": "24" }, { "brand": "Google Chrome", "version": "140" } ]; this["mobile"] = false; this["platform"] = "Windows" } safeFunction(NavigatorUAData) //Screen function Screen() {} screen = new Screen() safeFunction(Screen) //History function History() { } history = new History() safeFunction(History) //Location function Location() { } location = new Location() location.href = 'https://www.xiaohongshu.com/explore' safeFunction(Location) setProxyArr(["window",'document', 'location', 'history', 'screen', 'navigator']) 这个代码会发生无限递归, 我测试过,setProxyArr([“window”,‘document’, ‘location’, ‘history’, ‘screen’, ‘navigator’]) 里面如果没有window,在这个环境下执行业务代码不会发生无限递归,这是为什么,是不是window的某些属性导致的
最新发布
09-19
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值