Giter Club home page Giter Club logo

fe-practice-hard's Issues

第 23 期(ECMAScript-语法):字符串对象HTML格式替代方法

题目:

已知有如下 HTML 结构,请编写函数 format,实现点击对应按钮后对 #str 文本进行加粗、斜体、上标或下标格式化。

提示:请使用 HTML 格式替代方法

<span id="str">儿童节快乐!</span>
<p>
  <button onclick="format(1)">加粗</button>
  <button onclick="format(2)">斜体</button>
  <button onclick="format(3)">上标</button>
  <button onclick="format(4)">下标</button>
</p>

参考答案:

function format(type) {
  let text = str.innerText || str.textContent;
  let result;

  switch(type) {
    case 1:
      result = text.bold();
      break;
    case 2:
      result = text.italics();
      break;
    case 3:
      result = text.sup();
      break;
    case 4:
      result = text.sub();
      break;      
    default:
      result = text;  
  }

  str.innerHTML = result;
}

第 17 期(W3C标准-HTML):ol标签计数器

题目:

已知有如下 HTML 结构:

<ol>
  <li>第 1 项</li>
  <li>第 2 项</li>
  <li>第 3 项</li>
  <li>第 4 项</li>
</ol>

默认情况下会渲染出一个从1到4的数字序号列表,如将列表第 2 项的 style 设置为 display: none,则其后面的序号是否会变动?如换成设为 visibility: hidden 呢?为什么?


参考答案:
应用 display: none 的元素不可见、不占据空间、辅助设备无法访问,而且该元素不会被渲染,所以计数器自动跳过第二项,第二项后面的序号从 2 开始递增。
应用 visibility: hidden 的元素虽然在视觉上不可见,但依旧占据布局空间,其计数器仍在运行,不会影响计数器的计数。

第 35 期(W3C 标准-CSS-布局排版):图片等比缩放匹配父容器尺寸

题目:

请使用纯 CSS 实现图片等比缩放最大化匹配父容器尺寸的效果:使下面的图片自适应填充父容器尺寸,同时保持宽高比。

要求:

  • 图片不能变形
  • 图片不能被剪裁
  • 图片不能溢出父容器

效果图:
image

.box {
  width: 300px;
  height: 200px;
  padding: 10px;
  border: 1px solid #ccc;
}
<div class="box">
  <img src="https://fezaoduke.github.io/fe-practice-hard/assets/pics/cartoon.png">
</div>

参考答案:

.box > img {
  width: 100%;
  height: 100%;
  object-fit: contain;
}

拓展阅读:object-fit

第 30 期(算法-搜索):二分搜索算法

题目:

请使用 二分搜索算法 编写函数 binarySearch,实现类似 indexOf 的功能。要求:

  • 不要用递归方式实现;
  • 避免产生副作用(即不能修改原数组)。
/**
 * @param {array} arr - 按升序排列的普通数组
 * @param {number} target - 需要在 arr 中搜索的目标值
 * @return {number} 返回 target 在 arr 中的索引值,如不存在,则返回 -1
 */
function binarySearch(arr, target) {
  // 你的代码
}

测试数据:

const test = [1, 3, 8, 9, 27, 34, 128, 275];

binarySearch(test, 128);  // 6
binarySearch(test, 30);  // -1

参考答案:

function binarySearch(arr, target) {
  let startIdx = 0;
  let endIdx = arr.length - 1;
  let midIdx = Math.floor((startIdx + endIdx) / 2);

  while(endIdx - startIdx > 1) {
    switch(target) {
      case arr[startIdx]: return startIdx;
      case arr[endIdx]: return endIdx;
      case arr[midIdx]: return midIdx;
    }

    if (target > arr[midIdx]) {  // 右边找
      startIdx = midIdx;
    } else if (target < arr[midIdx]) {  // 左边找
      endIdx = midIdx;
    }

    midIdx = Math.floor((startIdx + endIdx) / 2);
  }

  return -1;
}

第 28 期(W3C 标准-SVG):用SVG画西瓜

题目:

请使用SVG画一个如下图所示的“西瓜”:

image

尺寸:200×200
颜色:#E92F34(红)、#32AC1A(绿)

<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
  <!-- 请开始你的表演 -->
</svg>

参考答案:

<svg version="1.1" xmlns="http://www.w3.org/2000/svg" viewbox="0 0 208 208">
  <circle
    fill="#E92F34"
    stroke="#32AC1A"
    stroke-width="8"
    cx="104"
    y="100"
    r="100"
  ></circle> 
</svg>

第 44 期(W3C标准-JavaScript-DOM):元素滚动到视区

题目:

有一个条目数量不定的列表,其 HTML 结构如下:

<ul id="list" style="height: 300px; overflow: auto">
  <li>列表项1</li>
  <li>列表项2</li>
  <li>列表项3</li>
  <li>...</li>
  <li>列表项n</li>
</ul>

要求:请使用 javascript 写一个表达式,让列表的最后一项默认可见(滚动到可视区域)


参考答案:

document.querySelector('#list > li:last-child').scrollIntoView();

第 12 期(2019-05-19):同名函数的执行

类型:基础知识
难度:★

有以下 html 文件,请问运行后浏览器控制台输出结果是什么?为什么?

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
</head>
<body>
  <script>
    function fn() {
      console.log(1);
    }
    fn();

    function fn() {
      console.log(2);
    }
    fn();
  </script>
  <script>
    function fn() {
      console.log(3);
    }
    fn();
  </script>
</body>
</html>

参考答案:

控制台依次输出:2, 2, 3

原因:JavaScript 解释器在执行页面脚本时,是按块执行的。具体来讲,就是当浏览器在解析 HTML 文档时,如果遇到一个 script 标签,则 JavaScript 解释器会等到这个代码块都加载完成后(读取到当前代码块的 </script> 标签),先对代码块进行预编译,然后再执行。执行完毕后,浏览器会继续解析下面的 HTML 文档,同时JavaScript 解释器也准备好处理下一个代码块……

上面代码的执行步骤:

  1. 读入第一个代码块(代码块指 <script></script> 中的代码,下同);
  2. 做语法分析,如有语法错误,则报错并停止当前代码块里后续代码的执行,跳到第 5 步;
  3. 对代码块内的所有变量和函数做预编译处理(这里有 2 个重名的 fn 函数,后面一个会覆盖前面一个函数的定义);
  4. 执行代码(这段代码里调用了 2 次 fn(),故依次输出 22);
  5. 读入第二个代码块;
  6. 重复 2 ~ 4,输出 3

题外话:如果 script 标签带有 deferasync 属性,情况有所不同。

相关资料:https://www.jianshu.com/p/bda5266755a2


本期优秀回答者: @AMY-Y

第 34 期(W3C 标准-ECMAScript-语法):js 对象深拷贝

题目:

请编写一个js对象深拷贝的函数,需要考虑循环引用的情况。


参考答案:

function deepCopy(obj) {
  // hash表,记录所有的对象的引用关系
  let map = new WeakMap();

  function dp(obj) {
    let result = null;
    let keys = Object.keys(obj);
    let key = null,
      temp = null,
      existobj = null;
 
    existobj = map.get(obj);

    // 如果这个对象已经被记录则直接返回
    if (existobj) {
      return existobj;
    }
 
    result = {}
    map.set(obj, result);
 
    for (let i = 0; i < keys.length; i++) {
      key = keys[i];
      temp = obj[key];

      if (temp && typeof temp === 'object') {
        result[key] = dp(temp);
      }else {
        result[key] = temp;
      }
    }

    return result;
  }

  return dp(obj);
}

第 4 期(2019-05-11):CSS 菱形剪切

来源:原创题
难度:★

使用纯 CSS 将下面的图片进行菱形剪切。

注:图片不允许拉伸、挤压。实现代码越简单越好。

<!-- html -->
<img src="https://fezaoduke.github.io/fe-practice-hard/assets/pics/cartoon.png">
/* css */
img {
  /* 你的代码 */
}

参考效果图:

image


本期优秀回答者: @liwenkang

第 40 期(HTTP规范-请求过程):HTTP的方法

题目:

HTTP有哪些方法?具体作用分别是什么?


参考答案:

HTTP1.0 定义了三种请求方法: GET, POST 和 HEAD方法
HTTP1.1 新增了五种请求方法:OPTIONS, PUT, DELETE, TRACE 和 CONNECT

具体作用:

  • GET: 通常用于请求服务器发送某些资源
  • HEAD: 请求资源的头部信息, 并且这些头部与 HTTP GET 方法请求时返回的一致. 该请求方法的一个使用场景是在下载一个大文件前先获取其大小再决定是否要下载, 以此可以节约带宽资源
  • OPTIONS: 用于获取目的资源所支持的通信选项
  • POST: 发送数据给服务器
  • PUT: 用于新增资源或者使用请求中的有效负载替换目标资源的表现形式
  • DELETE: 用于删除指定的资源
  • PATCH: 用于对资源进行部分修改
  • CONNECT: HTTP/1.1协议中预留给能够将连接改为管道方式的代理服务器
  • TRACE: 回显服务器收到的请求,主要用于测试或诊断

第 22 期(ECMAScript-原型链 继承):实现 Array map

题目:

请编写一个方法 mapArr,实现与 ES5 规范中数组的 map 方法同样的功能

测试用例:

var data = [1, 2, 3, 4];

var result = data.mapArr(function(it, idx, arr) {
  console.log('当前项', it);
  console.log('当前索引', idx);
  console.log('数组', arr);

  return it * 2;
});

console.log(result);  // [2, 4, 6, 8]

参考答案:

Array.prototype.mapArr = function(fn, context) {
  var arr = Array.prototype.slice.call(this);
  var mappedArr = [];

  for (var i = 0; i < arr.length; i++) {
    mappedArr.push(fn.call(context, arr[i], i, this));
  }

  return mappedArr;
}

第 8 期(2019-05-15):求斐波那契数前N项

来源:面试题
难度:★★

封装一个函数,接收1个整数参数 n,返回 斐波那契数列 前 n 项

/**
 * @param {number} n - 整数
 */
function fibonacci(n) {
  // 你的代码
}

参考答案:

function fibonacci(n) {
  var a = 0;
  var b = 1;
  var c = a + b;
  var arr = [c];

  for (var i = arr.length; i < n; i++) {
    arr.push(c);
    a = b;
    b = c;
    c = a + b;
  }

  return arr;
}

// 再来个使用递归+ES6实现的(原创)
function fibonacci(n) {
  let fn = i => i < 3 ? 1 : fn(i - 1) + fn(i - 2);
  return [...Array(n).keys()].map(it => fn(it + 1));
}

本期优秀回答者: @AMY-Y

第 1 期(2019-05-08):多重排序

这是前端晚练课的第 1 期,希望大家在参与前先去「达成以下 2 个成就」:

  1. 有看过 「前端晚练课的简介、愿景、角色、参与方式和激励措施」
  2. 有阅读过 「答题规范」

来源:原创题
难度:★★

封装一个多重排序函数 multiSort,功能要求:

  1. 接收一个对象数组,返回一个按多个字段名顺序排序后的新数组;
  2. 可自定义排序参照的字段名顺序;

例如:['field2', 'field1', 'field3']

首先按 field2 进行排序,如果 field2 的值相等,则按 field1 排序;如果 field1 的值仍相等,则按 field3 排序……

  1. 可设置排序规则为正序(升序)或倒序(降序),默认为正序。

实战用例:

根据员工数据,评选出月度最佳员工

[
  { "name": "Sweet", "education": 4, "sales": 10, "duty": 24, "workAge": 2 },
  { "name": "Tough", "education": 3, "sales": 15, "duty": 24, "workAge": 6 },
  { "name": "Yummy", "education": 4, "sales": 10, "duty": 24, "workAge": 4 },
  { "name": "Ghost", "education": 6, "sales": 15, "duty": 23, "workAge": 8 },
  { "name": "Flora", "education": 5, "sales": 15, "duty": 24, "workAge": 6 }
]

销售额(sales)、出勤天数(duty)、工龄(workAge)、教育程度(education) 的顺序 降序 排名:

[
  { "name": "Flora", "education": 5, "sales": 15, "duty": 24, "workAge": 6 },
  { "name": "Tough", "education": 3, "sales": 15, "duty": 24, "workAge": 6 },
  { "name": "Ghost", "education": 6, "sales": 15, "duty": 23, "workAge": 8 },
  { "name": "Yummy", "education": 4, "sales": 10, "duty": 24, "workAge": 4 },
  { "name": "Sweet", "education": 4, "sales": 10, "duty": 24, "workAge": 2 }
]

参考答案:

function multiSort(arr, rules, reversal) {
  return [...arr].sort((o, p) => {
    let a, b;

    for (let rule of rules) {
      a = o[rule];
      b = p[rule];

      if (a !== b) {
        return (a - b) * (reversal ? -1 : 1);
      }
    }
  });
}

// 或者挂载到 Array 构造函数的原型上
Array.prototype.multiSort = function(rules, reversal) {
  return [...this].sort((o, p) => {
    // 逻辑代码同上,此处略
  });
}

本期优秀回答者: @cnyballk

第 3 期(2019-05-10):无重复字符的最长子串

来源:leetcode
难度:★★★

给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。

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

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

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


本期优秀回答者: @cnyballk

第 33 期(W3C 标准-HTML):汉语拼音

题目:

实现如下图所示布局效果:

image


参考答案:

<ruby><rt>&nbsp;chuǎng&nbsp;</rt><rt>&nbsp;qián&nbsp;</rt><rt>&nbsp;mǐng&nbsp;</rt><rt>&nbsp;yuè&nbsp;</rt><rt>&nbsp;guāng&nbsp;</rt>
</ruby>

第 11 期(2019-05-18):arguments与'use strict'

入门级
 难度★
请分别写出在浏览器控制台执行以下代码的结果
        function b(x,y,a){
            arguments[2]=10;
            console.log(a);
        };
        b(1,2,3);
        function b(x,y,a){
            'use strict'
            arguments[2]=10;
            console.log(a);
        };
        b(1,2,3);

第 7 期(2019-05-14):n以内的随机数

来源:原创题
难度:★

封装一个函数,接收一个整数参数 n ,返回 n 以内的随机整数 m (0 <= m < n)

/**
 * @param {number} n - 随机数最大范围
 */
function getRandomNum(n) {
  // 你的代码
}

参考答案:

// 方法1
function getRandomNum(n) {
  return Math.floor(Math.random() * n);
}

// 方法2
function getRandomNum(n) {
  return ~~(Math.random() * n);
}

// 方法3
function getRandomNum(n) {
  return (Math.random() * n) >>> 0;
}

// 方法4
function getRandomNum(n) {
  return Math.random() * n | 0;
}

本期最佳回答者: @AMY-Y

第 18 期(W3C标准-HTML):a 标签

题目:

使用 a 标签分别实现下面的功能:

  1. 下载一张图片:<img src="images/photo.jpg">
  2. 呼出拨打电话给 4006-066-066 的界面(手机端)
  3. 呼出发送短信给 10086 的界面(手机端)
  4. 呼出本地邮件客户端发送邮件给 [email protected] 的界面

参考答案:

<!-- 第 1 题 -->
<a href="images/photo.jpg" download>
  <img src="images/photo.jpg">
</a>

<!-- 第 2 题。也可省略中划线,效果都一样 -->
<a href="tel:4006-066-066">4006-066-066</a>

<!-- 第 3 题 -->
<a href="sms:10086">发短信给10086</a>

<!-- 第 4 题 -->
<a href="mailto:[email protected]">[email protected]</a>

第 27 期(ECMAScript-正则表达式):金额数值格式化

题目:

请实现一个按千分位格式化金额数值的功能

function formatMoney(num) {
  // 你的代码
}

测试用例:

formatMoney(100);  // 100.00
formatMoney(1000);  // 1,000.00
formatMoney(1000.56);  // 1,000.56
formatMoney(1000000000.25);  // 1,000,000,000.25

参考答案:

function formatMoney(num) {
  // 字符串捕获(零宽度正预测先行断言)
  let regex = /\d{1,3}(?=(\d{3})+$)/g;

  // 将字符串拆分成“符号”(如有)、“整数位”和“小数位”三部分
  return String(num).replace(/^(-|\+?)(\d+)((\.\d+)?)$/, (s, s1, s2, s3) => (
    // $&表示 replace() 函数第一个正则表达式参数所匹配的内容
    s1 + s2.replace(regex, '$&,') + s3
  ));
}

相关资料:正则表达式零宽断言

第 41 期W3C标准-JavaScript-DOM):点击空白处检测

题目:

<div id="box">
  <h2>酱油君1</h2>
  <p>酱油君2</p>
  <div>
    <input type="text">
    <button>按钮</button>
  </div>
</div>
#box {
  position: absolute;
  top: 20%;
  left: 40%;
  width: 300px;
  padding: 1em;
  background: #f5f5f5;
  border: 1px solid #ccc;
}

请编写一个方法,实现点击 #box(含内部元素)时,浏览器控制台输出 "inner",点击 #box 外部空白处时输出 "outer"


参考答案:

const box = document.getElementById('box');

window.addEventListener('click', e => {
  let elm = e.target;

  if (elm === box || box.contains(elm)) {  // 自身或内部元素
    console.log('inner');
  } else {
    console.log('outter');
  }
});

Node.contains 方法

第 36 期(W3C 标准-JavaScript-异步):实现一个Promise方法

题目:

请实现一个合乎规范的 Promise 方法。

参考答案:

class Promise {
  constructor (fn) {
    // 三个状态
    this.state = 'pending'
    this.value = undefined
    this.reason = undefined
    let resolve = value => {
      if (this.state === 'pending') {
        this.state = 'fulfilled'
        this.value = value
      }
    }
    let reject = value => {
      if (this.state === 'pending') {
        this.state = 'rejected'
        this.reason = value
      }
    }
    // 自动执行函数
    try {
      fn(resolve, reject)
    } catch (e) {
      reject(e)
    }
  }
  // then
  then(onFulfilled, onRejected) {
    switch (this.state) {
      case 'fulfilled':
        onFulfilled()
        break
      case 'rejected':
        onRejected()
        break
      default:
    }
  }
}

/**
 * 作者:陈煜仑
 * 链接:https://juejin.im/post/5d2ee123e51d4577614761f8
 * 来源:掘金
 * 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
 */

第 14 期(2019-05-21):类型判断

类型:基础知识
难度:★

实现 isObject(X), isString(X), isArray(X) 三个方法,用以判断是否为对应类型,返回布尔值

测试用例:

isObject([1, 2]);  // false
isString(123);  // false
isArray({a: 1});  // false

isObject({a: 1});  // true
isString('123');  // true
isArray([1, 2]);  // true

参考答案:

非常有价值的一段代码,类型判断的神码,函数柯里化的入门级教学代码。(来自 seajs 源码)

function isType(type) {
  return function(obj) {
    return Object.prototype.toString.call(obj) === '[object ' + type + ']'
  }
}

var isObject = isType('Object');
var isString = isType('String');
var isArray = Array.isArray || isType('Array');

第 2 期(2019-05-09):定时输出数字

来源:经典面试题
难度:★

编写一个方法,每隔 1s 依次在控制台打印出 5, 4, 3, 2, 1


参考答案:

请参考 @liwenkang 的答案,很全面。

@Wxh16144 的答案也不错,代码很优雅。

async function display() {
  for (let i = 5; i > 0; i--) {
    let num = await new Promise(resolve => {
      setTimeout(() => {
        resolve(i)
      }, 1e3)
    });

    console.log(num)
  }
}

display();

本期优秀回答者: @liwenkang

第 9 期(2019-05-16):CSS兼容性验证

类型:常用技巧
难度:★★☆

封装一个特性检测函数,用以验证当前浏览器是否支持某个 CSS 属性

注:需要兼容 IE8+(含)以及其他主流浏览器

/**
 * @param {string} [prop] - 需要验证的 CSS 属性名。
 * @return:
      1. 当 `prop` 为字符串时,返回当前浏览器是否支持该 CSS 属性的布尔值
      2. 当 `prop` 为空时,返回一个由当前浏览器支持的所有 CSS 属性名组成的数组
 */
function supported(prop) {
  // 你的代码
}

测试用例: (以下结果来自 Chrome 74)

supported('animation');  // true
supported('background-clip');  // true
supported('mix-blend-mode');  // true
supported('-webkit-user-drag');  // true
supported('-moz-force-broken-image-icon');  // false
supported('-ms-block-progression');  // false
supported('abcd');  // false
supported();  // ["align-content", "align-items", "align-self" ... ]

参考答案:

function supported(prop) {
  var result = [];
  var format = function(p) {
    // 浏览器前缀处理
    var prefix = /^([webkit|moz|ms|o]+)[A-Z]+.*/.test(p) ? '-' : '';
    return prefix + p.replace(/[A-Z]/g, '-$&').toLowerCase();
  };

  if (Object.hasOwnProperty('keys') && Object.keys(document.body.style).length) {
    result = Object.keys(document.body.style).map(format);        
  } else {
    for (var key in document.body.style) {
      result.push(format(key));
    }
  }

  // 兼容 IE8
  if (!('indexOf' in Array.prototype)) {
    result = String(result);
  }

  if (typeof prop === 'undefined') {
    return typeof result === 'string' ? result.split(',') : result;
  }

  return result.indexOf(prop) === -1 ? false : true;
}

本期优秀回答者: 无 [哭笑.jpg]

第 20 期(W3C标准-HTML):meta标签

题目:

请写出你所知道的所有 <meta> 标签,例如:

<meta charset="UTF-8">  <!-- 字符集声明 -->

参考答案:

<meta charset="UTF-8"> <!-- 字符集声明 -->

<!-- 视口类 -->
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="viewport" content="user-scalable=no">

<!-- HTTP 参数类 -->
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> <!-- 浏览器渲染版本 -->
<meta http-equiv="cache-control" content="no-cache"> <!-- 缓存控制 -->
<meta http-equiv="expires" content="Sunday 26 October 2016 01:00 GMT"> <!-- 网页过期时间 -->
<meta http-equiv="refresh" content="5;url=http://xx.xx"> <!-- 网页重定向 -->
<meta http-equiv="cleartype" content="on"> <!-- 开启 cleartype,限IE -->
<meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests"> <!-- XSS终结者 -->

<!-- 禁止自动转码、翻译 -->
<meta http-equiv="Cache-Control" content="no-transform"> <!-- 进制转码 -->
<meta http-equiv="Cache-Control" content="no-siteapp"> <!-- 进制转码 -->
<meta name="google" value="notranslate"> <!-- 限chrome -->

<!-- SEO 类 -->
<meta name="keywords" content="xxx,xxx,xx">
<meta name="description" content="xxxxxxxx">

<!-- 其他 -->
<meta name="renderer" content="webkit"> <!-- 默认浏览器渲染内核,限360浏览器 -->
<meta name="format-detection" content="telephone=no,email=no,adress=no"> <!-- 禁止电话、邮箱、地址文本自动解析 -->
<meta name="apple-mobile-web-app-capable" content="yes"> <!-- 是否启用 WebApp 全屏模式 -->
<meta name="apple-mobile-web-app-status-bar-style" content="black"> <!-- 上面一条设置启用时生效 -->

拓展阅读

第 31 期(ECMAScript-作用域 闭包):模拟ES6 Generator

题目:

请模拟实现 ES6 中的 Generator 函数

function generator(array) {
  // 你的代码
}

测试数据:

const arr = [
  {
    name: '张三',
    age: 18
  }, {
    name: '李四',
    age: 22
  }, {
    name: '王五',
    age: 30
  }
];

const it = generator(arr);

console.log(it.next());  // {value: {age: 18, name: "张三"}, done: false}
console.log(it.next());  // {value: {age: 22, name: "李四"}, done: false}
console.log(it.next());  // {value: {age: 30, name: "王五"}, done: false}
console.log(it.next());  // {value: undefined, done: true}

参考答案:

function generator(array) {
  let nextIndex = 0;

  return {
    next: function() {
      return nextIndex < array.length ?
      {value: array[nextIndex++], done: false} :
      {value: undefined, done: true};
    }
  }
}

第 45 期(W3C标准-JavaScript-DOM):获取节点所有属性

题目:

请编写函数 getAttributes,接收一个 DOM 节点作为参数,输出该节点的所有属性。

测试用例:

<a class="btn btn-link" id="demo" href="page.html" title="页面" role="link">链接</a>
var demo = document.getElementById('demo');

getAttributes(demo);
/**
 * 返回数据:
    {
      class: "btn btn-link",
      id: "demo",
      href: "page.html",
      title: "页面",
      role: "link"
    }
  */

function getAttributes(el) {
  // 你的代码
}

参考答案:

function getAttributes(el) {
  var result = {};

  [].slice.call(el.attributes).forEach(function(attr) {
    result[attr.name] = attr.value;
  });

  return result;
}

第 6 期(2019-05-13):获取过去n天的日期

来源:原创题
难度:★★

封装一个函数,接收一个整数参数 n ,返回当天前 n 天的日期(不含当天)

/**
 * @param {number} n - 天数
 * @return {array} 日期数组,格式:[yyyy-MM-dd, yyyy-MM-dd]
 */
function getPastDays(n) {
  // 你的代码
}

测试用例:

getPastDays(7);  // 获取前 7 天的日期(今天是:2019年5月13日)

// 运行返回数据:
["2019-05-06", "2019-05-07", "2019-05-08", "2019-05-09", "2019-05-10", "2019-05-11", "2019-05-12"]

参考答案:

function getPastDays(n) {
  // 非整数或负数,返回空数组
  if (!Number.isInteger(n) || n < 0) {
    return [];
  }

  const oneDay = 24 * 3600 * 1e3;  // 将1天时间换算成UTC毫秒数
  const preZero = num => num < 10 ? `0${num}` : num;  // 1位数前置补零

  return (
    [...Array(n).keys()]
      .map(days => new Date(Date.now() - oneDay * (days + 1)))
      .map(day => `${day.getFullYear()}-${preZero(day.getMonth() + 1)}-${preZero(day.getDate())}`)
      .reverse()  // 反转数组,按从远到近的日期顺序
  );
}

本期优秀回答者: @liwenkang @Wxh16144

第 38 期(W3C 标准-JavaScript-事件):事件的绑定与移除

题目:

JavaScript 中为 DOM 元素绑定事件可使用 addEventListener 来实现,但与之对应的事件移除方法 removeEventListener 却没有那么好用,例如它无法移除绑定的匿名方法。
请结合下面的代码,实现按钮点击一次后,移除自身绑定的匿名方法的功能。

var btn = document.createElement('button');
btn.innerText = '按钮';
btn.addEventListener('click', function() {
  btn.innerText = '我被点击了-' + (+new Date());
});
document.body.appendChild(btn);

参考答案:

window.HTMLElement && !function() {
  HTMLElement.prototype.addListener = function(type, fn, capture) {
    var el = this;
    fn = typeof fn === 'function' ? fn : function(){};

    var bind = function() {
      el.addEventListener(type, fn, capture);
      return {
        removeListener: function() {
          el.removeEventListener(type, fn);
        }
      }
    };

    return bind();
  }
}();

var btn = document.createElement('button');
btn.innerText = '按钮';
var evt = btn.addListener('click', function() {
  btn.innerText = '我被点击了-' + (+new Date());
  evt.removeListener();
});
document.body.appendChild(btn);

第 5 期(2019-05-12):数组最大数最小数

来源:经典算法题
难度:★★

求一个给定数组中的最大数、最小数

/**
 * @param {array} arr - 给定的数组,数组每项为整数
 * @return {array} 返回最大数最小数组成的数组,格式:[max, min]
 */
function findMaxMin(arr) {
  // 你的代码
}

参考答案: 请参阅 @liwenkang 清脆的回答。

另外,如果需要兼容 ES5,可以写成 Math.max.apply(0, arr) Math.min.apply(0, arr)


本期优秀回答者: @liwenkang

第 26 期(ECMAScript-原型链 继承):实现 Array reduce

题目:

请编写一个方法 reduceArr,实现与 ES5 规范中数组的 reduce 方法同样的功能

相关: 第 22 期(ECMAScript-原型链 继承):实现 Array map

测试用例:

var data = [1, 2, 3, 4];

var result1 = data.reduceArr(function(total, cur, idx, arr) {
  return total + cur;
});

var result2 = data.reduceArr(function(total, cur, idx, arr) {
  return total + cur;
}, 100);

console.log(result1);  // 10
console.log(result2);  // 110

参考答案:

Array.prototype.reduceArr = function(fn, initialVal) {
  var arr = this;
  var result = arr[0];
  var startIdx = 1;
  
  if (typeof initialVal !== 'undefined') {
    result = initialVal;
    startIdx = 0;
  }

  for (var i = startIdx; i < arr.length; i++) {
    result = fn(result, arr[i], i, arr);
  }

  return result;
};

第 25 期(算法-递归):汉诺塔(河内塔)

题目:

汉诺塔是一个益智游戏,塔的设备包括三根柱子和一套直径不一的空心圆盘。开始时源柱子上的所有圆盘都按照较小的圆盘放在较大的圆盘之上的顺序堆叠。目标是通过每次移动一个圆盘到另一根柱子上,最终将一堆圆盘移动到目标柱子上,过程中不可将大的圆盘放置在较小的圆盘之上。

image

请使用 js 编写汉诺塔算法。(在浏览器控制台输出解法)

/**
 * @param {number} n - 圆盘数量
 * @param {string} A - 源柱子名称
 * @param {string} B - 辅助柱子名称
 * @param {string} C - 目标柱子名称
 */
function hanoi(n, A, B, C) {
  // 你的代码
}

测试用例:

hanoi(3, 'A', 'B', 'C');

// 控制台输出:
/*
  Move disc 1 from A to C
  Move disc 2 from A to B
  Move disc 1 from C to B
  Move disc 3 from A to C
  Move disc 1 from B to A
  Move disc 2 from B to C
  Move disc 1 from A to C
*/

参考答案:

function hanoi(n, A, B, C) {
  if (n > 0) {
    hanoi(n - 1, A, C, B);
    console.log(`Move disc ${n} from ${A} to ${C}`);
    hanoi(n - 1, B, A, C);
  }
}

第 39 期(W3C 标准-CSS-响应式布局):基于Grid的响应式布局

题目:

请结合下述代码,实现如下图所示的响应式布局效果:

16b725f8a0b394a8

要求:

  • 每个盒子宽度自适应,最小宽度为 100px,高度为 50px,盒子间距 5px;
  • 盒子呈横向排列,父容器有更多的可用空间时,每列平均分配宽度,父容器宽度不足时盒子自动换行;
  • 请使用纯 CSS 实现。
.container {
  
}

.container > div {
  text-align: center;
  font-size: 32px;
  line-height: 50px;
  color: #fff;
}

.container > div:nth-child(1) {background: #ADF2B7;}
.container > div:nth-child(2) {background: #FEE87A;}
.container > div:nth-child(3) {background: #5DFDFB;}
.container > div:nth-child(4) {background: #E5B5FC;}
.container > div:nth-child(5) {background: #8DFCCA;}
.container > div:nth-child(6) {background: #FE985F;}

参考答案:

.container {
  display: grid;
  grid-gap: 5px;
  grid-template-columns: repeat(auto-fit, minmax(100px, 1fr));
  grid-template-rows: repeat(2, 50px);
}

.container > div {
  text-align: center;
  font-size: 32px;
  line-height: 50px;
  color: #fff;
}

.container > div:nth-child(1) {background: #ADF2B7;}
.container > div:nth-child(2) {background: #FEE87A;}
.container > div:nth-child(3) {background: #5DFDFB;}
.container > div:nth-child(4) {background: #E5B5FC;}
.container > div:nth-child(5) {background: #8DFCCA;}
.container > div:nth-child(6) {background: #FE985F;}

第 29 期(算法-数学):抽奖概率算法

题目:

以下面的数据为参考,编写一个抽奖算法,其中 chance 字段为当前奖品的获奖概率(0.01-1)

const awards = [
  {name: '智能平衡车', chance: 0.12},
  {name: '华为 P30 Pro手机', chance: 0.06},
  {name: '蓝牙手环', chance: 0.3},
  {name: '100元购物卡', chance: 0.5},
  {name: 'Mac Book Pro', chance: 0.02}
];

参考答案:

初步思路:将所有奖品的概率转换为百分数(即 chance * 100),然后按照各自的占比生成一个100长度的数组:

  • 1-12 项是智能平衡车区间
  • 13-18 项是华为 P30 Pro手机区间
  • 19-48 项是蓝牙手环区间
  • 49-98 项是100元购物卡区间
  • 99-100 项是Mac Book Pro区间

然后从1-100生成一个随机数,看落在哪个区间即可确定抽奖结果。

进阶:上面的思路空间复杂度较高,通过观察可以发现,生成的5个概率区间有5个临界参考点,即 12, 18, 48, 98, 100,换句话说,我们只需将获取的随机数按这些参考点依次进行比较,找到第一个比随机数大的参考点即可确定结果,而无需划分100长度的数组。

> 在线演示 <

let arr = awards.map(it => ({ name: it.name, chance: it.chance * 100}))
  .map((it, idx, array) => {
    if (idx > 0) {
      it.chance = it.chance + array[idx - 1].chance;  // 累加上一个临界参考点
    }
    return it;
  });

// 生成 1-99 随机数
let rdmNum = Math.floor(Math.random() * 99) + 1;

for (let award of arr) {
  if (award.chance > rdmNum) {
    console.log(`你抽中了 ${award.name}`);
    break;
  }
}  

参考资料:Alias Method离散分布随机取样

第 43 期(W3C标准-HTML):快捷键

题目:

请根据提供的 html 代码实现下述效果:

  • 点击按钮或按快捷键 Alt + H,控制台输出对应信息;
  • 点击或按快捷键 Alt + Y 选中“同意”单选框;
  • 点击或按快捷键 Alt + N 选中“不同意”单选框。
<button onclick="console.log('这是帮助信息')">帮助信息</button>
<label>
  <input type="radio" name="choice"> 同意
</label>
<label>
  <input type="radio" name="choice"> 不同意
</label>

参考答案:

<button accesskey="h" onclick="console.log('这是帮助信息')">帮助信息</button>
<label accesskey="y">
  <input type="radio" name="choice"> 同意
</label>
<label accesskey="n">
  <input type="radio" name="choice"> 不同意
</label>

Element accesskey

第 13 期(2019-05-20):无返回值的语句

        基础
        


        1 请写出四种无返回值的四种语句
        2 判断在浏览器控制台执行以下代码的结果,同时写出原因
        eval('1+2;var x=5;;;;;;function fn(){};');
        eval('1+2;var x=5;;;;;;function fn(){};void 0');

第 42 期(算法-搜索):获取多层嵌套对象的目标属性值

题目:

已知后端某接口可能返回的数据结构如下:

// 正常情况:
{
  "status": 200,
  "msg": "ok",
  "response": {
    "data": {
      "total": 2,
      "pageSize": 10,
      "lists": [
        { "id": 1, "name": "hello" },
        { "id": 2, "name": "world" }
      ]
    },
    "keyword": "hello world"
  }
}

// 请求异常:
{
  "status": 400,
  "msg": "bad request",
  "response": null
}

// 空数据:
{
  "status": 200,
  "msg": "ok",
  "response": {
    "data": {
      "total": 0,
      "pageSize": 10,
      "lists": null
    },
    "keyword": "hack"
  }
}

前端需要获取返回数据中的 response.data.lists 来渲染业务页面(伪代码如下),请编写一个通用函数来改善逐级判断属性值的问题。

axios.get('/list?keyword=xxx')
  .then(function(res) {
    // 为了防止报错,而不得不逐级判断属性值的有效性
    if (res.response && res.response.data && res.response.data.lists) {
      render(res.response.data.lists);
    }
  });
/**
 * @param {object | array} data - 源数据
 * @param {string} fieldRoute - 字段名路径,如 a.b.c 
 */
function getDataBy(data, fieldRoute) {
  // 你的代码
}

测试数据:

// 正常情况:
getDataBy(res, 'response.data.lists');  // [{"id": 1, "name": "hello"}, {"id": 2, "name": "world"}]

// 请求异常:
getDataBy(res, 'response.data.lists');  // null

// 空数据:
getDataBy(res, 'response.data.lists');  // null

getDataBy(null, 'response.data.lists');  // null
getDataBy([{id: 1}, {id: 2}, {id: 3}, {id: 4}], 1);  // {id: 2}

参考答案:

function getDataBy(data, fieldRoute) {
  if (fieldRoute == undefined) {  // undefined | null
    return data
  }

  var fields = String(fieldRoute).split('.');
  
  return fields.reduce(function(obj, field) {
    if (obj) {
      return obj[field]
    } else {
      return null
    }
  }, data);
}

第 47 期(技巧):图片加载器

题目:

请编写一个名为 ImageLoader 的图片加载器,接收一个数组或字符串参数,包含图片的 URL 地址,当所有图片加载完毕时,触发 onReady 回调。

测试用例:

const imgUrls = [
  'https://cdn.pixabay.com/photo/2019/04/29/14/50/camogli-4166255__340.jpg',
  'https://cdn.pixabay.com/photo/2019/06/24/15/31/forest-4296305__340.jpg',
  'https://cdn.pixabay.com/photo/2019/06/27/03/42/beach-4301479__340.jpg',
  'https://cdn.pixabay.com/photo/2019/06/19/23/13/plum-blossoms-4285819__340.jpg',
  'https://cdn.pixabay.com/photo/2019/05/19/23/47/clouds-4215608__340.jpg',
  'https://cdn.pixabay.com/photo/2018/10/18/11/29/waterfowl-3756126__340.jpg'
];
const loader = new ImageLoader(imgUrls);
loader.onReady = () => {
  console.log('图片全部加载完毕');
}

参考答案:

class ImageLoader {
  constructor(urls) {
    this.cache = {};

    if (Array.isArray(urls)) {
      urls.forEach(url => this.load(url));
    } else {
      this.load(urls);
    }
  }

  load(url) {
    if (this.cache[url]) {
      return this.cache[url];
    }

    let img = new Image();

    img.addEventListener('load', _ => {
      this.cache[url] = img;

      if (this.isReady()) {
        this.onReady();
      }
    });

    this.cache[url] = false;
    img.src = url;
  }

  isReady() {
    for (let k in this.cache) {
      if (!this.cache[k]) {
        return false;
      }
    }

    return true;
  }

  onReady(fn) {
    typeof fn === 'function' && fn();
  }
}

1-16期总结以及后期的改版方向【手动加精】

晚练课已经开了 16 期了,并没有达到预期效果,虽然其中有一些客观因素,但更多的是我在主观方面没有做好前期的规划。

从之前 16 期整体来看,这种东一榔头西一棒槌的做题练习模式知识点太过零散,如果只是做题,还不如直接去 LeetCode,另外 GitHub 上也有不少通过 issue 练题的同质化 repo,与之相比,晚练课目前的开展模式没有多少优势可言。如果要继续开展下去就必须另寻思路,找到差异化细分的切入点,这个切入点,以我个人之见,应该是 “刻意练习”

那么问题来了,为什么要去刻意练习?因为随着前端技术的日新月异,前端工程师所需要学的知识体量越来越大了,为“提高”学习效率,我们往往追求快餐式、碎片化的学习方式,这种浅层的学习方式,不足以让知识系统地转化为技能,所以当工作中遇到实际问题,我们经常介于似懂非懂之间,需要翻查各种资料才能解决。要改善这种“一学就会,一写就跪”的情况,光靠学是不够的,还应当进行有针对性的刻意练习,锻炼出“代码肌肉”(有个叫一万小时理论的怎么说得来着?)。

刻意练习些什么呢?应该是专业前端工程师所必备的技能点。我最近收集(骗取)了许多培训班的资料,看了他们的学习线路图和知识体系,很受启发,我觉得可以参照这些知识体系,组织系统化的刻意练习,我已经在做这方面的准备了,请大家拭目以待。

最后欢迎大家积极参与,不断驱动自己去提升,让自己的能力变得更强,早日成为前端专家。

第16期(2019-5-23):浅克隆

        基础篇
        难度 
        
        //浅拷贝
        请写出下列代码的输出结果,为什么?

        //1.
        var a = 2 ;
        var a_copy = a ;
        a_copy  = 3;
        console.log(a);//?

        //2.数组1
        var arr = [1,2,3,4];
        var arr_copy = arr ;
        arr_copy.push(5);
        console.log(arr);//?
        //3.数组2
        var arr = [1,2,3,4];
        var arr_copy = arr ;
        arr_copy = [1,2,3,4,5];
        console.log(arr);//?
        console.log(arr_copy);//?

        //4.对象1
        var obj = {
            name:'sunshine',
            age:18
        };
        var obj_copy = obj ;
        obj_copy.name = '过客';
        console.log(obj.name);//?

        //5.对象2
        var obj = {
            name:'sunshine',
            age:18
        };
        var obj_copy = obj ;
        obj_copy = {
            name:'过客',
            age:18
        };
        console.log(obj.name);//?
        console.log(obj_copy.name);//?

第 48 期(数据结构-数组):获取字母表

题目:

编写一个名为 getAlphabet 的函数,返回一个由 a 到 z 26个字母组成的数组。


参考答案:

思路:利用 ASCⅡ 表中字母编码是连续的这个特点,获得字母 a 的编码作为起始位置,然后累加编号,从而得到字母表。

// 方法1
function getAlphabet() {
  return [...Array(26).keys()].map((_, idx) => String.fromCharCode(97 + idx));
}

// 方法2
function getAlphabet() {
  return new Array(26).fill().map((_, idx) => String.fromCharCode(97 + idx));
}

// 方法3
function getAlphabet() {
  return Array.from({length: 26)).map((_, idx) => String.fromCharCode(97 + idx));
}

// 方法4
function getAlphabet() {
  var len = 26;
  var result = [];

  while(len) {
    result.push(String.fromCharCode(97 + (26 - len)));
    len--;
  }

  return result;
}

第 0 期(2019-05-07):答题规范

  鄙人昨日夜观天象,但见紫气东凝、七斗璨谧,遂遍查玄学典籍,方知此象为明日大吉之兆!故择明日(5月8号)为本课开启吉日,望诸位赏光莅临!:tada: :tada: :tada:


  • 练习题发布规范(for 考官)

    • 标题

      • 格式:第 [n] 期([日期]):[标题名称]
      • 示例:第 1 期(2019-05-08):数组的九种写法
    • 内容

      • 格式:

        来源:[ 原创题 | 经典算法题 | 大厂面试题 | 其他 …… ]
        难度:[ 入门 | 简单 | 中等 | 困难 | 噩梦 ]
        
        /* 题目内容巴拉巴拉…… 要求语言简洁明了,将题意阐述清楚,避免歧义 */
        
      • 示例:

        来源:原创题

        难度:★★★★

        javascript 的数组有九种写法,请依次写出来。

  • 关于练习题难度等级

  1. 入门(★):基础型的入门题目,答题者了解相关基础知识即可作答;

    示例:javascript 中的基本类型有哪些?

  2. 简单(★★):将基础知识实际运用的题目,答题者需要对相关基础知识有一定的理解和认识;

    示例:将一个对象数组按给定的字段名进行排序

  3. 中等(★★★):将基础知识和相关技巧灵活应用的题目,答题者需要扎实的基础功底;

    示例:用 ES5 实现 Promise

  4. 困难(★★★★):考察底层原理、逻辑思维类的高阶题目,答题者需要清晰的逻辑思维能力和一定的技术知识深度;

    示例:不使用递归,中序遍历一个二叉树

  5. 噩梦(★★★★★):请自重

    示例:面试官:请你清唱一首《忐忑》

  • 答题规范(for 试炼者)

    • 良好的代码规范和代码风格;
    • 包含必要的代码注释,让别人理解你的意图;
    • 必要时提供在线演示 demo,推荐使用 CodePen,可以绑定 GitHub 账号登录。
  • 代码内容规范(for All)

    • 使用 markdown 中的代码块语法来插入代码(GitHub 会自动解析并高亮代码);

      ```js
      // 这里是 javascript 代码内容
      ```
      
      ```html
      // 这里是 HTML 代码内容
      ```
      
      ```css
      // 这里是 CSS 代码内容
      ```
      
    • 注意代码块的缩进距离,起始位置从左边缘开始。

  • 其他

    • 如果觉得当期的练习题不错,就给考官一个赞吧,点赞数是衡量金牌考官的量化指标之一;

    • 如果别人的回答很棒,让你学到了新东西,别吝啬,给TA个赞吧!

      13


~~ 期待大家的参与 ~~

第 19 期(W3C标准-HTML):换行

题目:

在网页中,连续英文单词文本默认是不换行的,所以当容器宽度不够显示时,文本内容会溢出。我们通常的做法是使用 word-break:break-allword-wrap:break-word,但这种强制换行的方式具有不可控性,很容易破坏单词的可读性。请尝试解决这个问题。

测试内容如下:

<p>
  https://juejin.im/search?query=requestAnimationFrame
</p>

要求:容器宽度足够时,整体一行显示;容器宽度不足时,文本内容自动换行,文本中的单词不会被截行。


参考答案:

https://<wbr>juejin.im<wbr>/search?<wbr>query=<wbr>requestAnimationFrame

<wbr> 是一个神奇的标签,可以实现精确换行:当容器宽度不够时,在 <wbr> 这里换行;宽度足够,还是一行显示,非常智能。

参考资料

第 46 期(W3C标准-CSS-动画):按钮loading动画效果

题目:

请使用纯 CSS 实现 .btn 按钮的 loading 动画效果,效果如下图:

GIF

相关的 CSS 和 HTML 已写好:

.btn {
  display: inline-block;
  padding: .5em 1.2em;
  font-size: 14px;
  color: #fff;
  background: #369;
  border: 0;
  border-radius: 5px;
}
/* 请补充 loading 动画的 CSS 实现 */
<button class="btn">确定</button>
<button class="btn loading">确定</button>

参考答案:

.btn.loading {position: relative;}
.btn.loading:first-line {color: transparent;}
.btn.loading::before {
  content: "";
  position: absolute;
  top: 0; right: 0; bottom: 0; left: 0;
  width: 4px;
  height: 4px;
  margin: auto;
  animation: spinZoom 1s steps(8) infinite;
  border-radius: 100%;
  box-shadow: 0 -10px 0 1px currentColor,
    10px 0 currentColor,
    0 10px currentColor,
    -10px 0 currentColor,
    -7px -7px 0 .5px currentColor,
    7px -7px 0 1.5px currentColor,
    7px 7px currentColor,
    -7px 7px currentColor;
}

@keyframes spinZoom {
  0% {
    transform: scale(.75) rotate(0);
  }
  100% {
    transform: scale(.75) rotate(360deg);
  }
}

第 37 期(W3C 标准-ECMAScript-原型链 继承):原型链的尽头

题目:

以下代码运行后输出什么?为什么?

console.log(Object.getPrototypeOf(Object.prototype));

参考答案:

null

JavaScript 规定,所有对象都有自己的原型对象(prototype)。一方面,任何一个对象,都可以充当其他对象的原型;另一方面,由于原型对象也是对象,所以它也有自己的原型。因此,就会形成一个“原型链”(prototype chain):对象到原型,再到原型的原型……
如果一层层地上溯,所有对象的原型最终都可以上溯到 Object.prototype,即 Object 构造函数的 prototype 属性。也就是说,所有对象都继承了Object.prototype 的属性。这就是所有对象都有 valueOf 和 toString 方法的原因,因为这是从Object.prototype 继承的。

那么,Object.prototype 对象有没有它的原型呢?有,Object.prototype 的原型是 null。null 没有任何属性和方法,也没有自己的原型。因此,原型链的尽头就是 null。

第 15 期(2019-05-22):数组去重

类型:高频面试题
难度:★★

请编写一个数组去重函数(用 ES5、ES6 各写一个)

function removeRepeat(arr) {
  // 你的代码
}

参考答案:

// 对象属性法
// 注意:[1, '1'] 形式的数组会产生误差,因为 hash[1] === hash['1']
function removeRepeat(arr) {
  var result = [],
      hash = {};

  for (var i = 0, elem; i < arr.length; i++) {
      elem = arr[i];

      if (!hash[elem]) {
          result.push(elem);
          hash[elem] = true;
      }
  }

  return result;
}

// 指针查询法
function removeRepeat(arr) {
  var result = [];

  arr.map(function(item, idx, array) {
    if (array.indexOf(item) === idx) {
      result.push(item);
    }
  });

  return result;
}

// 数组反查法
function removeRepeat(arr) {
  var result = [];

  for (var i = 0; i < arr.length; i++) {
    if (!~result.indexOf(arr[i])) {
      result.push(arr[i]);
    }
  }

  return result;
}

// 过滤法
function removeRepeat(arr) {
  return arr.filter(function(item, idx, array) {
    return array.indexOf(item) === idx;
  });
}

// ES6 Set 去重法
function removeRepeat(arr) {
  return [...new Set(arr)];
}

// 执行效率排行(从高到低):
// 对象属性法 > ES6 Set 去重法 > 数组反查法 > 过滤法 > 指针查询法

本期优秀回答者: @AMY-Y

第 21 期(JSON):JSON.stringify

题目:

已知如下数据:

let country = {
  name: 'China',
  language: 'Chinese',
  population: {
    value: 14,
    unit: '亿'
  }
};

请使用 JSON.stringify 将其转化为以下格式的字符串:

--"name": "China",
--"language": "Chinese",
--"population": "14 亿"

参考答案:

JSON.stringify(country, (k, v) => {
  if (k === 'population') {
    return `${v.value} ${v.unit}`;
  }

  return v;
}, '--').replace(/\{|\}/g, '');

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.