之后在直播课或者录屏课进行详细的讲解
第二个问题,解释型语言和编译型语言的差异是什么?
电脑能认得的是二进制数,不能够识别高级语言。所有高级语言在电脑上执行都需要先转变为机器语言。但是高级语言有两种类型,编译型语言和解释型语言。常见的编译型语言语言有C/C++、Pascal/Object 等等。常见的解释性语言有python、JavaScript等等。
编译型语言先要进行编译,然后转为特定的可执行文件,这个可执行文件是针对平台的(CPU类型),可以这么理解你在PC上编译一个C源文件,需要经过预处理,编译,汇编等等过程生成一个可执行的二进制文件。当你需要再次运行改代码时,不需要重新编译代码,只需要运行该可执行的二进制文件。优点,编译一次,永久执行。还有一个优点是,你不需要提供你的源代码,你只需要发布你的可执行文件就可以为客户提供服务,从而保证了你的源代码的安全性。但是,如果你的代码需要迁移到linux、ARM下时,这时你的可执行文件就不起作用了,需要根据新的平台编译出一个可执行的文件。这也就是多个平台需要软件的多个版本。缺点是,跨平台能力差。
解释型语言需要一个解释器,在源代码执行的时候被解释器翻译为一个与平台无关的中间代码,解释器会把这些代码翻译为及其语言。打个比方,编译型中的编译相当于一个翻译官,它只能翻译英语,而且中文文章翻译一次就不需要重新对文章进行二次翻译了,但是如果需要叫这个翻译官翻译德语就不行了。而解释型语言中的解释器相当于一个会各种语言的机器人,而且这个机器人回一句一句的翻译你的语句。对于不同的国家,翻译成不同的语言,所以,你只需要带着这个机器人就可以。解释型语言的有点是,跨平台,缺点是运行时需要源代码,知识产权保护性差,运行效率低。
此方法与之前说到的console.error
一样,用于输出信息,没有什么特别之处。
可将传入的对象,或数组以表格形式输出,相比传统树形输出,这种输出方案更适合内部元素排列整齐的对象或数组,不然可能会出现很多的 undefined。
输入一段 log 信息。
这是个挺高大上的东西,可用于性能分析。在 JS 开发中,我们常常要评估段代码或是某个函数的性能。在函数中手动打印时间固然可以,但显得不够灵活而且有误差。借助控制台以及console.profile()
方法我们可以很方便地监控运行性能。
console.trace()
用来追踪函数的调用过程。在大型项目尤其是框架开发中,函数的调用轨迹可以十分复杂,console.trace()
方法可以将函数的被调用过程清楚地输出到控制台上。
输出参数的内容,作为警告提示。
请参阅前面第 31 题答案。
-
get,一旦目标属性被访问时,就会调用相应的方法
-
set,一旦目标属性被设置时,就会调用相应的方法
-
writable,这是一个布尔值,表示一个属性是否可以被修改,默认是 true
-
enumerable,这是一个布尔值,表示在用 for-in 循环遍历对象的属性时,该属性是否可以显示出来,默认值为 true
-
configurable,这是一个布尔值,表示我们是否能够删除一个属性或者修改属性的特性,默认值为 true
可以用于监听对象的数据变化
此外 还有以下配置项 ,
-
只能劫持对象的属性,属性值也是对象那么需要深度遍历
2、proxy ,可以理解为在被劫持的对象之前 加了一层拦截
-
proxy 返回的是一个新对象, 可以通过操作返回的新的对象达到目的
-
Object.defineProperty 无法监控到数组下标的变化,导致通过数组下标添加元素,不能实时响应
-
Object.defineProperty 只能劫持对象的属性,从而需要对每个对象,每个属性进行遍历,如果,属性值是对象,还需要深度遍历。Proxy 可以劫持整个对象,并返回一个新的对象。
-
Proxy 不仅可以代理对象,还可以代理数组。还可以代理动态增加的属性。
instanceof 主要作用就是判断一个实例是否属于某种类型
因此,instanceof 在查找的过程中会遍历左边变量的原型链,直到找到右边变量的 prototype,如果查找失败,则会返回 false,告诉我们左边变量并非是右边变量的实例。
228. 强制类型转换规则?
首先需要参阅前面第 104 题答案。了解隐式转换所调用的函数。
其实这三个函数不仅仅可以当作构造函数,它们可以直接当作普通的函数来使用,将任何类型的参数转化成原始类型的值,
== (或者 !=) 操作在需要的情况下自动进行了类型转换。=== (或 !==)操作不会执行任何转换。
=在比较值和类型时,可以说比更快。
230. +
操作符什么时候用于字符串的拼接?
在有一边操作数是字符串时会进行字符串拼接。
这两个方式都是浅拷贝。
在拷贝的对象只有一层时是深拷贝,但是一旦对象的属性值又是一个对象,也就是有两层或者两层以上时,就会发现这两种方式都是浅拷贝。
可以修改,具体原因可以参阅前面第 231 题。
233. 如果 new 一个箭头函数的会怎么样
会报错,因为箭头函数无法作为构造函数。
234. 扩展运算符的作用及使用场景
扩展运算符是三个点(…),主要用于展开数组,将一个数组转为参数序列。
Proxy 是 ES6 中新增的一个特性。Proxy 让我们能够以简洁易懂的方式控制外部对对象的访问。其功能非常类似于设计模式中的代理模式。
Proxy 在目标对象的外层搭建了一层拦截,外界对目标对象的某些操作,必须通过这层拦截。
使用 Proxy 的好处是对象只需关注于核心逻辑,一些非核心的逻辑(如,读取或设置对象的某些属性前记录日志;设置对象的某些属性值前,需要验证;某些属性的访问控制等)可以让 Proxy 来做。从而达到关注点分离,降级对象复杂度的目的。
Proxy 的基本语法如下,
通过构造函数来生成 Proxy 实例,构造函数接收两个参数。target 参数是要拦截的目标对象,handler 参数也是一个对象,用来定制拦截行为。
236. 对象与数组的解构的理解
解构是 ES6 的一种语法规则,可以将一个对象或数组的某个属性提取到某个变量中。
237. 如何提取高度嵌套的对象里的指定属性?
一般会使用递归的方式来进行查找。下面是一段示例代码,
Unicode 为世界上所有字符都分配了一个唯一的数字编号,这个编号范围从 0x000000 到 0x10FFFF (十六进制),有 110 多万,每个字符都有一个唯一的 Unicode 编号,这个编号一般写成 16 进制,在前面加上
Unicode 就相当于一张表,建立了字符与编号之间的联系。
Unicode 本身只规定了每个字符的数字编号是多少,并没有规定这个编号如何存储。
那我们可以直接把 Unicode 编号直接转换成二进制进行存储,怎么对应到二进制表示呢?
Unicode 可以使用的编码有三种,分别是,
-
UFT-8,一种变长的编码方案,使用 1~6 个字节来存储;
-
UFT-32,一种固定长度的编码方案,不管字符编号大小,始终使用 4 个字节来存储;
-
UTF-16,介于 UTF-8 和 UTF-32 之间,使用 2 个或者 4 个字节来存储,长度既固定又可变。
239. 为什么函数的 arguments 参数是类数组而不是数组?如何遍历类数组?
首先了解一下什么是数组对象和类数组对象。
数组对象,使用单独的变量名来存储一系列的值。从 Array 构造函数中继承了一些用于进行数组操作的方法。
类数组对象,对于一个普通的对象来说,如果它的所有 property 名均为正整数,同时也有相应的length属性,那么虽然该对象并不是由Array构造函数所创建的,它依然呈现出数组的行为,在这种情况下,这些对象被称为“类数组对象”。
所以说arguments对象不是一个 Array 。它类似于Array,但除了length属性和索引元素之外没有任何Array属性。
escape 除了 ASCII 字母、数字和特定的符号外,对传进来的字符串全部进行转义编码,因此如果想对 URL 编码,最好不要使用此方法。
encodeURI 用于编码整个 URI,因为 URI 中的合法字符都不会被编码转换。
encodeURIComponent 方法在编码单个URIComponent(指请求参数)应当是最常用的,它可以讲参数中的中文、特殊字符进行转义,而不会影响整个 URL。
use strict 代表开启严格模式,这种模式使得 Javascript 在更严格的条件下运行,实行更严格解析和错误处理。
开启“严格模式”的优点,
- 消除 Javascript 语法的一些不合理、不严谨之处,减少一些怪异行为;
- 消除代码运行的一些不安全之处,保证代码运行的安全;
- 提高编译器效率,增加运行速度;
JavaScript 原有的 for…in 循环,只能获得对象的键名,不能直接获取键值。ES6 提供 for…of 循环,允许遍历获得键值。
ajax 是指一种创建交互式网页应用的网页开发技术,并且可以做到无需重新加载整个网页的情况下,能够更新部分网页,也叫作局部更新。
使用 ajax 发送请求是依靠于一个对象,叫 XmlHttpRequest 对象,通过这个对象我们可以从服务器获取到数据,然后再渲染到我们的页面上。现在几乎所有的浏览器都有这个对象,只有 IE7 以下的没有,而是通过 ActiveXObject 这个对象来创建的。
Fetch 是 ajax 非常好的一个替代品,基于 Promise 设计,使用 Fetch 来获取数据时,会返回给我们一个 Pormise 对象,但是 Fetch 是一个低层次的 API,想要很好的使用 Fetch,需要做一些封装处理。
下面是 Fetch 的一些缺点
-
Fetch 只对网络请求报错,对 400,500 都当做成功的请求,需要封装去处理
-
Fetch 默认不会带 cookie,需要添加配置项。
-
Fetch 不支持 abort,不支持超时控制,使用 setTimeout 及 Promise.reject 的实现超时控制并不能阻止请求过程继续在后台运行,造成了流量的浪费。
-
Fetch 没有办法原生监测请求的进度,而 XHR 可以。
Vue2.0 之后,axios 开始受到更多的欢迎了。其实 axios 也是对原生 XHR 的一种封装,不过是 Promise 实现版本。它可以用于浏览器和 nodejs 的 HTTP 客户端,符合最新的 ES 规范。
244. 下面代码的输出是什么?( D )
let 声明的 age 不会发生变量提升,在输出 age 时该变量还未声明,因此会抛出 ReferenceError 的报错。
245. 下面代码的输出是什么?( C )
第一个 for 循环中的变量 i 通过 var 声明, 为全局变量,因此每一次的 i++ 都会将全局变量 i 的值加 1,当第一个 for 执行完成后 i 的值为 3。所以再执行 setTimeout
时,输出 i 的值都为 3;
第二个 for 循环中的变量 i 通过 let 声明,为局部变量,因此每一次 for 循环时都会产生一个块级作用域,用来存储本次循环中新产生的 i 的值。当循环结束后,setTimeout 会沿着作用域链去对应的块级作用域中寻找对应的 i 值。
246. 下面代码的输出是什么?( B )
247. 下面代码的输出是什么?( A )
一元加号会将数据隐式转换为 number 类型,true 转换为数值为 1;
非运算符 ! 会将数据隐式转换为 boolean 类型后进行取反,“Lydia” 转换为布尔值为 true,取反后为 false。
248. 哪个选项是不正确的?( A )
249. 下面代码的输出是什么?( A )
在 JavaScript 中,复杂类型数据在进行赋值操作时,进行的是「引用传递」,因此变量 d 和 c 指向的是同一个引用。当 c 通过引用去修改了数据后,d 再通过引用去访问数据,获取到的实际就是 c 修改后的数据。
250. 下面代码的输出是什么?( C )
new Number() 是 JavaScript 中一个内置的构造函数。变量 b 虽然看起来像一个数字,但它并不是一个真正的数字,它有一堆额外的功能,是一个对象。
== 会触发隐式类型转换,右侧的对象类型会自动转换为 Number 类型,因此最终返回 true。
=== 不会触发隐式类型转换,因此在比较时由于数据类型不相等而返回 false。
251. 下面代码的输出是什么?( D )
colorChange 方法是静态的。 静态方法仅在创建它们的构造函数中存在,并且不能传递给任何子级。 由于 freddie 是一个子级对象,函数不会传递,所以在 freddie 实例上不存在 colorChange 方法,抛出TypeError。
252. 下面代码的输出是什么?( A )
控制台会输出空对象,因为我们刚刚在全局对象上创建了一个空对象!
253. 当我们执行以下代码时会发生什么?( A )
因为函数也是对象!(原始类型之外的所有东西都是对象)
函数是一种特殊类型的对象,我们可以给函数添加属性,且此属性是可调用的。
254. 下面代码的输出是什么?( A )
Person.getFullName 是将方法添加到了函数身上,因此当我们通过实例对象 member 去调用该方法时并不能找到该方法。
255. 下面代码的输出是什么?( A )
sarah 是调用普通函数后得到的返回值,而 Person 作为普通函数没有返回值;
256. 事件传播的三个阶段是什么?( D )
257. 下面代码的输出是什么?( C )
任意数据类型在跟 String 做 + 运算时,都会隐式转换为 String 类型。
即 a 所对应的 Number 值 1,被隐式转换为了 String 值 “1”,最终字符串拼接的到 “12”。
258. 下面代码的输出是什么?( C )
++ 后置时,先输出,后加 1;++ 前置时,先加 1,后输出;
第一次输出的值为 0,输出完成后 number 加 1 变为 1。
第二次输出,number 先加 1 变为 2,然后输出值 2。
第三次输出,number 值没有变化,还是 2。
259. 下面代码的输出是什么?( B )
如果使用标记的模板字符串,则第一个参数的值始终是字符串值的数组。 其余参数获取传递到模板字符串中的表达式的值!
260. 下面代码的输出是什么?( C )
在比较相等性时,原始类型通过它们的值进行比较,而对象通过它们的引用进行比较。
data 和条件中的 { age: 18 } 两个不同引用的对象,因此永远都不相等。
261. 下面代码的输出是什么?( C )
ES6 中的不定参数(…args)返回的是一个数组。
262. 下面代码的输出是什么?( C )
“use strict” 严格模式中,使用未声明的变量会引发报错。
263. 下面代码的输出是什么?( A )
- A,永远,数据不会丢失。
- B,用户关闭选项卡时。
- C,当用户关闭整个浏览器时,不仅是选项卡。
- D,用户关闭计算机时。
sessionStorage 是会话级别的本地存储,当窗口关闭,则会话结束,数据删除。
265. 下面代码的输出是什么?( B )
var 声明的变量允许重复声明,但后面的值会覆盖前面的值。
266. 下面代码的输出是什么?( C )
267. 下面代码的输出是什么?( C )
如果对象有两个具有相同名称的键,则后面的将替前面的键。它仍将处于第一个位置,但具有最后指定的值。
268. 下面代码的输出是什么?( C )
当 i 的值为 3 时,进入 if 语句执行 continue,结束本次循环,立即进行下一次循环。
269. 下面代码的输出是什么?( A )
String 是一个内置的构造函数,我们可以为它添加属性。 我们给它的原型添加了一个方法。 原始类型的字符串自动转换为字符串对象,由字符串原型函数生成。 因此,所有字符串(字符串对象)都可以访问该方法!
当使用基本类型的字符串调用 giveLydiaPizza 时,实际上发生了下面的过程,
270. 下面代码的输出是什么?( B )
当 b 和 c 作为一个对象的键时,会自动转换为字符串,而对象自动转换为字符串化时,结果都为 [Object object]。因此 a[b] 和 a[c] 其实都是同一个属性 a[“Object object”]。
对象同名的属性后面的值会覆盖前面的,因此最终 a[“Object object”] 的值为 456。
271. 下面代码的输出是什么?( B )
bar 函数中执行的是一段异步代码,按照 JavaScript 中的事件循环机制,主线程中的所有同步代码执行完成后才会执行异步代码。因此 “Second” 最后输出。
273. 单击下面的 html 片段打印的内容是什么?( A )
onclick 绑定的事件为冒泡型事件。因此当点击 p 标签时,事件会从事件目标开始依次往外触发。
274. 下面代码的输出是什么?( D )
call 和 bind 都可以修改 this 的指向,但区别在于 call 方法会立即执行,而 bind 会返回一个修改后的新函数。
275. 下面代码的输出是什么?( B )
276. 下面这些值哪些是假值?( A )
278. 下面代码的输出是什么?( B )
279. 下面代码的输出是什么?( C )
当你为数组中的元素设置一个超过数组长度的值时,JavaScript 会创建一个名为“空插槽”的东西。 这些位置的值实际上是 undefined,但你会看到类似的东西,
这取决于你运行它的位置(每个浏览器有可能不同)。
280. 下面代码的输出是什么?( A )
catch 块接收参数 x。当我们传递参数时,这与变量的 x 不同。这个变量 x 是属于 catch 作用域的。
之后,我们将这个块级作用域的变量设置为 1,并设置变量 y 的值。 现在,我们打印块级作用域的变量 x,它等于 1。
282. 下面代码的输出是什么?
[1,2] 是我们的初始值。 这是我们开始执行 reduce 函数的初始值,以及第一个 acc 的值。 在第一轮中,acc 是 [1,2],cur 是 [0,1]。 我们将它们连接起来,结果是 [1,2,0,1]。
283. 下面代码的输出是什么?( B )
285. 下面代码的返回值是什么?( A )
字符串是可迭代的。 扩展运算符将迭代的每个字符映射到一个元素。
2)document.write 会将解析后的 DOM 树插入到文档中调用它的脚本元素的位置,而 innerHTML 会将 DOM 树插入到指定的元素内;
3)document.write 会将多次调用的字符串参数自动连接起来,innerHTML 要用赋值运算符 “+=” 拼接;
注,也可以参阅前面第 157 题答案
287. 假设有两个变量 a 和 b,他们的值都是数字,如何在不借用第三个变量的情况下,将两个变量的值对调?
方法二(ES6 中的解构),
288. 前端为什么提倡模块化开发?
模块化能将一个复杂的大型系统分解成一个个高内聚、低耦合的简单模块,并且每个模块都是独立的,用于完成特定的功能。模块化后的系统变得更加可控、可维护、可扩展,程序代码也更简单直观,可读性也很高,有利于团队协作开发。ES6 模块化的出现,使得前端能更容易、更快速的实现模块化开发。
289. 请解释 JSONP 的原理,并用代码描述其过程。
1)它的 src 属性能够访问任何 URL 资源,不会受同源策略的限制;
2)如果访问的资源包含 JavaScript 代码,那么在下载下来后会自动执行;
JSONP 就是基于这两点,再与服务器配合来实现跨域请求的,它的执行步骤可分为以下 6 步,
1)定义一个回调函数;
3)通过 <script> 元素的 src 属性指定要请求的 URL,并且将回调函数的名称作为一个参数传递过去;
4)将 <script> 元素插入到当前文档中,开始请求;
5)服务器接收到传递过来的参数,然后将回调函数和数据以调用的形式输出;
6)当 <script> 元素接收到响应中的脚本代码后,就会自动的执行它们;
290. 列举几种 JavaScript 中数据类型的强制转换和隐式转换。
- 隐式转换为 number,算术运算/比较运算,例如加、减、乘、除、相等(==)、大于、小于等;
- 隐式转换为 string,与字符串拼接,例如 + “”;
- 隐式转换为 boolean,逻辑运算,例如或(||)、与(&&)、非(!);
291. 分析以下代码的执行结果并解释为什么。
首先,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:
292. 分析以下代码的执行结果并解释为什么。
这题考察的是对象的键名的转换。
-
对象的键名只能是字符串和 Symbol 类型。
- 其他类型的键名会被转换成字符串类型。
- 对象转字符串默认会调用 String 方法。
方法生成的值都是唯一的,里面的参数不会影响结果。因此在 example 2 中 b 和 c 是两个不同的键名;example 3 中,对象不能作为键名,因此 b 和 c 都会通过 String() 方法转为字符串 [object
293. 下面的代码打印什么内容?为什么?
当 JavaScript 解释器遇到非匿名立即执行函数(题目中的 b)时,会创建一个辅助的特定对象,然后将函数名称当作这个对象的属性,因此函数内部可以访问到 b,但是这个值又是只读的,所以对他的赋值并不生效,所以打印的结果还是这个函数,并且外部的值也没有发生更改。
294. 下面代码中,a 在什么情况下会执行输出语句打印 1 ?
这道题考查的知识点是,相等运算符(==)在作比较时会进行隐式转换,而如果操作数是引用类型,则会调用 toString() 或 valueOf() 方法对引用类型数据进行隐式转换。
方法一和方法二没啥解释的了,解释下方法三和方法四。
a.join = a.shift 的目的是将数组的 join 方法替换成 shift 方法。因为数组在参与相等比较时也会通过 toString() 将数组转为字符串,而该字符串实际上是数组中每个元素的 toString() 返回值经调用 join()
方法拼接(由逗号隔开)组成。现在我们将 join() 方法替换为了 shift() 方法,也就意味着数组在通过 toString() 隐式转换后,得到是 shift() 的返回值,每次返回数组中的第一个元素,而原数组删除第一个值,正好可以使判断成立。
ES6 中提供了 11 个内置的 Symbo 值,指向语言内部使用的方法。Symbol.toPrimitive 就是其中一个,它指向一个方法,当该对象被转为原始类型的值时,会调用这个方法,并返回该对象对应的原始类型值。这里就是改变这个属性,把它的值改为一个闭包返回的函数。
295. 介绍前端模块化的发展。
-
IIFE,使用自执行函数来编写模块化(特点,在一个单独的函数作用域中执行代码,避免变量冲突)。
-
AMD,使用 requireJS 来编写模块化(特点,依赖必须提前声明好)。
-
CMD,使用 seaJS 来编写模块化(特点,支持动态引入依赖文件)。
页面加载完成有两种事件,一是 ready,表示文档结构已经加载完成(不包含图片等非文字媒体文件);二是 onload,指示页面包含图片等文件在内的所有元素都加载完成。
298. 列举几种你知道的数组排序的方法。
299. 区分什么是“客户区坐标”、“页面坐标”、“屏幕坐标”?
- 客户区坐标,鼠标指针在可视区中的水平坐标 (clientX) 和垂直坐标 (clientY);
- 页面坐标,鼠标指针在页面布局中的水平坐标 (pageX) 和垂直坐标 (pageY);
- 屏幕坐标,设备物理屏幕的水平坐标 (screenX) 和垂直坐标 (screenY);
- 将 JavaScript 本放在页面底部,加快渲染页面
- 将 JavaScript 脚本将脚本成组打包,减少请求
- 尽量使用局部变量来保存全局变量
- 缓存 DOM 节点的访问
- 尽量使用直接量创建对象和数组
301. 下面的代码输出什么?