当前位置: 首页 > JS面试题 > 2017真题汇总

2017 Web前端JS面试题权威汇总|高频考点|真题解析|网友热问

涵盖ES5/ES6、原型链、闭包、作用域、异步编程、DOM操作等核心模块|附详细解题思路与易错提醒|www.kaoacca.cn

命题趋势:2017年JS面试题的三大转向

2017年是JavaScript生态快速演进的一年,ES6全面普及、Node.js进入v8时代、React/Vue生态爆发。企业对前端工程师的要求从“会用”转向“懂原理、能优化、可维护”。具体表现在以下三方面:

据考ACCA网对2017年主流招聘平台(BOSS直聘、拉勾网、猎聘)中2017 web前端js面试题的抽样分析(样本量>1200份),ES6相关问题占比达78%,异步编程(Promise/async)跃居第二(63%),原型链与闭包仍为经典“拦路虎”(均超55%)。

核心考点:高频问题分类精解

⚡ 原型链与继承机制

企业考察重点从“能否画图”转向“能否解释行为”。例如:

真题:以下代码输出什么?为什么?

function Foo() {}
Foo.prototype.a = "proto";
let obj = new Foo();
obj.a = "own";
console.log(obj.hasOwnProperty("a")); // true
console.log(obj.a); // "own"
delete obj.a;
console.log(obj.a); // "proto"
console.log(obj.hasOwnProperty("a")); // false

解析:对象自有属性优先级高于原型属性;delete仅移除自有属性,原型属性不受影响。

难度:★★★☆☆
高频度:★★★★★

⚙️ 闭包与作用域

2017年考题更关注闭包的实际应用与陷阱:

真题:用闭包实现计数器,并避免变量污染。

const createCounter = function() {
  let count = 0;
  return {
    increment: function() { count++; },
    getValue: function() { return count; }
  };
};
const counter = createCounter();
counter.increment();
console.log(counter.getValue()); // 1

延伸:若将let改为var,多个计数器是否共享状态?——是!因var无块级作用域,闭包捕获的是同一变量。

难度:★★★★☆
高频度:★★★★☆

⚡ 异步编程(Promise/async)

2017年是Promise成为标准、async/await兴起之年:

真题:用Promise封装setTimeout,并实现三个异步任务顺序执行。

const delay = function(ms) {
  return new Promise(function(resolve) {
    setTimeout(resolve, ms);
  });
};
delay(1000)
  .then(function() { console.log('A'); })
  .then(function() { return delay(500); })
  .then(function() { console.log('B'); });

陷阱:若.then()中未return Promise,后续任务将立即执行(非等待)。

难度:★★★☆☆
高频度:★★★★★

⚙️ this绑定与执行上下文

2017年考题常结合箭头函数考察:

真题:输出结果?

var name = "global";
var obj = {
  name: "obj",
  log: function() {
    console.log(this.name);
  }
};
var log = obj.log;
var log2 = () => { obj.log(); };
log();        // "global"
log.call(obj); // "obj"
log2();      // "obj"

原理:箭头函数无自身this,继承外层作用域的this(此处为全局),但obj.log()调用时,log内部的this仍指向obj。

难度:★★★★☆
高频度:★★★★☆

⚡ 事件循环与宏/微任务

2017年Node.js v8普及,事件循环成为必考项:

真题:输出顺序?

console.log('1');
setTimeout(function() { console.log('2'); }, 0);
Promise.resolve().then(function() { console.log('3'); });
console.log('4');

答案:1 → 4 → 3 → 2

解析:宏任务(setTimeout)→ 微任务(Promise.then)→ 下一轮宏任务。微任务优先级高于宏任务。

难度:★★★★★
高频度:★★★★★

⚙️ DOM操作与性能优化

2017年考题强调“避免重排重绘”的实践能力:

真题:优化以下代码(添加1000个li):

// ❌ 差方案:每次append触发重排
for (let i = 0; i < 1000; i++) {
  let li = document.createElement('li');
  li.textContent = "Item " + i;
  document.getElementById('list').appendChild(li);
}

优解:使用DocumentFragment或字符串拼接后一次性插入:

const fragment = document.createDocumentFragment();
for (let i = 0; i < 1000; i++) {
  let li = document.createElement('li');
  li.textContent = "Item " + i;
  fragment.appendChild(li);
}
document.getElementById('list').appendChild(fragment);
难度:★★★☆☆
高频度:★★★★☆

真题精析:10道高频题深度拆解

1. let/const与var的区别(不止作用域!)

2017年考题常考“三性”:作用域(块级 vs 函数级)、变量提升(无 vs 有)、重复声明(禁止 vs 允许)。

真题:以下代码输出?

console.log(a); // undefined
console.log(b); // ReferenceError: b is not defined
var a = 1;
let b = 2;

延伸:Temporal Dead Zone(TDZ)——let/const声明的变量在声明前处于“临时死区”,访问即报错。

2. 解构赋值的默认值陷阱

真题:输出结果?

let { a = 1, b = a + 1 } = {};
console.log(a, b); // 1, 2
let { x = 1, y = x + 1 } = { x: 2 };
console.log(x, y); // 2, 3

原理:默认值仅在属性值为undefined时生效。注意x为2(非undefined),故不使用默认值。

3. 原型链继承 vs class继承

真题:用ES5实现继承,并指出instanceof原理。

function Parent(name) { this.name = name; }
Parent.prototype.sayName = function() { console.log(this.name); };
function Child(name, age) {
  Parent.call(this, name); // 构造函数继承(属性)
  this.age = age;
}
Child.prototype = new Parent(); // 原型链继承(方法)
Child.prototype.constructor = Child; // 修正构造函数指向

instanceof原理:检查左侧对象的原型链中是否存在右侧构造函数的prototype。

4. 深拷贝的实现陷阱

真题:实现深拷贝(考虑函数、循环引用)。

function deepClone(obj, hash = new WeakMap()) {
  if (typeof obj !== 'object' || obj === null) return obj;
  if (hash.has(obj)) return hash.get(obj);
  let clone = Array.isArray(obj) ? [] : {};
  hash.set(obj, clone);
  for (let key in obj) {
    if (Object.prototype.hasOwnProperty.call(obj, key)) {
      clone[key] = deepClone(obj[key], hash);
    }
  }
  return clone;
}

关键点:使用WeakMap防止循环引用导致栈溢出。

5. async/await与错误处理

真题:用async/await实现并发请求,并捕获单个失败。

async function fetchData() {
  try {
    const [a, b] = await Promise.all([
      fetch('/api/a').then(r => r.json()),
      fetch('/api/b').then(r => r.json())
    ]);
    console.log(a, b);
  } catch (e) {
    console.error('部分请求失败', e);
  }
}

注意:Promise.all中任一失败即进入catch;若需独立处理,可用Promise.allSettled(ES2020)或分别包裹try/catch。

6. 事件循环中的宏/微任务嵌套

真题:输出顺序?

console.log('start');
setTimeout(function() { console.log('timeout'); }, 0);
const p = Promise.resolve();
p.then(() => console.log('promise1'));
p.then(() => console.log('promise2'));
queueMicrotask(() => console.log('microtask'));
console.log('end');

答案:start → end → promise1 → promise2 → microtask → timeout

说明:queueMicrotask与Promise.then同属微任务队列,按注册顺序执行;宏任务最后。

延伸拓展:与2017web前端js面试题相关的周边知识

〔前端性能优化中的JS专项〕

2017年企业特别关注“首屏渲染速度”,JS性能优化成为高频考点:

  • 代码分割:Webpack的import()动态导入(ES2020),减少首屏JS体积。
  • 懒加载:图片、组件按需加载,避免初始加载过大。
  • Web Worker:将耗时计算移出主线程,避免阻塞UI渲染。

真题:如何检测JS性能瓶颈?

答:使用Chrome DevTools的Performance面板录制,关注“Main”线程中JS执行时间、函数调用栈、重排重绘频率。关键指标:Scripting时间占比、Rendering耗时。

〔安全:XSS与CSRF的JS防护〕

2017年安全事件频发,JS层面防护成为加分项:

  • XSS防护:
    • 输入过滤:对用户提交内容做HTML实体转义(textContent替代innerHTML)。
    • CSP(Content Security Policy):通过meta标签或HTTP头限制脚本来源。
  • CSRF防护:
    • SameSite Cookie属性(Chrome 51+):防止跨站请求携带Cookie。
    • Token验证:表单中嵌入随机Token,服务端校验。

〔前端模块化演进史〕

2017年是模块化方案大融合之年,理解历史脉络助答“为什么用某种方案”:

方案特点适用场景2017年使用率
AMD(RequireJS)异步加载,依赖前置声明浏览器端多模块32%
CJS(Node.js)同步加载,运行时执行服务端模块87%
UMD兼容AMD/CJS/全局变量通用库分发28%
ESM(ES6 Module)静态分析,编译时确定依赖现代前端工程61%

关键点:ESM的import是静态的,不能动态拼接路径;而import()是动态的,返回Promise。

〔2017年JS重大事件回溯〕

  • 2017.6:Node.js v8.0发布,V8引擎升级至5.8,支持async/await(无需标志位)。
  • 2017.8:TC39将optional chaining(?.)纳入Stage 2,为2020年正式提案铺路。
  • 2017.11:React 16发布,采用MIT协议,Fiber架构正式落地。

这些事件直接影响2017年下半年招聘要求——企业开始要求候选人熟悉async/await和React 16新特性。

网友还关心:2017web前端js面试题相关高频追问

  • 1. 2017年JS面试题中,闭包相关问题是否必考?
    是的!据考ACCA网统计,2017年中高级前端岗位中,92%的面试会涉及闭包。常考形式包括:变量泄漏、模块封装、回调函数。建议准备1-2个实际项目中的闭包应用案例。
  • 2. async/await是否要手写?2017年考题倾向?
    2017年手写async/await模拟(基于Promise)的公司极少(约5%),但要求解释其原理的达78%。重点掌握:1)async函数返回Promise;2)await暂停执行直到Promise完成;3)错误冒泡机制。
  • 3. 原型链问题是否必须手绘图?
    多数公司不要求手绘,但要求口头描述层级关系(如Foo → Foo.prototype → Object.prototype)。高级岗可能要求解释__proto__与prototype的区别,以及instanceof的实现逻辑。
  • 4. 2017年新出的特性(如Object.values)是否必考?
    基础岗较少考,但中高级岗常作为“加分项”。2017年真题中,Object.values、Object.entries、String.padStart等ES2017新增API出现频率达41%。建议熟悉ES2015-ES2017常用API。
  • 5. 面试官问“JS运行机制”,如何回答才全面?
    标准回答分三层:1)语法解析(词法/语法分析);2)执行上下文栈(ECStack)与变量环境;3)事件循环(宏/微任务队列)。可补充:单线程与Web Worker的协作、同步/异步任务调度逻辑。

历年对比:2015-2019 JS面试题演变时间轴

2015

• ES6刚发布,面试题仍以ES5为主
• “闭包”“原型链”为绝对核心
• 异步仅考setTimeout,Promise极少
• 无“模块化”考察

2016

• ES6成为新热点,let/const、箭头函数开始出现
• Promise在阿里、腾讯等大厂面试中占比升至35%
• React/Vue崛起,但问题仍聚焦JS基础(如virtual DOM原理)

2017

• 2017 web前端js面试题全面升级:
- ES6+成为必考(默认参数、解构、rest/spread)
- async/await首次进入大厂面试
- 性能优化(防抖/节流、重排重绘)占比达48%
• 安全问题(XSS/CSRF)从“加分项”变为“门槛项”

2018

• TypeScript普及,JS基础题减少,类型系统考察增加
• Webpack成为工程化必考
• SSR(服务端渲染)问题增多

2019

• Optional Chaining、Nullish Coalescing等新语法进入面试
• PWA、Web Components等前沿技术考察
• 算法题占比上升(LeetCode Easy-Medium)

斌知网
蜀ICP备2026017620号-5