1. {
  2. for (var i = 1; i <= 3; i++) {
  3. console.log(i); // 1 2 3
  4. // setTimeout(function () {
  5. // console.log(i); // 4 4 4
  6. // }, 0);
  7. }
  8. }
  9. {
  10. var a = null;
  11. console.log(typeof a); // object
  12. }
  13. {
  14. var a = 100;
  15. function test() {
  16. console.log(a); // 100
  17. a = 10;
  18. console.log(a); // 10
  19. }
  20. test();
  21. console.log(a); // 10
  22. }
  23. {
  24. var uname = "jack";
  25. function change() {
  26. console.log(uname); // undefined
  27. var uname = "wcd";
  28. console.log(uname); // wcd
  29. }
  30. change();
  31. }
  32. {
  33. function createBase(baseNumber) {
  34. return function (N) {
  35. return baseNumber + N;
  36. };
  37. }
  38. let addSix = createBase(6);
  39. console.log(addSix(10)); // 16
  40. console.log(addSix(21)); // 27
  41. }
  42. {
  43. var name = "global";
  44. var obj = {
  45. name: "obj",
  46. sex: function () {
  47. this.name = "wcd";
  48. return function () {
  49. return this.name;
  50. };
  51. }
  52. };
  53. console.log(obj.sex().call(this)); // undefined
  54. console.log(obj.sex().call(obj)); // wcd
  55. }
  56. {
  57. /**
  58. * 需求:假设需要对字符串进行字符长度限制
  59. * str为字符串,len为长度
  60. */
  61. function setString(str, len) {
  62. var strlen = 0;
  63. var s = "";
  64. for (var i = 0; i < str.length; i++) {
  65. if (str.charCodeAt(i) > 128) {
  66. strlen += 2;
  67. } else {
  68. strlen++;
  69. }
  70. s += str.charAt(i);
  71. if (strlen >= len) {
  72. return s + "...";
  73. }
  74. }
  75. return s;
  76. }
  77. }
  78. {
  79. const isType = (obj, type) => {
  80. if (typeof obj !== 'object') return false;
  81. const typeString = Object.prototype.toString.call(obj);
  82. let flag;
  83. switch (type) {
  84. case 'Array':
  85. flag = typeString === '[object Array]';
  86. break;
  87. case 'Date':
  88. flag = typeString === '[object Date]';
  89. break;
  90. case 'RegExp':
  91. flag = typeString === '[object RegExp]';
  92. break;
  93. default:
  94. flag = false;
  95. }
  96. return flag;
  97. }
  98. const getRegExp = re => {
  99. var flags = '';
  100. if (re.global) flags += 'g';
  101. if (re.ignoreCase) flags += 'i';
  102. if (re.multiline) flags += 'm';
  103. return flags;
  104. }
  105. }

1~100的完全平方数

  1. {
  2. // 1~100的完全平方数
  3. function isSqrt(n) {
  4. for (var i = 1; n > 0; i += 2) {
  5. n -= i;
  6. }
  7. return 0 == n;
  8. }
  9. for (var j = 1; j <= 100; j++) {
  10. if (isSqrt(j)) {
  11. console.log(j); // 1 4 9 16 25 36 49 64 81 100
  12. }
  13. }
  14. }

统计数组中相同项的个数

  1. {
  2. // 统计数组中相同项的个数
  3. var cars = ["xiaoming", "xiaohong", "xiaohong", "xiaohong", "xiaolv", "xiaolan", "xiaohei"];
  4. var carsObj = cars.reduce(function (obj, name) {
  5. obj[name] = obj[name] ? ++obj[name] : 1;
  6. return obj;
  7. }, {});
  8. console.log(carsObj); // { xiaoming: 1, xiaohong: 3, xiaolv: 1, xiaolan: 1, xiaohei: 1 }
  9. }

判断数组或者一个字符串中出现次数最多的元素及其出现的次数

  1. {
  2. // 判断数组或者一个字符串中出现次数最多的元素及其出现的次数
  3. function maxCountElement(arr) {
  4. var obj = {};
  5. for (var i = 0; i < arr.length; i++) {
  6. var key = arr[i];
  7. if (obj[key]) {
  8. obj[key]++;
  9. } else {
  10. obj[key] = 1;
  11. }
  12. }
  13. var maxCount = 0;
  14. var maxElement = arr[0];
  15. var eq = [];
  16. for (var key in obj) {
  17. if (maxCount < obj[key]) {
  18. maxCount = obj[key];
  19. maxElement = key;
  20. eq.length = 0;
  21. } else if (maxCount === obj[key]) {
  22. eq.push(key);
  23. }
  24. }
  25. if (eq.length > 0) {
  26. for (var j = 0; j < eq.length; j++) {
  27. maxElement += "," + eq[j];
  28. }
  29. }
  30. return `该数组中出现次数最多的元素:${maxElement},出现了:${maxCount}次`;
  31. }
  32. var arr = [1, 2, 2, 2, 3, 3, 3, 4, 5, 6];
  33. var res = maxCountElement(arr);
  34. console.log(res); // 该数组中出现次数最多的元素:2,3,出现了:3次
  35. }

判断回文字符串

  1. {
  2. // 实现一个函数,判断输入是不是回文字符串(在我的理解,如果将一个字符串翻转过来,能和原字符串完全相等,那么就可以称之为“回文”)
  3. // one
  4. function Palindrome1(input) {
  5. if (typeof input !== "string") return false;
  6. return (input.split("").reverse().join("") === input);
  7. }
  8. // two
  9. function Palindrome2(line) {
  10. line += "";
  11. for (var i = 0, j = line.length - 1; i < j; i++, j--) {
  12. if (line.charAt(i) !== line.charAt(j)) {
  13. return false;
  14. }
  15. }
  16. return true;
  17. }
  18. }

trim

  1. {
  2. String.prototype.trim = function () {
  3. return this.replace(/^\s+/, "").replace(/\s+$/, "");
  4. };
  5. }
  6. {
  7. // 正则实现trim()功能
  8. function myTrim(str) {
  9. let reg = /^\s+|\s+$/g;
  10. return str.replace(reg, "");
  11. }
  12. let str = " wcd ";
  13. console.log(myTrim(str)); // wcd
  14. }

检测平台(设备)类型

  1. {
  2. // 检测平台(设备)类型
  3. let isWechat = /micromessenger/i.test(navigator.userAgent),
  4. isWeibo = /weibo/i.test(navigator.userAgent),
  5. isQQ = /qq\//i.test(navigator.userAgent),
  6. isIOS = /(iphone|ipod|ipad|ios)/i.test(navigator.userAgent),
  7. isAndroid = /android/i.test(navigator.userAgent);
  8. }

获取 URL 的中参数

  1. {
  2. // 获取 URL 的中参数 (推荐 https://github.com/derek-watson/jsUri)
  3. // 正则
  4. function getQueryString(name) {
  5. var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)", "i");
  6. var r = window.location.search.substr(1).match(reg); //获取url中"?"符后的字符串并正则匹配
  7. var context = "";
  8. if (r != null) context = r[2];
  9. reg = null;
  10. r = null;
  11. return context == null || context == "" || context == "undefined" ? "" : context;
  12. }
  13. // such as:
  14. // alert(GetQueryString("参数名1"));
  15. // alert(GetQueryString("参数名2"));
  16. // alert(GetQueryString("参数名3"));
  17. // split拆分法
  18. function GetRequest() {
  19. var url = location.search; //获取url中"?"符后的字串
  20. var theRequest = new Object();
  21. if (url.indexOf("?") != -1) {
  22. var str = url.substr(1);
  23. strs = str.split("&");
  24. for (var i = 0; i < strs.length; i++) {
  25. theRequest[strs[i].split("=")[0]] = unescape(strs[i].split("=")[1]);
  26. }
  27. }
  28. return theRequest;
  29. }
  30. var Request = new Object();
  31. Request = GetRequest();
  32. // var 参数1,参数2,参数3,参数N;
  33. // 参数1 = Request['参数1'];
  34. // 参数2 = Request['参数2'];
  35. // 参数3 = Request['参数3'];
  36. // 参数N = Request['参数N'];
  37. // 修改 URL 的中某个参数值
  38. //替换指定传入参数的值,paramName为参数,replaceWith为新值
  39. function replaceParamVal(paramName, replaceWith) {
  40. var oUrl = this.location.href.toString();
  41. var re = eval("/(" + paramName + "=)([^&]*)/gi");
  42. var nUrl = oUrl.replace(re, paramName + "=" + replaceWith);
  43. this.location = nUrl;
  44. window.location.href = nUrl;
  45. }
  46. /**
  47. * 指定参数名称,返回该参数的值 或者 空字符串
  48. * 不指定参数名称,返回全部的参数对象 或者 {}
  49. * 如果存在多个同名参数,则返回数组
  50. */
  51. function getUrlParam(url, key) {
  52. var arr = {};
  53. url.replace(/\??(\w+)=(\w+)&?/g, function (match, matchKey, matchValue) {
  54. if (!arr[matchKey]) {
  55. arr[matchKey] = matchValue;
  56. } else {
  57. var temp = arr[matchKey];
  58. arr[matchKey] = [].concat(temp, matchValue);
  59. }
  60. });
  61. if (!key) {
  62. return arr;
  63. } else {
  64. for (ele in arr) {
  65. if ((ele = key)) {
  66. return arr[ele];
  67. }
  68. }
  69. return "";
  70. }
  71. }
  72. }

H5(ios)-在点击输入框,出现键盘后,弹出层被顶上去,而光标还停留在原处,即出现错位情况

  1. {
  2. // 单个input(textarea)
  3. $("input.van-field__control, textarea.van-field__control").blur(function () {
  4. setTimeout(function () {
  5. var currentPosition = document.documentElement.scrollTop || document.body.scrollTop;
  6. window.scrollTo(0, currentPosition); //页面向上滚动
  7. }, 200);
  8. });
  9. // 多个input(textarea)
  10. $(function () {
  11. var setTimerTop = 0;
  12. $(document).on('blur', 'input.van-field__control, textarea.van-field__control', function () {
  13. event.preventDefault()
  14. setTimerTop = setTimeout(function () {
  15. window.scrollBy(0, 5); // 页面向上滚动
  16. window.scrollBy(0, -5);
  17. }, 500)
  18. }).on('focus', 'input.van-field__control, textarea.van-field__control', function () {
  19. clearTimeout(setTimerTop)
  20. })
  21. })
  22. // 多个input(textarea)-iframe情况
  23. $(function() {
  24. var setTimerTop = 0;
  25. $(document).on('blur', 'input.van-field__control, textarea.van-field__control', function() {
  26. event.preventDefault()
  27. setTimerTop = setTimeout(function() {
  28. parent.scrollBy(0, 5); // 页面向上滚动
  29. parent.scrollBy(0, -5);
  30. $('#hide-area-cb').focus();
  31. }, 500)
  32. }).on('focus', 'input.van-field__control, textarea.van-field__control', function() {
  33. clearTimeout(setTimerTop);
  34. }).on('focus', 'input.van-field__control[disabled]', function() {
  35. setTimerTop = setTimeout(function() {
  36. parent.scrollBy(0, 5); // 页面向上滚动
  37. parent.scrollBy(0, -5);
  38. }, 500)
  39. })
  40. })
  41. }

判断类型

  1. // 判断类型
  2. function toType(obj) {
  3. return {}.toString.call(obj).match(/\s([a-zA-Z]+)/)[1].toLowerCase();
  4. }

对象判空

注:永远不要使用构造函数创建对象

  1. {
  2. function isEmptyObject(value) {
  3. return (
  4. value && Object.keys(value).length === 0 && value.constructor === Object
  5. );
  6. }
  7. }
  8. {
  9. function isEmptyObject(value) {
  10. return (
  11. Object.prototype.toString.call(value) === "[object Object]" &&
  12. JSON.stringify(value) === "{}"
  13. );
  14. }
  15. }
  16. // Lodash
  17. _.isEmpty({});
  18. // jQuery
  19. jQuery.isEmptyObject({});

函数防抖

  1. {
  2. // 简单 函数防抖
  3. function debounce(method, wait) {
  4. let timeout;
  5. // args为返回函数调用时传入的参数,传给method
  6. return function (...args) {
  7. let context = this;
  8. if (timeout) {
  9. clearTimeout(timeout);
  10. }
  11. timeout = setTimeout(() => {
  12. // args是一个数组,所以使用fn.apply
  13. // 也可写作method.call(context, ...args)
  14. method.apply(context, args);
  15. }, wait);
  16. };
  17. }
  18. // 完整 函数防抖
  19. function debounce(method, wait, immediate) {
  20. let timeout;
  21. // debounced函数为返回值
  22. // 使用Async/Await处理异步,如果函数异步执行,等待setTimeout执行完,拿到原函数返回值后将其返回
  23. // args为返回函数调用时传入的参数,传给method
  24. let debounced = function (...args) {
  25. return new Promise(resolve => {
  26. // 用于记录原函数执行结果
  27. let result;
  28. // 将method执行时this的指向设为debounce返回的函数被调用时的this指向
  29. let context = this;
  30. // 如果存在定时器则将其清除
  31. if (timeout) {
  32. clearTimeout(timeout);
  33. }
  34. // 立即执行需要两个条件,一是immediate为true,二是timeout未被赋值或被置为null
  35. if (immediate) {
  36. // 如果定时器不存在,则立即执行,并设置一个定时器,wait毫秒后将定时器置为null
  37. // 这样确保立即执行后wait毫秒内不会被再次触发
  38. let callNow = !timeout;
  39. timeout = setTimeout(() => {
  40. timeout = null;
  41. }, wait);
  42. // 如果满足上述两个条件,则立即执行并记录其执行结果
  43. if (callNow) {
  44. result = method.apply(context, args);
  45. resolve(result);
  46. }
  47. } else {
  48. // 如果immediate为false,则等待函数执行并记录其执行结果
  49. // 并将Promise状态置为fullfilled,以使函数继续执行
  50. timeout = setTimeout(() => {
  51. // args是一个数组,所以使用fn.apply
  52. // 也可写作method.call(context, ...args)
  53. result = method.apply(context, args);
  54. resolve(result);
  55. }, wait);
  56. }
  57. });
  58. };
  59. // 在返回的debounced函数上添加取消方法
  60. debounced.cancel = function () {
  61. clearTimeout(timeout);
  62. timeout = null;
  63. };
  64. return debounced;
  65. }
  66. }

生成 -0

  1. // one
  2. // 首先创建一个8位的ArrayBuffer
  3. const buffer = new ArrayBuffer(8);
  4. // 创建DataView对象操作buffer
  5. const dataView = new DataView(buffer);
  6. // 将第1个字节设置为0x80,即最高位为1
  7. dataView.setUint8(0, 0x80);
  8. // 将buffer内容当做Float64类型返回
  9. console.log(dataView.getFloat64(0)); // -0
  10. // two
  11. console.log(0 * -1); // -0

reduce

  1. {
  2. // 对后端返回的列表数据进行相同数据整合处理
  3. let oldList = [
  4. { id: 111, date: "05-25", list: [1, 2, 3] },
  5. { id: 222, date: "05-26", list: [4, 5] },
  6. { id: 111, date: "05-25", list: [4, 5] }
  7. ];
  8. function formatList() {
  9. return Array.from(
  10. oldList.reduce((dict, item) => {
  11. if (dict.has(item.id)) {
  12. dict.get(item.id).list.push(...item.list);
  13. } else {
  14. dict.set(item.id, {
  15. id: item.id,
  16. date: item.date,
  17. list: [...item.list]
  18. });
  19. }
  20. return dict;
  21. }, new Map())
  22. ).map(item => ({
  23. date: item[1].date,
  24. id: item[1].id,
  25. list: item[1].list
  26. }));
  27. }
  28. console.log(formatList());
  29. // [
  30. // { id: 111, date: "05-25", list: [1, 2, 3, 4, 5] },
  31. // { id: 222, date: "05-26", list: [4, 5] }
  32. // ];
  33. // 数组list去重
  34. const data = [
  35. { name: "Kris", age: "24" },
  36. { name: "Andy", age: "25" },
  37. { name: "Kitty", age: "25" },
  38. { name: "Andy", age: "25" },
  39. { name: "Kitty", age: "25" },
  40. { name: "Andy", age: "25" },
  41. { name: "Kitty", age: "25" }
  42. ];
  43. let newData = Object.values(
  44. data.reduce((prev, cur, idx) => {
  45. let obj = {};
  46. const { name } = cur;
  47. obj[name] = cur;
  48. return {
  49. ...prev,
  50. ...obj
  51. };
  52. }, {})
  53. );
  54. console.log(newData)
  55. }
  56. {
  57. /**
  58. * reduce方法同时实现map和filter
  59. * 需求:假设现在有一个数列,你希望更新它的每一项(map的功能)然后筛选出一部分(filter的功能)。如果是先使用map然后filter的话,你需要遍历这个数组两次。 在下面的代码中,我们将数列中的值翻倍,然后挑选出那些大于50的数
  60. */
  61. const numbers = [10, 20, 30, 40];
  62. const doubledOver50 = numbers.reduce((finalList, num) => {
  63. num = num * 2;
  64. if (num > 50) {
  65. finalList.push(num);
  66. }
  67. return finalList;
  68. }, []);
  69. console.log(doubledOver50); // [ 60, 80 ]
  70. }

实现数字金额转大写金额

  1. function digitUppercase(n) {
  2. let fraction = ["角", "分"];
  3. let digit = ["零", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖"];
  4. let unit = [
  5. ["元", "万", "亿"],
  6. ["", "拾", "佰", "仟"]
  7. ];
  8. let head = n < 0 ? "欠" : "";
  9. n = Math.abs(n);
  10. let s = "";
  11. for (let i = 0; i < fraction.length; i++) {
  12. s += (digit[Math.floor(n * 10 * Math.pow(10, i)) % 10] + fraction[i]).replace(/零./, "");
  13. }
  14. s = s || "整";
  15. n = Math.floor(n);
  16. for (let k = 0; k < unit[0].length && n > 0; k++) {
  17. let p = "";
  18. for (let j = 0; j < unit[1].length && n > 0; j++) {
  19. p = digit[n % 10] + unit[1][j] + p;
  20. n = Math.floor(n / 10);
  21. }
  22. s = `${p.replace(/(零.)*零$/, "").replace(/^$/, "零")}${unit[0][k]}${s}`;
  23. }
  24. return `${head}${s.replace(/(零.)*零元/, "元").replace(/(零.)+/g, "零").replace(/^整$/, "零元整")}`;
  25. }
  26. console.log(digitUppercase(7682.01)); // 柒仟陆佰捌拾贰元壹分
  27. console.log(digitUppercase(7682)); // 柒仟陆佰捌拾贰元整
  28. console.log(digitUppercase(951434677682.0)); // 玖仟伍佰壹拾肆亿叁仟肆佰陆拾柒万柒仟陆佰捌拾贰元整
  29. function noToChinese(num) {
  30. if (!/^\d*(\.\d*)?$/.test(num)) return;
  31. var digit = new Array("零", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖");
  32. var unit = new Array("", "拾", "佰", "仟", "萬", "億", "点", "");
  33. var a = ("" + num).replace(/(^0*)/g, "").split("."),
  34. k = 0,
  35. re = "";
  36. for (var i = a[0].length - 1; i >= 0; i--) {
  37. switch (k) {
  38. case 0:
  39. re = unit[7] + re;
  40. break;
  41. case 4:
  42. if (!new RegExp("0{4}\\d{" + (a[0].length - i - 1) + "}$").test(a[0]))
  43. re = unit[4] + re;
  44. break;
  45. case 8:
  46. re = unit[5] + re;
  47. unit[7] = unit[5];
  48. k = 0;
  49. break;
  50. }
  51. if (k % 4 == 2 && a[0].charAt(i + 2) != 0 && a[0].charAt(i + 1) == 0)
  52. re = digit[0] + re;
  53. if (a[0].charAt(i) != 0) re = digit[a[0].charAt(i)] + unit[k % 4] + re;
  54. k++;
  55. }
  56. // 处理小数部分
  57. if (a.length > 1) {
  58. re += unit[6];
  59. for (var i = 0; i < a[1].length; i++) re += digit[a[1].charAt(i)];
  60. }
  61. return re;
  62. }

返回字符串的字节长度

  1. function byteSize(str) {
  2. return new Blob([str]).size;
  3. }
  4. console.log(byteSize("Hello World")); // 11

平均数

  1. // 平均数
  2. const average = (...nums) => nums.reduce((acc, val) => acc + val, 0) / nums.length;
  3. console.log(average(...[1, 2, 3])); // 2
  4. console.log(average(1, 2, 3)); // 2

日期

  1. // 当前日期天数
  2. const dayOfYear = date => Math.floor((date - new Date(date.getFullYear(), 0, 0)) / 1000 / 60 / 60 / 24);
  3. console.log(dayOfYear(new Date())); // 302
  4. // 返回日期间的天数
  5. const getDaysDiffBetweenDates = (dateInitial, dateFinal) => (dateFinal - dateInitial) / (1000 * 3600 * 24);
  6. console.log(getDaysDiffBetweenDates(new Date('2019-01-01'), new Date('2019-10-29'))); // 301

解析有效日期

iOS 解析 YYYY-MM-DD HH:mm:ss 这种日期格式会报错 Invalid Date,Android 无问题
查看开发手册发现可用:YYYY/MM/DD HH:mm:ss,那么需替换其中的 - 为 /

  1. const date = "2021-02-05 10:39:00";
  2. new Date(date.replace(/\-/g, "/"));

首(每个)字母大、小写

  1. // 首字母大写
  2. const capitalize = ([first, ...rest]) => first.toUpperCase() + rest.join('');
  3. console.log(capitalize('fooBar')); // FooBar
  4. console.log(capitalize('fooBar', true)); // FooBar
  5. // 首字母小写
  6. const decapitalize = ([first, ...rest]) => first.toLowerCase() + rest.join('');
  7. console.log(decapitalize('FooBar')); // fooBar
  8. console.log(decapitalize('FooBar')); // fooBar
  9. // 每个单词首字母大写
  10. const capitalizeEveryWord = str => str.replace(/\b[a-z]/g, char => char.toUpperCase());
  11. console.log(capitalizeEveryWord('hello world!')); // 'Hello World!'

平滑滚动至顶部

  1. const scrollToTop = () => {
  2. const c = document.documentElement.scrollTop || document.body.scrollTop;
  3. if (c > 0) {
  4. window.requestAnimationFrame(scrollToTop);
  5. window.scrollTo(0, c - c / 8);
  6. }
  7. };

滚动到指定元素区域

  1. const smoothScroll = element =>
  2. document.querySelector(element).scrollIntoView({
  3. behavior: 'smooth'
  4. });
  5. smoothScroll('#fooBar');

深克隆

  1. const clone = parent => {
  2. // 维护两个储存循环引用的数组
  3. const parents = [];
  4. const children = [];
  5. const _clone = parent => {
  6. if (parent === null) return null;
  7. if (typeof parent !== 'object') return parent;
  8. let child, proto;
  9. if (isType(parent, 'Array')) {
  10. // 对数组做特殊处理
  11. child = [];
  12. } else if (isType(parent, 'RegExp')) {
  13. // 对正则对象做特殊处理
  14. child = new RegExp(parent.source, getRegExp(parent));
  15. if (parent.lastIndex) child.lastIndex = parent.lastIndex;
  16. } else if (isType(parent, 'Date')) {
  17. // 对Date对象做特殊处理
  18. child = new Date(parent.getTime());
  19. } else {
  20. // 处理对象原型
  21. proto = Object.getPrototypeOf(parent);
  22. // 利用Object.create切断原型链
  23. child = Object.create(proto);
  24. }
  25. // 处理循环引用
  26. const index = parents.indexOf(parent);
  27. if (index != -1) {
  28. // 如果父数组存在本对象,说明之前已经被引用过,直接返回此对象
  29. return children[index];
  30. }
  31. parents.push(parent);
  32. children.push(child);
  33. for (let i in parent) {
  34. // 递归
  35. child[i] = _clone(parent[i]);
  36. }
  37. return child;
  38. };
  39. return _clone(parent);
  40. };
  41. {
  42. const isComplexDataType = (obj) => (typeof obj === "object" || typeof obj === "function") && obj !== null;
  43. const deepClone = function (obj, hash = new WeakMap()) {
  44. // 日期对象直接返回一个新的日期对象
  45. if (obj.constructor === Date) {
  46. return new Date(obj);
  47. }
  48. //正则对象直接返回一个新的正则对象
  49. if (obj.constructor === RegExp) {
  50. return new RegExp(obj);
  51. }
  52. //如果循环引用了就用 weakMap 来解决
  53. if (hash.has(obj)) {
  54. return hash.get(obj);
  55. }
  56. let allDesc = Object.getOwnPropertyDescriptors(obj);
  57. //遍历传入参数所有键的特性
  58. let cloneObj = Object.create(Object.getPrototypeOf(obj), allDesc);
  59. //继承原型链
  60. hash.set(obj, cloneObj);
  61. for (let key of Reflect.ownKeys(obj)) {
  62. cloneObj[key] =
  63. isComplexDataType(obj[key]) && typeof obj[key] !== "function"
  64. ? deepClone(obj[key], hash)
  65. : obj[key];
  66. }
  67. return cloneObj;
  68. };
  69. }