乐趣区

关于javascript:前端一面常考手写面试题整理

请实现 DOM2JSON 一个函数,能够把一个 DOM 节点输入 JSON 的格局

<div>
  <span>
    <a></a>
  </span>
  <span>
    <a></a>
    <a></a>
  </span>
</div>

把下面 dom 构造转成上面的 JSON 格局

{
  tag: 'DIV',
  children: [
    {
      tag: 'SPAN',
      children: [{ tag: 'A', children: [] }
      ]
    },
    {
      tag: 'SPAN',
      children: [{ tag: 'A', children: [] },
        {tag: 'A', children: [] }
      ]
    }
  ]
}

实现代码如下:

function dom2Json(domtree) {let obj = {};
  obj.name = domtree.tagName;
  obj.children = [];
  domtree.childNodes.forEach((child) => obj.children.push(dom2Json(child)));
  return obj;
}

转化为驼峰命名

var s1 = "get-element-by-id"

// 转化为 getElementById

var f = function(s) {return s.replace(/-\w/g, function(x) {return x.slice(1).toUpperCase();})
}

批改嵌套层级很深对象的 key

// 有一个嵌套档次很深的对象,key 都是 a_b 模式,须要改成 ab 的模式,留神不能用递归。const a = {
  a_y: {
    a_z: {y_x: 6},
    b_c: 1
  }
}
// {
//   ay: {
//     az: {
//       yx: 6
//     },
//     bc: 1
//   }
// }

办法 1:序列化 JSON.stringify + 正则匹配

const regularExpress = (obj) => {
  try {const str = JSON.stringify(obj).replace(/_/g, "");
    return JSON.parse(str);
  } catch (error) {return obj;}
};;

办法 2:递归

const recursion = (obj) => {const keys = Object.keys(obj);
  keys.forEach((key) => {const newKey = key.replace(/_/g, "");
    obj[newKey] = recursion(obj[key]);
    delete obj[key];
  });
  return obj;
};

reduce 用法汇总

语法

array.reduce(function(total, currentValue, currentIndex, arr), initialValue);
/*
  total: 必须。初始值, 或者计算完结后的返回值。currentValue:必须。以后元素。currentIndex:可选。以后元素的索引;arr:可选。以后元素所属的数组对象。initialValue: 可选。传递给函数的初始值,相当于 total 的初始值。*/

reduceRight() 该办法用法与 reduce() 其实是雷同的,只是遍历的程序相同,它是从数组的最初一项开始,向前遍历到第一项

1. 数组求和

const arr = [12, 34, 23];
const sum = arr.reduce((total, num) => total + num);

// 设定初始值求和
const arr = [12, 34, 23];
const sum = arr.reduce((total, num) => total + num, 10);  // 以 10 为初始值求和


// 对象数组求和
var result = [{ subject: 'math', score: 88},
  {subject: 'chinese', score: 95},
  {subject: 'english', score: 80}
];
const sum = result.reduce((accumulator, cur) => accumulator + cur.score, 0); 
const sum = result.reduce((accumulator, cur) => accumulator + cur.score, -10);  // 总分扣除 10 分

2. 数组最大值

const a = [23,123,342,12];
const max = a.reduce((pre,next)=>pre>cur?pre:cur,0); // 342

3. 数组转对象

var streams = [{name: '技术', id: 1}, {name: '设计', id: 2}];
var obj = streams.reduce((accumulator, cur) => {accumulator[cur.id] = cur; return accumulator;}, {});

4. 扁平一个二维数组

var arr = [[1, 2, 8], [3, 4, 9], [5, 6, 10]];
var res = arr.reduce((x, y) => x.concat(y), []);

5. 数组去重

实现的基本原理如下:① 初始化一个空数组
② 将须要去重解决的数组中的第 1 项在初始化数组中查找,如果找不到(空数组中必定找不到),就将该项增加到初始化数组中
③ 将须要去重解决的数组中的第 2 项在初始化数组中查找,如果找不到,就将该项持续增加到初始化数组中
④ ……
⑤ 将须要去重解决的数组中的第 n 项在初始化数组中查找,如果找不到,就将该项持续增加到初始化数组中
⑥ 将这个初始化数组返回
var newArr = arr.reduce(function (prev, cur) {prev.indexOf(cur) === -1 && prev.push(cur);
    return prev;
},[]);

6. 对象数组去重

const dedup = (data, getKey = () => {}) => {const dateMap = data.reduce((pre, cur) => {const key = getKey(cur)
        if (!pre[key]) {pre[key] = cur
        }
        return pre
    }, {})
    return Object.values(dateMap)
}

7. 求字符串中字母呈现的次数

const str = 'sfhjasfjgfasjuwqrqadqeiqsajsdaiwqdaklldflas-cmxzmnha';

const res = str.split('').reduce((pre,next)=>{pre[next] ? pre[next]++ : pre[next] = 1
 return pre 
},{})
// 后果
-: 1
a: 8
c: 1
d: 4
e: 1
f: 4
g: 1
h: 2
i: 2
j: 4
k: 1
l: 3
m: 2
n: 1
q: 5
r: 1
s: 6
u: 1
w: 2
x: 1
z: 1

8. compose 函数

redux compose 源码实现

function compose(...funs) {if (funs.length === 0) {return arg => arg;}
    if (funs.length === 1) {return funs[0];
    }
    return funs.reduce((a, b) => (...arg) => a(b(...arg)))
}

对象数组列表转成树形构造(解决菜单)

[
    {
        id: 1,
        text: '节点 1',
        parentId: 0 // 这里用 0 示意为顶级节点
    },
    {
        id: 2,
        text: '节点 1_1',
        parentId: 1 // 通过这个字段来确定子父级
    }
    ...
]

转成
[
    {
        id: 1,
        text: '节点 1',
        parentId: 0,
        children: [
            {
                id:2,
                text: '节点 1_1',
                parentId:1
            }
        ]
    }
]

实现代码如下:

function listToTree(data) {let temp = {};
  let treeData = [];
  for (let i = 0; i < data.length; i++) {temp[data[i].id] = data[i];
  }
  for (let i in temp) {if (+temp[i].parentId != 0) {if (!temp[temp[i].parentId].children) {temp[temp[i].parentId].children = [];}
      temp[temp[i].parentId].children.push(temp[i]);
    } else {treeData.push(temp[i]);
    }
  }
  return treeData;
}

怎么在制订数据源外面生成一个长度为 n 的不反复随机数组 能有几种办法 工夫复杂度多少(字节)

第一版 工夫复杂度为 O(n^2)

function getTenNum(testArray, n) {let result = [];
  for (let i = 0; i < n; ++i) {const random = Math.floor(Math.random() * testArray.length);
    const cur = testArray[random];
    if (result.includes(cur)) {
      i--;
      break;
    }
    result.push(cur);
  }
  return result;
}
const testArray = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14];
const resArr = getTenNum(testArray, 10);

第二版 标记法 / 自定义属性法 工夫复杂度为 O(n)

function getTenNum(testArray, n) {let hash = {};
  let result = [];
  let ranNum = n;
  while (ranNum > 0) {const ran = Math.floor(Math.random() * testArray.length);
    if (!hash[ran]) {hash[ran] = true;
      result.push(ran);
      ranNum--;
    }
  }
  return result;
}
const testArray = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14];
const resArr = getTenNum(testArray, 10);

第三版 交换法 工夫复杂度为 O(n)

function getTenNum(testArray, n) {const cloneArr = [...testArray];
  let result = [];
  for (let i = 0; i < n; i++) {
    debugger;
    const ran = Math.floor(Math.random() * (cloneArr.length - i));
    result.push(cloneArr[ran]);
    cloneArr[ran] = cloneArr[cloneArr.length - i - 1];
  }
  return result;
}
const testArray = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14];
const resArr = getTenNum(testArray, 14);

值得一提的是操作数组的时候应用交换法 这种思路在算法外面很常见

最终版 边遍历边删除 工夫复杂度为 O(n)

function getTenNum(testArray, n) {const cloneArr = [...testArray];
  let result = [];
  for (let i = 0; i < n; ++i) {const random = Math.floor(Math.random() * cloneArr.length);
    const cur = cloneArr[random];
    result.push(cur);
    cloneArr.splice(random, 1);
  }
  return result;
}
const testArray = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14];
const resArr = getTenNum(testArray, 14);

参考 前端进阶面试题具体解答

判断括号字符串是否无效(小米)

题目形容

给定一个只包含 '(',')','{','}','[',']' 的字符串 s,判断字符串是否无效。无效字符串需满足:- 左括号必须用雷同类型的右括号闭合。- 左括号必须以正确的程序闭合。示例 1:输出:s = "()"
输入:true

示例 2:输出:s = "()[]{}"
输入:true

示例 3:输出:s = "(]"
输入:false

答案

const isValid = function (s) {if (s.length % 2 === 1) {return false;}
  const regObj = {"{": "}",
    "(": ")",
    "[": "]",
  };
  let stack = [];
  for (let i = 0; i < s.length; i++) {if (s[i] === "{" || s[i] === "(" || s[i] === "[") {stack.push(s[i]);
    } else {const cur = stack.pop();
      if (s[i] !== regObj[cur]) {return false;}
    }
  }

  if (stack.length) {return false;}

  return true;
};

实现有并行限度的 Promise 调度器

题目形容:JS 实现一个带并发限度的异步调度器 Scheduler,保障同时运行的工作最多有两个

addTask(1000,"1");
 addTask(500,"2");
 addTask(300,"3");
 addTask(400,"4");
 的输入程序是:2 3 1 4

 整个的残缺执行流程:一开始 1、2 两个工作开始执行
500ms 时,2 工作执行结束,输入 2,工作 3 开始执行
800ms 时,3 工作执行结束,输入 3,工作 4 开始执行
1000ms 时,1 工作执行结束,输入 1,此时只剩下 4 工作在执行
1200ms 时,4 工作执行结束,输入 4 

实现代码如下:

class Scheduler {constructor(limit) {this.queue = [];
    this.maxCount = limit;
    this.runCounts = 0;
  }
  add(time, order) {const promiseCreator = () => {return new Promise((resolve, reject) => {setTimeout(() => {console.log(order);
          resolve();}, time);
      });
    };
    this.queue.push(promiseCreator);
  }
  taskStart() {for (let i = 0; i < this.maxCount; i++) {this.request();
    }
  }
  request() {if (!this.queue || !this.queue.length || this.runCounts >= this.maxCount) {return;}
    this.runCounts++;
    this.queue
      .shift()()
      .then(() => {
        this.runCounts--;
        this.request();});
  }
}
const scheduler = new Scheduler(2);
const addTask = (time, order) => {scheduler.add(time, order);
};
addTask(1000, "1");
addTask(500, "2");
addTask(300, "3");
addTask(400, "4");
scheduler.taskStart();

实现一个队列

基于链表构造实现队列

const LinkedList = require('./ 实现一个链表构造')

// 用链表默认应用数组来模仿队列,性能更佳
class Queue {constructor() {this.ll = new LinkedList()
  }
  // 向队列中增加
  offer(elem) {this.ll.add(elem)
  }
  // 查看第一个
  peek() {return this.ll.get(0)
  }
  // 队列只能从头部删除
  remove() {return this.ll.remove(0)
  }
}

var queue = new Queue()

queue.offer(1)
queue.offer(2)
queue.offer(3)
var removeVal = queue.remove(3)

console.log(queue.ll,'queue.ll')
console.log(removeVal,'queue.remove')
console.log(queue.peek(),'queue.peek')

树形构造转成列表(解决菜单)

[
    {
        id: 1,
        text: '节点 1',
        parentId: 0,
        children: [
            {
                id:2,
                text: '节点 1_1',
                parentId:1
            }
        ]
    }
]
转成
[
    {
        id: 1,
        text: '节点 1',
        parentId: 0 // 这里用 0 示意为顶级节点
    },
    {
        id: 2,
        text: '节点 1_1',
        parentId: 1 // 通过这个字段来确定子父级
    }
    ...
]

实现代码如下:

function treeToList(data) {let res = [];
  const dfs = (tree) => {tree.forEach((item) => {if (item.children) {dfs(item.children);
        delete item.children;
      }
      res.push(item);
    });
  };
  dfs(data);
  return res;
}

实现千位分隔符

// 保留三位小数
parseToMoney(1234.56); // return '1,234.56'
parseToMoney(123456789); // return '123,456,789'
parseToMoney(1087654.321); // return '1,087,654.321'
function parseToMoney(num) {num = parseFloat(num.toFixed(3));
  let [integer, decimal] = String.prototype.split.call(num, '.');
  integer = integer.replace(/\d(?=(\d{3})+$)/g, '$&,');
  return integer + '.' + (decimal ? decimal : '');
}

字符串最长的不反复子串

题目形容

给定一个字符串 s,请你找出其中不含有反复字符的 最长子串 的长度。示例 1:

输出: s = "abcabcbb"
输入: 3
解释: 因为无反复字符的最长子串是 "abc",所以其长度为 3。示例 2:

输出: s = "bbbbb"
输入: 1
解释: 因为无反复字符的最长子串是 "b",所以其长度为 1。示例 3:

输出: s = "pwwkew"
输入: 3
解释: 因为无反复字符的最长子串是 "wke",所以其长度为 3。请留神,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。示例 4:

输出: s = ""
输入: 0

答案

const lengthOfLongestSubstring = function (s) {if (s.length === 0) {return 0;}

  let left = 0;
  let right = 1;
  let max = 0;
  while (right <= s.length) {let lr = s.slice(left, right);
    const index = lr.indexOf(s[right]);

    if (index > -1) {left = index + left + 1;} else {lr = s.slice(left, right + 1);
      max = Math.max(max, lr.length);
    }
    right++;
  }
  return max;
};

解析 URL Params 为对象

let url = 'http://www.domain.com/?user=anonymous&id=123&id=456&city=%E5%8C%97%E4%BA%AC&enabled';
parseParam(url)
/* 后果
{ user: 'anonymous',
  id: [123, 456], // 反复呈现的 key 要组装成数组,能被转成数字的就转成数字类型
  city: '北京', // 中文需解码
  enabled: true, // 未指定值得 key 约定为 true
}
*/
function parseParam(url) {const paramsStr = /.+\?(.+)$/.exec(url)[1]; // 将 ? 前面的字符串取出来
  const paramsArr = paramsStr.split('&'); // 将字符串以 & 宰割后存到数组中
  let paramsObj = {};
  // 将 params 存到对象中
  paramsArr.forEach(param => {if (/=/.test(param)) { // 解决有 value 的参数
      let [key, val] = param.split('='); // 宰割 key 和 value
      val = decodeURIComponent(val); // 解码
      val = /^\d+$/.test(val) ? parseFloat(val) : val; // 判断是否转为数字

      if (paramsObj.hasOwnProperty(key)) { // 如果对象有 key,则增加一个值
        paramsObj[key] = [].concat(paramsObj[key], val);
      } else { // 如果对象没有这个 key,创立 key 并设置值
        paramsObj[key] = val;
      }
    } else { // 解决没有 value 的参数
      paramsObj[param] = true;
    }
  })

  return paramsObj;
}

请实现一个 add 函数,满足以下性能

add(1);             // 1
add(1)(2);      // 3
add(1)(2)(3);// 6
add(1)(2, 3); // 6
add(1, 2)(3); // 6
add(1, 2, 3); // 6
function add(...args) {
  // 在外部申明一个函数,利用闭包的个性保留并收集所有的参数值
  let fn = function(...newArgs) {return add.apply(null, args.concat(newArgs))
  }

  // 利用 toString 隐式转换的个性,当最初执行时隐式转换,并计算最终的值返回
  fn.toString = function() {return args.reduce((total,curr)=> total + curr)
  }

  return fn
}

考点:

  • 应用闭包,同时要对 JavaScript 的作用域链(原型链)有深刻的了解
  • 重写函数的 toSting()办法
// 测试,调用 toString 办法触发求值

add(1).toString();             // 1
add(1)(2).toString();      // 3
add(1)(2)(3).toString();// 6
add(1)(2, 3).toString(); // 6
add(1, 2)(3).toString(); // 6
add(1, 2, 3).toString(); // 6

实现 lodash 的 chunk 办法 – 数组按指定长度拆分

题目

/**
 * @param input
 * @param size
 * @returns {Array}
 */
_.chunk(['a', 'b', 'c', 'd'], 2)
// => [['a', 'b'], ['c', 'd']]

_.chunk(['a', 'b', 'c', 'd'], 3)
// => [['a', 'b', 'c'], ['d']]

_.chunk(['a', 'b', 'c', 'd'], 5)
// => [['a', 'b', 'c', 'd']]

_.chunk(['a', 'b', 'c', 'd'], 0)
// => []

实现

function chunk(arr, length) {let newArr = [];
  for (let i = 0; i < arr.length; i += length) {newArr.push(arr.slice(i, i + length));
  }
  return newArr;
}

判断是否是电话号码

function isPhone(tel) {var regx = /^1[34578]\d{9}$/;
    return regx.test(tel);
}

实现 getValue/setValue 函数来获取 path 对应的值

// 示例
var object = {a: [{ b: { c: 3} }] }; // path: 'a[0].b.c'
var array = [{a: { b: [1] } }]; // path: '[0].a.b[0]'

function getValue(target, valuePath, defaultValue) {}

console.log(getValue(object, "a[0].b.c", 0)); // 输入 3
console.log(getValue(array, "[0].a.b[0]", 12)); // 输入 1
console.log(getValue(array, "[0].a.b[0].c", 12)); // 输入 12

实现

/**
 * 测试属性是否匹配
 */
export function testPropTypes(value, type, dev) {const sEnums = ['number', 'string', 'boolean', 'undefined', 'function']; // NaN
  const oEnums = ['Null', 'Object', 'Array', 'Date', 'RegExp', 'Error'];
  const nEnums = ['[object Number]',
    '[object String]',
    '[object Boolean]',
    '[object Undefined]',
    '[object Function]',
    '[object Null]',
    '[object Object]',
    '[object Array]',
    '[object Date]',
    '[object RegExp]',
    '[object Error]',
  ];
  const reg = new RegExp('\\[object (.*?)\\]');

  // 齐全匹配模式,type 应该传递相似格局[object Window] [object HTMLDocument] ...
  if (reg.test(type)) {
    // 排除 nEnums 的 12 种
    if (~nEnums.indexOf(type)) {if (dev === true) {console.warn(value, 'The parameter type belongs to one of 12 types:number string boolean undefined Null Object Array Date RegExp function Error NaN');
      }
    }

    if (Object.prototype.toString.call(value) === type) {return true;}

    return false;
  }
}
const syncVarIterator = {getter: function (obj, key, defaultValue) {
    // 后果变量
    const defaultResult = defaultValue === undefined ? undefined : defaultValue;

    if (testPropTypes(obj, 'Object') === false && testPropTypes(obj, 'Array') === false) {return defaultResult;}

    // 后果变量,临时指向 obj 持有的援用,后续将可能被一直的批改
    let result = obj;

    // 失去晓得值
    try {
      // 解析属性档次序列
      const keyArr = key.split('.');

      // 迭代 obj 对象属性
      for (let i = 0; i < keyArr.length; i++) {
        // 如果第 i 层属性存在对应的值则迭代该属性值
        if (result[keyArr[i]] !== undefined) {result = result[keyArr[i]];

          // 如果不存在则返回未定义
        } else {return defaultResult;}
      }
    } catch (e) {return defaultResult;}

    // 返回获取的后果
    return result;
  },
  setter: function (obj, key, val) {
    // 如果不存在 obj 则返回未定义
    if (testPropTypes(obj, 'Object') === false) {return false;}

    // 后果变量,临时指向 obj 持有的援用,后续将可能被一直的批改
    let result = obj;

    try {
      // 解析属性档次序列
      const keyArr = key.split('.');

      let i = 0;

      // 迭代 obj 对象属性
      for (; i < keyArr.length - 1; i++) {
        // 如果第 i 层属性对应的值不存在,则定义为对象
        if (result[keyArr[i]] === undefined) {result[keyArr[i]] = {};}

        // 如果第 i 层属性对应的值不是对象(Object)的一个实例,则抛出谬误
        if (!(result[keyArr[i]] instanceof Object)) {throw new Error('obj.' + keyArr.splice(0, i + 1).join('.') + 'is not Object');
        }

        // 迭代该层属性值
        result = result[keyArr[i]];
      }

      // 设置属性值
      result[keyArr[i]] = val;

      return true;
    } catch (e) {return false;}
  },
};

应用 promise 来实现

创立 enhancedObject 函数

const enhancedObject = (target) =>
  new Proxy(target, {get(target, property) {if (property in target) {return target[property];
      } else {return searchFor(property, target); // 理论应用时要对 value 值进行复位
      }
    },
  });

let value = null;
function searchFor(property, target) {for (const key of Object.keys(target)) {if (typeof target[key] === "object") {searchFor(property, target[key]);
    } else if (typeof target[property] !== "undefined") {value = target[property];
      break;
    }
  }
  return value;
}

应用 enhancedObject 函数

const data = enhancedObject({
  user: {
    name: "test",
    settings: {theme: "dark",},
  },
});

console.log(data.user.settings.theme); // dark
console.log(data.theme); // dark

以上代码运行后,控制台会输入以下代码:

dark
dark

通过观察以上的输入后果可知,应用 enhancedObject 函数解决过的对象,咱们就能够不便地拜访一般对象外部的深层属性。

实现 bind

实现 bind 要做什么

  • 返回一个函数,绑定 this,传递预置参数
  • bind 返回的函数能够作为构造函数应用。故作为构造函数时应使得 this 生效,然而传入的参数仍然无效
// mdn 的实现
if (!Function.prototype.bind) {Function.prototype.bind = function(oThis) {if (typeof this !== 'function') {
      // closest thing possible to the ECMAScript 5
      // internal IsCallable function
      throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable');
    }

    var aArgs   = Array.prototype.slice.call(arguments, 1),
        fToBind = this,
        fNOP    = function() {},
        fBound  = function() {
          // this instanceof fBound === true 时, 阐明返回的 fBound 被当做 new 的结构函数调用
          return fToBind.apply(this instanceof fBound
                 ? this
                 : oThis,
                 // 获取调用时 (fBound) 的传参.bind 返回的函数入参往往是这么传递的
                 aArgs.concat(Array.prototype.slice.call(arguments)));
        };

    // 保护原型关系
    if (this.prototype) {
      // Function.prototype doesn't have a prototype property
      fNOP.prototype = this.prototype; 
    }
    // 上行的代码使 fBound.prototype 是 fNOP 的实例, 因而
    // 返回的 fBound 若作为 new 的构造函数,new 生成的新对象作为 this 传入 fBound, 新对象的__proto__就是 fNOP 的实例
    fBound.prototype = new fNOP();

    return fBound;
  };
}

渲染几万条数据不卡住页面

渲染大数据时,正当应用 createDocumentFragmentrequestAnimationFrame,将操作切分为一小段一小段执行。

setTimeout(() => {
  // 插入十万条数据
  const total = 100000;
  // 一次插入的数据
  const once = 20;
  // 插入数据须要的次数
  const loopCount = Math.ceil(total / once);
  let countOfRender = 0;
  const ul = document.querySelector('ul');
  // 增加数据的办法
  function add() {const fragment = document.createDocumentFragment();
    for(let i = 0; i < once; i++) {const li = document.createElement('li');
      li.innerText = Math.floor(Math.random() * total);
      fragment.appendChild(li);
    }
    ul.appendChild(fragment);
    countOfRender += 1;
    loop();}
  function loop() {if(countOfRender < loopCount) {window.requestAnimationFrame(add);
    }
  }
  loop();}, 0)

实现一个 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"}

防止在不必要的状况下应用 evaleval() 是一个危险的函数,他执行的代码领有着执行者的权力。如果你用 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 代码的作用,然而在理论的编程中并不举荐应用

退出移动版