- 251. 下面代码的输出是什么?( D )
- 252. 下面代码的输出是什么?( A )
- 253. 当我们执行以下代码时会发生什么?( A )
- 254. 下面代码的输出是什么?( A )
- 255. 下面代码的输出是什么?( A )
- 256. 事件传播的三个阶段是什么?( D )
- 257. 下面代码的输出是什么?( C )
- 258. 下面代码的输出是什么?( C )
- 259. 下面代码的输出是什么?( B )
- 260. 下面代码的输出是什么?( C )
- 261. 下面代码的输出是什么?( C )
- 262. 下面代码的输出是什么?( C )
- 263. 下面代码的输出是什么?( A )
- 264. cool_secret 可以访问多长时间?( B )
- 265. 下面代码的输出是什么?( B )
- 266. 下面代码的输出是什么?( C )
- 267. 下面代码的输出是什么?( C )
- 268. 下面代码的输出是什么?( C )
- 269. 下面代码的输出是什么?( A )
- 270. 下面代码的输出是什么?( B )
- 271. 下面代码的输出是什么?( B )
- 272. 单击按钮时 event.target 是什么?( C )
- 273. 单击下面的 html 片段打印的内容是什么?( A )
- 274. 下面代码的输出是什么?( D )
- 275. 下面代码的输出是什么?( B )
- 276. 下面这些值哪些是假值?( A )
- 278. 下面代码的输出是什么?( B )
- 279. 下面代码的输出是什么?( C )
- 280. 下面代码的输出是什么?( A )
- 281. JavaScript 中的所有内容都是…( A )
- 282. 下面代码的输出是什么?
- 283. 下面代码的输出是什么?( B )
- 284. setInterval 方法的返回值什么?( A )
- 285. 下面代码的返回值是什么?( A )
- 286. document.write 和 innerHTML 有哪些区别?
- 287. 假设有两个变量 a 和 b,他们的值都是数字,如何在不借用第三个变量的情况下,将两个变量的值对调?
- 288. 前端为什么提倡模块化开发?
- 289. 请解释 JSONP 的原理,并用代码描述其过程。
- 290. 列举几种 JavaScript 中数据类型的强制转换和隐式转换。
- 291. 分析以下代码的执行结果并解释为什么。
- 292. 分析以下代码的执行结果并解释为什么。
- 293. 下面的代码打印什么内容?为什么?
- 294. 下面代码中,a 在什么情况下会执行输出语句打印 1 ?
- 295. 介绍前端模块化的发展。
- 296. 请指出 document.onload 和 document.ready 两个事件的区别
- 297. 表单元素的readonly 和 disabled 两个属性有什么区别?
- 298. 列举几种你知道的数组排序的方法。
- 299. 区分什么是“客户区坐标”、“页面坐标”、“屏幕坐标”?
- 300. 如何编写高性能的 JavaScript?
- 301. 下面的代码输出什么?
251. 下面代码的输出是什么?( D )
class Chameleon {
static colorChange(newColor) {
this.newColor = newColor;
}
constructor({ newColor = "green" } = {}) {
this.newColor = newColor;
}
}
const freddie = new Chameleon({ newColor: "purple" });
freddie.colorChange("orange");
- A: orange
- B: purple
- C: green
- D: TypeError
分析:
colorChange 方法是静态的。 静态方法仅在创建它们的构造函数中存在,并且不能传递给任何子级。 由于 freddie 是一个子级对象,函数不会传递,所以在 freddie 实例上不存在 colorChange 方法:抛出TypeError。
252. 下面代码的输出是什么?( A )
let greeting;
greetign = {}; // Typo!
console.log(greetign);
- A: {}
- B: ReferenceError: greetign is not defined
- C: undefined
分析:
控制台会输出空对象,因为我们刚刚在全局对象上创建了一个空对象!
当我们错误地将 greeting 输入为 greetign 时,JS 解释器实际上在浏览器中将其视为 window.greetign = {}。
253. 当我们执行以下代码时会发生什么?( A )
function bark() {
console.log("Woof!");
}
bark.animal = "dog";
- A 什么都不会发生
- B: SyntaxError. You cannot add properties to a function this way.
- C: undefined
D: ReferenceError
分析:
因为函数也是对象!(原始类型之外的所有东西都是对象)
函数是一种特殊类型的对象,我们可以给函数添加属性,且此属性是可调用的。
254. 下面代码的输出是什么?( A )
function Person(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
const member = new Person("Lydia", "Hallie");
Person.getFullName = () => this.firstName + this.lastName;
console.log(member.getFullName());
- A: TypeError
- B: SyntaxError
- C: Lydia Hallie
- D: undefined undefined
分析:
Person.getFullName 是将方法添加到了函数身上,因此当我们通过实例对象 member 去调用该方法时并不能找到该方法。
255. 下面代码的输出是什么?( A )
function Person(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
const lydia = new Person("Lydia", "Hallie");
const sarah = Person("Sarah", "Smith");
console.log(lydia);
console.log(sarah);
- A: Person { firstName: "Lydia", lastName: "Hallie" } 和 undefined
- B: Person { firstName: "Lydia", lastName: "Hallie" } 和 Person { firstName: "Sarah", lastName: "Smith" }
- C: Person { firstName: "Lydia", lastName: "Hallie" } 和 {}
- D: Person { firstName: "Lydia", lastName: "Hallie" } 和 ReferenceError
分析:
lydia 是调用构造函数后得到的实例对象,拥有 firstName 和 lastName 属性;
sarah 是调用普通函数后得到的返回值,而 Person 作为普通函数没有返回值;
256. 事件传播的三个阶段是什么?( D )
- A: 目标 > 捕获 > 冒泡
- B: 冒泡 > 目标 > 捕获
- C: 目标 > 冒泡 > 捕获
- D: 捕获 > 目标 > 冒泡
257. 下面代码的输出是什么?( C )
function sum(a, b) {
return a + b;
}
sum(1, "2");
- A: NaN
- B: TypeError
- C: "12"
- D: 3
分析:
任意数据类型在跟 String 做 + 运算时,都会隐式转换为 String 类型。
即 a 所对应的 Number 值 1,被隐式转换为了 String 值 "1",最终字符串拼接的到 "12"。
258. 下面代码的输出是什么?( C )
let number = 0;
console.log(number++);
console.log(++number);
console.log(number);
- A: 1 1 2
- B: 1 2 2
- C: 0 2 2
- D: 0 1 2
分析:
++ 后置时,先输出,后加 1;++ 前置时,先加 1,后输出;
第一次输出的值为 0,输出完成后 number 加 1 变为 1。
第二次输出,number 先加 1 变为 2,然后输出值 2。
第三次输出,number 值没有变化,还是 2。
259. 下面代码的输出是什么?( B )
function getPersonInfo(one, two, three) {
console.log(one);
console.log(two);
console.log(three);
}
const person = "Lydia";
const age = 21;
getPersonInfo`${person} is ${age} years old`;
- A: Lydia 21 ["", "is", "years old"]
- B: ["", "is", "years old"] Lydia 21
- C: Lydia ["", "is", "years old"] 21
分析:
如果使用标记的模板字符串,则第一个参数的值始终是字符串值的数组。 其余参数获取传递到模板字符串中的表达式的值!
260. 下面代码的输出是什么?( C )
function checkAge(data) {
if (data === { age: 18 }) {
console.log("You are an adult!");
} else if (data == { age: 18 }) {
console.log("You are still an adult.");
} else {
console.log(`Hmm.. You don't have an age I guess`);
}
}
checkAge({ age: 18 });
- A: You are an adult!
- B: You are still an adult.
- C: Hmm.. You don't have an age I guess
分析:
在比较相等性时,原始类型通过它们的值进行比较,而对象通过它们的引用进行比较。
data 和条件中的 { age: 18 } 两个不同引用的对象,因此永远都不相等。
261. 下面代码的输出是什么?( C )
function getAge(...args) {
console.log(typeof args);
}
getAge(21);
- A: "number"
- B: "array"
- C: "object"
- D: "NaN"
分析:
ES6 中的不定参数(…args)返回的是一个数组。
typeof 检查数组的类型返回的值是 object。
262. 下面代码的输出是什么?( C )
function getAge() {
"use strict";
age = 21;
console.log(age);
}
getAge();
- A: 21
- B: undefined
- C: ReferenceError
- D: TypeError
分析:
"use strict" 严格模式中,使用未声明的变量会引发报错。
263. 下面代码的输出是什么?( A )
const sum = eval("10*10+5");
- A: 105
- B: "105"
- C: TypeError
- D: "10\10+5"*
分析:
eval 方法会将字符串当作 JavaScript 代码进行解析。
264. cool_secret 可以访问多长时间?( B )
sessionStorage.setItem("cool_secret", 123);
- A:永远,数据不会丢失。
- B:用户关闭选项卡时。
- C:当用户关闭整个浏览器时,不仅是选项卡。
- D:用户关闭计算机时。
分析:
sessionStorage 是会话级别的本地存储,当窗口关闭,则会话结束,数据删除。
265. 下面代码的输出是什么?( B )
var num = 8;
var num = 10;
console.log(num);
- A: 8
- B: 10
- C: SyntaxError
- D: ReferenceError
分析:
var 声明的变量允许重复声明,但后面的值会覆盖前面的值。
266. 下面代码的输出是什么?( C )
const obj = { 1: "a", 2: "b", 3: "c" };
const set = new Set([1, 2, 3, 4, 5]);
obj.hasOwnProperty("1");
obj.hasOwnProperty(1);
set.has("1");
set.has(1);
- A: false true false true
- B: false true true true
- C: true true false true
- D: true true true true
267. 下面代码的输出是什么?( C )
const obj = { a: "one", b: "two", a: "three" };
console.log(obj);
- A: { a: "one", b: "two" }
- B: { b: "two", a: "three" }
- C: { a: "three", b: "two" }
- D: SyntaxError
分析:
如果对象有两个具有相同名称的键,则后面的将替前面的键。它仍将处于第一个位置,但具有最后指定的值。
268. 下面代码的输出是什么?( C )
for (let i = 1; i < 5; i++) {
if (i === 3) continue;
console.log(i);
}
- A: 1 2
- B: 1 2 3
- C: 1 2 4
- D: 1 3 4
分析:
当 i 的值为 3 时,进入 if 语句执行 continue,结束本次循环,立即进行下一次循环。
269. 下面代码的输出是什么?( A )
String.prototype.giveLydiaPizza = () => {
return "Just give Lydia pizza already!";
};
const name = "Lydia";
name.giveLydiaPizza();
- A: "Just give Lydia pizza already!"
- B: TypeError: not a function
- C: SyntaxError
- D: undefined
分析:
String 是一个内置的构造函数,我们可以为它添加属性。 我们给它的原型添加了一个方法。 原始类型的字符串自动转换为字符串对象,由字符串原型函数生成。 因此,所有字符串(字符串对象)都可以访问该方法!
当使用基本类型的字符串调用 giveLydiaPizza 时,实际上发生了下面的过程:
- 创建一个 String 的包装类型实例
- 在实例上调用 substring 方法
- 销毁实例
270. 下面代码的输出是什么?( B )
const a = {};
const b = { key: "b" };
const c = { key: "c" };
a[b] = 123;
a[c] = 456;
console.log(a[b]);
- A: 123
- B: 456
- C: undefined
- D: ReferenceError
分析:
当 b 和 c 作为一个对象的键时,会自动转换为字符串,而对象自动转换为字符串化时,结果都为 [Object object]。因此 a[b] 和 a[c] 其实都是同一个属性 a["Object object"]。
对象同名的属性后面的值会覆盖前面的,因此最终 a["Object object"] 的值为 456。
271. 下面代码的输出是什么?( B )
const foo = () => console.log("First");
const bar = () => setTimeout(() => console.log("Second"));
const baz = () => console.log("Third");
bar();
foo();
baz();
- A: First Second Third
- B: First Third Second
- C: Second First Third
- D: Second Third First
分析:
bar 函数中执行的是一段异步代码,按照 JavaScript 中的事件循环机制,主线程中的所有同步代码执行完成后才会执行异步代码。因此 "Second" 最后输出。
272. 单击按钮时 event.target 是什么?( C )
<div onclick="console.log('first div')">
<div onclick="console.log('second div')">
<button onclick="console.log('button')">
Click!
</button>
</div>
</div>
- A: div 外部
- B: div 内部
- C: button
- D: 所有嵌套元素的数组
分析:
event.target 指向的是事件目标,即触发事件的元素。因此点击 \ 触发事件的也就是 \。
273. 单击下面的 html 片段打印的内容是什么?( A )
<div onclick="console.log('div')">
<p onclick="console.log('p')">
Click here!
</p>
</div>
- A: p div
- B: div p
- C: p
- D: div
分析:
onclick 绑定的事件为冒泡型事件。因此当点击 p 标签时,事件会从事件目标开始依次往外触发。
274. 下面代码的输出是什么?( D )
const person = { name: "Lydia" };
function sayHi(age) {
console.log(`${this.name} is ${age}`);
}
sayHi.call(person, 21);
sayHi.bind(person, 21);
- A: undefined is 21 Lydia is 21
- B: function function
- C: Lydia is 21 Lydia is 21
- D: Lydia is 21 function
分析:
call 和 bind 都可以修改 this 的指向,但区别在于 call 方法会立即执行,而 bind 会返回一个修改后的新函数。
275. 下面代码的输出是什么?( B )
function sayHi() {
return (() => 0)();
}
typeof sayHi();
- A: "object"
- B: "number"
- C: "function"
- D: "undefined"
分析:
return 后是一个 IIFE,其返回值是 0,因此 sayHi 函数中返回的是一个 0。typeof 检测 sayHi 返回值类型即为 number。
276. 下面这些值哪些是假值?( A )
0;
new Number(0);
("");
(" ");
new Boolean(false);
undefined;
- A: 0 "" undefined
- B: 0 new Number(0) "" new Boolean(false) undefined
- C: 0 "" new Boolean(false) undefined
- D: 所有都是假值。
分析:
JavaScript 中假值只有 6 个:false、""、null、undefined、NaN、0
278. 下面代码的输出是什么?( B )
console.log(typeof typeof 1);
- A: "number"
- B: "string"
- C: "object"
- D: "undefined"
分析:
typeof 1 返回 "number",typeof "number" 返回 "string"
279. 下面代码的输出是什么?( C )
const numbers = [1, 2, 3];
numbers[10] = 11;
console.log(numbers);
- A: [1, 2, 3, 7 x null, 11]
- B: [1, 2, 3, 11]
- C: [1, 2, 3, 7 x empty, 11]
- D: SyntaxError
分析:
当你为数组中的元素设置一个超过数组长度的值时,JavaScript 会创建一个名为“空插槽”的东西。 这些位置的值实际上是 undefined,但你会看到类似的东西:
[1, 2, 3, 7 x empty, 11]
这取决于你运行它的位置(每个浏览器有可能不同)。
280. 下面代码的输出是什么?( A )
(() => {
let x, y;
try {
throw new Error();
} catch (x) {
(x = 1), (y = 2);
console.log(x);
}
console.log(x);
console.log(y);
})();
- A: 1 undefined 2
- B: undefined undefined undefined
- C: 1 1 2
- D: 1 undefined undefined
分析:
catch 块接收参数 x。当我们传递参数时,这与变量的 x 不同。这个变量 x 是属于 catch 作用域的。
之后,我们将这个块级作用域的变量设置为 1,并设置变量 y 的值。 现在,我们打印块级作用域的变量 x,它等于 1。
在catch 块之外,x 仍然是 undefined,而 y 是 2。 当我们想在 catch 块之外的 console.log(x) 时,它返回undefined,而 y 返回 2。
281. JavaScript 中的所有内容都是…( A )
- A:原始或对象
- B:函数或对象
- C:技巧问题!只有对象
- D:数字或对象
分析:
JavaScript 只有原始类型和对象。
282. 下面代码的输出是什么?
[[0, 1], [2, 3]].reduce(
(acc, cur) => {
return acc.concat(cur);
},
[1, 2]
);
- A: [0, 1, 2, 3, 1, 2]
- B: [6, 1, 2]
- C: [1, 2, 0, 1, 2, 3]
- D: [1, 2, 6]
分析:
[1,2] 是我们的初始值。 这是我们开始执行 reduce 函数的初始值,以及第一个 acc 的值。 在第一轮中,acc 是 [1,2],cur 是 [0,1]。 我们将它们连接起来,结果是 [1,2,0,1]。
然后,acc 的值为 [1,2,0,1],cur 的值为 [2,3]。 我们将它们连接起来,得到 [1,2,0,1,2,3]。
283. 下面代码的输出是什么?( B )
!!null;
!!"";
!!1;
- A: false true false
- B: false false true
- C: false true true
- D: true true false
分析:
null 是假值。 !null 返回 true。 !true 返回 false。
"" 是假值。 !"" 返回 true。 !true 返回 false。
1 是真值。 !1 返回 false。 !false 返回 true。
284. setInterval 方法的返回值什么?( A )
setInterval(() => console.log("Hi"), 1000);
- A:一个唯一的 id
- B:指定的毫秒数
- C:传递的函数
- D:undefined
分析:
它返回一个唯一的 id。 此 id 可用于使用 clearInterval() 函数清除该定时器。
285. 下面代码的返回值是什么?( A )
[..."Lydia"];
- A: ["L", "y", "d", "i", "a"]
- B: ["Lydia"]
- C: [[], "Lydia"]
- D: [["L", "y", "d", "i", "a"]]
分析:
字符串是可迭代的。 扩展运算符将迭代的每个字符映射到一个元素。
286. document.write 和 innerHTML 有哪些区别?
参考答案:
document.write 和 innerHTML 都能将 HTML 字符串解析为 DOM 树,再将 DOM 树插入到某个位置,但两种在执行细节上还是有许多不同。
1)write() 方法存在于 Document 对象中,innerHTML 属性存在于 Element 对象中;
2)document.write 会将解析后的 DOM 树插入到文档中调用它的脚本元素的位置,而 innerHTML 会将 DOM 树插入到指定的元素内;
3)document.write 会将多次调用的字符串参数自动连接起来,innerHTML 要用赋值运算符 "+=" 拼接;
4)只有当文档还在解析时,才能使用 document.write,否则 document.write 的值会将当前文档覆盖掉,而 innerHTML 属性则没有这个限制;
注:也可以参阅前面第 157 题答案
287. 假设有两个变量 a 和 b,他们的值都是数字,如何在不借用第三个变量的情况下,将两个变量的值对调?
参考答案:
方法一:
a = a + b; b = a - b; a = a - b;
方法二(ES6 中的解构):
[a, b] = [b, a]
288. 前端为什么提倡模块化开发?
参考答案:
模块化能将一个复杂的大型系统分解成一个个高内聚、低耦合的简单模块,并且每个模块都是独立的,用于完成特定的功能。模块化后的系统变得更加可控、可维护、可扩展,程序代码也更简单直观,可读性也很高,有利于团队协作开发。ES6 模块化的出现,使得前端能更容易、更快速的实现模块化开发。
289. 请解释 JSONP 的原理,并用代码描述其过程。
参考答案:
JSONP(JSON with padding) 是一种借助
<script>
元素实现跨域的技术,它不会使用 XHR 对象。之所以能实现跨域,主要是因为<script>
元素有以下两个特点:1)它的 src 属性能够访问任何 URL 资源,不会受同源策略的限制;
2)如果访问的资源包含 JavaScript 代码,那么在下载下来后会自动执行;
JSONP 就是基于这两点,再与服务器配合来实现跨域请求的,它的执行步骤可分为以下 6 步:
1)定义一个回调函数;
2)用 DOM 方法动态创建一个
<script>
元素;3)通过
<script>
元素的 src 属性指定要请求的 URL,并且将回调函数的名称作为一个参数传递过去;4)将
<script>
元素插入到当前文档中,开始请求;5)服务器接收到传递过来的参数,然后将回调函数和数据以调用的形式输出;
6)当
<script>
元素接收到响应中的脚本代码后,就会自动的执行它们;
290. 列举几种 JavaScript 中数据类型的强制转换和隐式转换。
参考答案:
强制转换:
- 转换为 number:parseInt()、parseFloat()、Number()
- 转换为 string:String()、toString()
- 转换为 boolean:Boolean()
隐式转换:
- 隐式转换为 number:算术运算/比较运算,例如加、减、乘、除、相等(==)、大于、小于等;
- 隐式转换为 string:与字符串拼接,例如 + "";
- 隐式转换为 boolean:逻辑运算,例如或(||)、与(&&)、非(!);
291. 分析以下代码的执行结果并解释为什么。
var a = {n: 1};
var b = a;
a.x = a = {n: 2};
console.log(a.x)
console.log(b.x)
参考答案:
运行结果:
undefined、{n: 2}
分析:
首先,a 和 b 同时引用了 {n: 1} 对象,接着执行到 a.x = a = {n: 2} 语句,虽然赋值是从右到左执行,但是点(.)的优先级比赋值符(=)要高,所以这里首先执行 a.x,相当于为 a(或者 b)所指向的 {n:1} 对象新增了一个属性 x,即此时对象将变为 {n: 1; x: undefined}。然后按正常情况,从右到左进行赋值,此时执行 a = {n: 2} 的时候,a的引用改变,指向了新对象 {n: 2},而 b 依然指向的是旧对象 {n: 1; x: undefined}。之后再执行 a.x = {n: 2} 的时候,并不会重新解析一遍 a,而是沿用最初解析 a.x 时候的 a,即旧对象 {n: 1; x: undefined},故此时旧对象的 x 的值变为{n: 2},旧对象为 {n: 1; x: {n: 2}},它依然被 b 引用着。
最后,a 指向的对象为 {n: 2},b 指向的对象为 {n: 1; x: {n: 2}}。因此输出 a.x 值为 undefined,输出 b.x 值为 {n: 2}。
292. 分析以下代码的执行结果并解释为什么。
// example 1
var a = {}, b = '123', c = 123;
a[b] = 'b';
a[c] = 'c';
console.log(a[b]);
// example 2
var a = {}, b = Symbol('123'), c = Symbol('123');
a[b] = 'b';
a[c] = 'c';
console.log(a[b]);
// example 3
var a = {}, b = {key:'123'}, c = {key:'456'};
a[b] = 'b';
a[c] = 'c';
console.log(a[b]);
参考答案:
运行结果:
example 1:c
example 2:b
example 3:c
分析:
这题考察的是对象的键名的转换。
- 对象的键名只能是字符串和 Symbol 类型。
- 其他类型的键名会被转换成字符串类型。
- 对象转字符串默认会调用 String 方法。
因此 example 1 中 c 作为键名后也是 '123',直接覆盖 a[b] 的值;而 example 2 中,Symbol 作为 ES6 中新增的基本数据类型,它的特点就是唯一,Symbol() 方法生成的值都是唯一的,里面的参数不会影响结果。因此在 example 2 中 b 和 c 是两个不同的键名;example 3 中,对象不能作为键名,因此 b 和 c 都会通过 String() 方法转为字符串 [object Object]。
293. 下面的代码打印什么内容?为什么?
var b = 10;
(function b() {
b = 20;
console.log(b)
})()
参考答案:
运行结果:
function b() { b = 20; console.log(b) } 分析:
当 JavaScript 解释器遇到非匿名立即执行函数(题目中的 b)时,会创建一个辅助的特定对象,然后将函数名称当作这个对象的属性,因此函数内部可以访问到 b,但是这个值又是只读的,所以对他的赋值并不生效,所以打印的结果还是这个函数,并且外部的值也没有发生更改。
294. 下面代码中,a 在什么情况下会执行输出语句打印 1 ?
var a = ?;
if(a == 1 && a == 2 && a == 3){
console.log(1);
}
参考答案:
分析:
这道题考查的知识点是:相等运算符(==)在作比较时会进行隐式转换,而如果操作数是引用类型,则会调用 toString() 或 valueOf() 方法对引用类型数据进行隐式转换。
// 方法一:利用 toString() let a = { i: 1, toString () { return a.i++; } } if(a == 1 && a == 2 && a == 3) { console.log('1'); } // 方法二:利用 valueOf() let a = { i: 1, valueOf () { return a.i++ } } if(a == 1 && a == 2 && a == 3) { console.log('1'); } // 方法三:利用数组(这个是真的骚) var a = [1,2,3]; a.join = a.shift; if(a == 1 && a == 2 && a == 3) { console.log('1'); } // 方法四:利用 Symbol let a = {[Symbol.toPrimitive]: ((i) => () => ++i) (0)}; if(a == 1 && a == 2 && a == 3) { console.log('1'); }
方法一和方法二没啥解释的了,解释下方法三和方法四。
方法三:
a.join = a.shift 的目的是将数组的 join 方法替换成 shift 方法。因为数组在参与相等比较时也会通过 toString() 将数组转为字符串,而该字符串实际上是数组中每个元素的 toString() 返回值经调用 join() 方法拼接(由逗号隔开)组成。现在我们将 join() 方法替换为了 shift() 方法,也就意味着数组在通过 toString() 隐式转换后,得到是 shift() 的返回值,每次返回数组中的第一个元素,而原数组删除第一个值,正好可以使判断成立。
方法四:
ES6 中提供了 11 个内置的 Symbo 值,指向语言内部使用的方法。Symbol.toPrimitive 就是其中一个,它指向一个方法,当该对象被转为原始类型的值时,会调用这个方法,并返回该对象对应的原始类型值。这里就是改变这个属性,把它的值改为一个闭包返回的函数。
295. 介绍前端模块化的发展。
参考答案:
IIFE:使用自执行函数来编写模块化(特点:在一个单独的函数作用域中执行代码,避免变量冲突)。
(function(){ return { data:[] } })()
AMD:使用 requireJS 来编写模块化(特点:依赖必须提前声明好)。
define('./index.js',function(code){ // code 就是index.js 返回的内容 })
CMD:使用 seaJS 来编写模块化(特点:支持动态引入依赖文件)。
define(function(require, exports, module) { var indexCode = require('./index.js'); });
CommonJS:nodejs 中自带的模块化。
var fs = require('fs');
UMD:通用模块规范,整合了 AMD 和 CommonJS 模块化。
(function (global, factory) { if (typeof exports === 'object' && typeof module !== undefined) { //检查CommonJS是否可用 module.exports = factory(require('jquery')); } else if (typeof define === 'function' && define.amd) { //检查AMD是否可用 define('toggler', ['jquery', factory]) } else { //两种都不能用,把模块添加到JavaScript的全局命名空间中。 global.toggler = factory(global, factory); } })(this, function ($) { function init() { } return { init: init } });
webpack(require.ensure):webpack 2.x 版本中的代码分割。
ES Modules: ES6 引入的模块化,支持 import 来引入另一个 js 。
296. 请指出 document.onload 和 document.ready 两个事件的区别
参考答案:
页面加载完成有两种事件:一是 ready,表示文档结构已经加载完成(不包含图片等非文字媒体文件);二是 onload,指示页面包含图片等文件在内的所有元素都加载完成。
297. 表单元素的readonly 和 disabled 两个属性有什么区别?
参考答案:
- readonly:
- 不可编辑,但可以选择和复制;
- 值可以传递到后台;
- disabled:
- 不能编辑,不能复制,不能选择;
- 值不可以传递到后台;
298. 列举几种你知道的数组排序的方法。
参考答案:
// 方法一:选择排序 let ary = [5, 7, 8, 11, 3, 6, 4]; for (let i = 0; i < ary.length - 1; i++) { for (let j = i + 1; j < ary.length; j++) { if (ary[i] < ary[j]) { [ary[i], ary[j]] = [ary[j], ary[i]]; } } }
// 方法二:冒泡排序 let ary = [5, 7, 8, 11, 3, 6, 4]; for (let i = 1; i < ary.length; i++) { for (let j = 0; j < ary.length - i; j++) { if (ary[j] < ary[j + 1]) { [ary[j], ary[j + 1]] = [ary[j + 1], ary[j]] } } }
299. 区分什么是“客户区坐标”、“页面坐标”、“屏幕坐标”?
参考答案:
- 客户区坐标:鼠标指针在可视区中的水平坐标 (clientX) 和垂直坐标 (clientY);
- 页面坐标:鼠标指针在页面布局中的水平坐标 (pageX) 和垂直坐标 (pageY);
- 屏幕坐标:设备物理屏幕的水平坐标 (screenX) 和垂直坐标 (screenY);
300. 如何编写高性能的 JavaScript?
参考答案:
- 遵循严格模式:"use strict"
- 将 JavaScript 本放在页面底部,加快渲染页面
- 将 JavaScript 脚本将脚本成组打包,减少请求
- 使用非阻塞方式下载 JavaScript 脚本
- 尽量使用局部变量来保存全局变量
- 尽量减少使用闭包
- 使用 window 对象属性方法时,省略 window
- 尽量减少对象成员嵌套
- 缓存 DOM 节点的访问
- 通过避免使用 eval() 和 Function() 构造器
- 给 setTimeout() 和 setInterval() 传递函数而不是字符串作为参数
- 尽量使用直接量创建对象和数组
- 最小化重绘 (repaint) 和回流 (reflow)
301. 下面的代码输出什么?
var a = function () { return 5 }
a.toString = function () { return 3 }
console.log(a + 7);
参考答案:
10
因为会自动调用 a 函数的 toString 方法。
Comments