【面试篇】寒冬求职季之你必须要懂的原生JS

本文提供了Java、算法数据结构、数据库等多个编程领域的入门到进阶书单。同时梳理了一系列有难度的高频原生JS面试题,包括数据类型判断、循环区别、数组API、ES6特性等内容,并给出详细解答,助力读者提升编程知识与面试能力。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

附Java/C/C++/机器学习/算法与数据结构/前端/安卓/Python/程序员必读书籍书单大全:

书单导航页(点击右侧 极客侠栈 即可打开个人博客):极客侠栈
【Java】学习之路吐血整理技术书从入门到进阶最全50+本(珍藏版)
【算法数据结构+acm】从入门到进阶吐血整理书单50+本(珍藏版)
【数据库】从入门到进阶必读18本技术书籍网盘吐血整理网盘(珍藏版)
【Web前端】从HTML到JS到AJAX到HTTP从框架到全栈帮你走更少弯路(珍藏版)   
【python】书最全已整理好(从入门到进阶)(珍藏版)

【机器学习】+python整理技术书(从入门到进阶已经整理好)(珍藏版)
【C语言】推荐书籍从入门到进阶带你走上大牛之路(珍藏版)
【安卓】入门到进阶推荐书籍整理pdf书单整理(珍藏版)

【架构师】之路史诗级必读书单吐血整理四个维度系列80+本书(珍藏版)

【C++】吐血整理推荐书单从入门到进阶成神之路100+本(珍藏)

【ios】IOS书单从入门到进阶吐血整理(珍藏版)

-------------------------------------------------------------------------------------------------------------------------------------------

互联网寒冬之际,各大公司都缩减了HC,甚至是采取了“裁员”措施,在这样的大环境之下,想要获得一份更好的工作,必然需要付出更多的努力。

一年前,也许你搞清楚闭包,this,原型链,就能获得认可。但是现在,很显然是不行了。本文梳理出了一些面试中有一定难度的高频原生JS问题,部分知识点可能你之前从未关注过,或者看到了,却没有仔细研究,但是它们却非常重要。

本文将以真实的面试题的形式来呈现知识点,大家在阅读时,建议不要先看我的答案,而是自己先思考一番。尽管,本文所有的答案,都是我在翻阅各种资料,思考并验证之后,才给出的(绝非复制粘贴而来)。但因水平有限,本人的答案未必是最优的,如果您有更好的答案,欢迎给我留言。

本文篇幅较长,但是满满的都是干货!并且还埋伏了可爱的表情包,希望小伙伴们能够坚持读完。

衷心的祝愿大家都能找到心仪的工作。

1. 基本类型有哪几种?null 是对象吗?基本数据类型和复杂数据类型存储有什么区别?

  • 基本类型有6种,分别是undefined,null,bool,string,number,symbol(ES6新增)。
  • 虽然 typeof null 返回的值是 object,但是null不是对象,而是基本数据类型的一种。
  • 基本数据类型存储在栈内存,存储的是值。
  • 复杂数据类型的值存储在堆内存,地址(指向堆中的值)存储在栈内存。当我们把对象赋值给另外一个变量的时候,复制的是地址,指向同一块内存空间,当其中一个对象改变时,另一个对象也会变化。

2. typeof 是否正确判断类型? instanceof呢? instanceof 的实现原理是什么?

首先 typeof 能够正确的判断基本数据类型,但是除了 null, typeof null输出的是对象。

但是对象来说,typeof 不能正确的判断其类型, typeof 一个函数可以输出 ‘function’,而除此之外,输出的全是 object,这种情况下,我们无法准确的知道对象的类型。

instanceof可以准确的判断复杂数据类型,但是不能正确判断基本数据类型。(正确判断数据类型请戳:https://github.com/YvetteLau/Blog/blob/master/JS/data-type.js)

instanceof 是通过原型链判断的,A instanceof B, 在A的原型链中层层查找,是否有原型等于B.prototype,如果一直找到A的原型链的顶端(null;即Object.prototype.__proto__),仍然不等于B.prototype,那么返回false,否则返回true.

instanceof的实现代码:

<span style="color:#1c1f21"><code class="language-javascript"><span style="color:#708090">// L instanceof R</span>
<span style="color:#36bcd6">function</span> <span style="color:#f92672">instance_of</span><span style="color:#999999">(</span>L<span style="color:#999999">,</span> R<span style="color:#999999">)</span> <span style="color:#999999">{</span><span style="color:#708090">//L 表示左表达式,R 表示右表达式</span>
    <span style="color:#36bcd6">var</span> O <span style="color:#a67f59">=</span> R<span style="color:#999999">.</span>prototype<span style="color:#999999">;</span><span style="color:#708090">// 取 R 的显式原型</span>
    L <span style="color:#a67f59">=</span> L<span style="color:#999999">.</span>__proto__<span style="color:#999999">;</span>    <span style="color:#708090">// 取 L 的隐式原型</span>
    <span style="color:#36bcd6">while</span> <span style="color:#999999">(</span><span style="color:#ae81ff">true</span><span style="color:#999999">)</span> <span style="color:#999999">{</span> 
        <span style="color:#36bcd6">if</span> <span style="color:#999999">(</span>L <span style="color:#a67f59">===</span> <span style="color:#36bcd6">null</span><span style="color:#999999">)</span> <span style="color:#708090">//已经找到顶层</span>
            <span style="color:#36bcd6">return</span> <span style="color:#ae81ff">false</span><span style="color:#999999">;</span>  
        <span style="color:#36bcd6">if</span> <span style="color:#999999">(</span>O <span style="color:#a67f59">===</span> L<span style="color:#999999">)</span>   <span style="color:#708090">//当 O 严格等于 L 时,返回 true</span>
            <span style="color:#36bcd6">return</span> <span style="color:#ae81ff">true</span><span style="color:#999999">;</span> 
        L <span style="color:#a67f59">=</span> L<span style="color:#999999">.</span>__proto__<span style="color:#999999">;</span>  <span style="color:#708090">//继续向上一层原型链查找</span>
    <span style="color:#999999">}</span> 
<span style="color:#999999">}</span>
</code></span>

3. for of , for in 和 forEach,map 的区别。

  • for…of循环:具有 iterator 接口,就可以用for…of循环遍历它的成员(属性值)。for…of循环可以使用的范围包括数组、Set 和 Map 结构、某些类似数组的对象、Generator 对象,以及字符串。for…of循环调用遍历器接口,数组的遍历器接口只返回具有数字索引的属性。对于普通的对象,for…of结构不能直接使用,会报错,必须部署了 Iterator 接口后才能使用。可以中断循环。
  • for…in循环:遍历对象自身的和继承的可枚举的属性, 不能直接获取属性值。可以中断循环。
  • forEach: 只能遍历数组,不能中断,没有返回值(或认为返回值是undefined)。
  • map: 只能遍历数组,不能中断,返回值是修改后的数组。

PS: Object.keys():返回给定对象所有可枚举属性的字符串数组

关于forEach是否会改变原数组的问题,有些小伙伴提出了异议,为此我写了代码测试了下(注意数组项是复杂数据类型的情况)。
除了forEach之外,map等API,也有同样的问题。

<span style="color:#1c1f21"><code class="language-javascript"><span style="color:#36bcd6">let</span> arry <span style="color:#a67f59">=</span> <span style="color:#999999">[</span><span style="color:#ae81ff">1</span><span style="color:#999999">,</span> <span style="color:#ae81ff">2</span><span style="color:#999999">,</span> <span style="color:#ae81ff">3</span><span style="color:#999999">,</span> <span style="color:#ae81ff">4</span><span style="color:#999999">]</span><span style="color:#999999">;</span>

arry<span style="color:#999999">.</span><span style="color:#f92672">forEach</span><span style="color:#999999">(</span><span style="color:#999999">(</span>item<span style="color:#999999">)</span> <span style="color:#a67f59">=></span> <span style="color:#999999">{</span>
    item <span style="color:#a67f59">*=</span> <span style="color:#ae81ff">10</span><span style="color:#999999">;</span>
<span style="color:#999999">}</span><span style="color:#999999">)</span><span style="color:#999999">;</span>
console<span style="color:#999999">.</span><span style="color:#f92672">log</span><span style="color:#999999">(</span>arry<span style="color:#999999">)</span><span style="color:#999999">;</span> <span style="color:#708090">//[1, 2, 3, 4]</span>

arry<span style="color:#999999">.</span><span style="color:#f92672">forEach</span><span style="color:#999999">(</span><span style="color:#999999">(</span>item<span style="color:#999999">)</span> <span style="color:#a67f59">=></span> <span style="color:#999999">{</span>
    arry<span style="color:#999999">[</span><span style="color:#ae81ff">1</span><span style="color:#999999">]</span> <span style="color:#a67f59">=</span> <span style="color:#ae81ff">10</span><span style="color:#999999">;</span> <span style="color:#708090">//直接操作数组</span>
<span style="color:#999999">}</span><span style="color:#999999">)</span><span style="color:#999999">;</span>
console<span style="color:#999999">.</span><span style="color:#f92672">log</span><span style="color:#999999">(</span>arry<span style="color:#999999">)</span><span style="color:#999999">;</span> <span style="color:#708090">//[ 1, 10, 3, 4 ]</span>

<span style="color:#36bcd6">let</span> arry2 <span style="color:#a67f59">=</span> <span style="color:#999999">[</span>
    <span style="color:#999999">{</span> name<span style="color:#999999">:</span> <span style="color:#78ab12">"Yve"</span> <span style="color:#999999">}</span><span style="color:#999999">,</span>
    <span style="color:#999999">{</span> age<span style="color:#999999">:</span> <span style="color:#ae81ff">20</span> <span style="color:#999999">}</span>
<span style="color:#999999">]</span><span style="color:#999999">;</span>
arry2<span style="color:#999999">.</span><span style="color:#f92672">forEach</span><span style="color:#999999">(</span><span style="color:#999999">(</span>item<span style="color:#999999">)</span> <span style="color:#a67f59">=></span> <span style="color:#999999">{</span>
    item<span style="color:#999999">.</span>name <span style="color:#a67f59">=</span> <span style="color:#ae81ff">10</span><span style="color:#999999">;</span>
<span style="color:#999999">}</span><span style="color:#999999">)</span><span style="color:#999999">;</span>
console<span style="color:#999999">.</span><span style="color:#f92672">log</span><span style="color:#999999">(</span>arry2<span style="color:#999999">)</span><span style="color:#999999">;</span><span style="color:#708090">//[ { name: 10 }, { age: 20, name: 10 } ]</span>
</code></span>

如还不了解 iterator 接口或 for…of, 请先阅读ES6文档: Iterator 和 for…of 循环

更多细节请戳: https://github.com/YvetteLau/Blog/blob/master/JS/for.js


4. 如何判断一个变量是不是数组?

  • 使用 Array.isArray 判断,如果返回 true, 说明是数组
  • 使用 instanceof Array 判断,如果返回true, 说明是数组
  • 使用 Object.prototype.toString.call 判断,如果值是 [object Array], 说明是数组
  • 通过 constructor 来判断,如果是数组,那么 arr.constructor === Array. (不准确,因为我们可以指定 obj.constructor = Array)
<span style="color:#1c1f21"><code class="language-javascript"><span style="color:#36bcd6">function</span> <span style="color:#f92672">fn</span><span style="color:#999999">(</span><span style="color:#999999">)</span> <span style="color:#999999">{</span>
    console<span style="color:#999999">.</span><span style="color:#f92672">log</span><span style="color:#999999">(</span>Array<span style="color:#999999">.</span><span style="color:#f92672">isArray</span><span style="color:#999999">(</span>arguments<span style="color:#999999">)</span><span style="color:#999999">)</span><span style="color:#999999">;</span>   <span style="color:#708090">//false; 因为arguments是类数组,但不是数组</span>
    console<span style="color:#999999">.</span><span style="color:#f92672">log</span><span style="color:#999999">(</span>Array<span style="color:#999999">.</span><span style="color:#f92672">isArray</span><span style="color:#999999">(</span><span style="color:#999999">[</span><span style="color:#ae81ff">1</span><span style="color:#999999">,</span><span style="color:#ae81ff">2</span><span style="color:#999999">,</span><span style="color:#ae81ff">3</span><span style="color:#999999">,</span><span style="color:#ae81ff">4</span><span style="color:#999999">]</span><span style="color:#999999">)</span><span style="color:#999999">)</span><span style="color:#999999">;</span>   <span style="color:#708090">//true</span>
    console<span style="color:#999999">.</span><span style="color:#f92672">log</span><span style="color:#999999">(</span>arguments <span style="color:#36bcd6">instanceof</span> Array<span style="color:#999999">)</span><span style="color:#999999">;</span> <span style="color:#708090">//fasle</span>
    console<span style="color:#999999">.</span><span style="color:#f92672">log</span><span style="color:#999999">(</span><span style="color:#999999">[</span><span style="color:#ae81ff">1</span><span style="color:#999999">,</span><span style="color:#ae81ff">2</span><span style="color:#999999">,</span><span style="color:#ae81ff">3</span><span style="color:#999999">,</span><span style="color:#ae81ff">4</span><span style="color:#999999">]</span> <span style="color:#36bcd6">instanceof</span> Array<span style="color:#999999">)</span><span style="color:#999999">;</span> <span style="color:#708090">//true</span>
    console<span style="color:#999999">.</span><span style="color:#f92672">log</span><span style="color:#999999">(</span>Object<span style="color:#999999">.</span>prototype<span style="color:#999999">.</span>toString<span style="color:#999999">.</span><span style="color:#f92672">call</span><span style="color:#999999">(</span>arguments<span style="color:#999999">)</span><span style="color:#999999">)</span><span style="color:#999999">;</span> <span style="color:#708090">//[object Arguments]</span>
    console<span style="color:#999999">.</span><span style="color:#f92672">log</span><span style="color:#999999">(</span>Object<span style="color:#999999">.</span>prototype<span style="color:#999999">.</span>toString<span style="color:#999999">.</span><span style="color:#f92672">call</span><span style="color:#999999">(</span><span style="color:#999999">[</span><span style="color:#ae81ff">1</span><span style="color:#999999">,</span><span style="color:#ae81ff">2</span><span style="color:#999999">,</span><span style="color:#ae81ff">3</span><span style="color:#999999">,</span><span style="color:#ae81ff">4</span><span style="color:#999999">]</span><span style="color:#999999">)</span><span style="color:#999999">)</span><span style="color:#999999">;</span> <span style="color:#708090">//[object Array]</span>
    console<span style="color:#999999">.</span><span style="color:#f92672">log</span><span style="color:#999999">(</span>arguments<span style="color:#999999">.</span>constructor <span style="color:#a67f59">===</span> Array<span style="color:#999999">)</span><span style="color:#999999">;</span> <span style="color:#708090">//false</span>
    arguments<span style="color:#999999">.</span>constructor <span style="color:#a67f59">=</span> Array<span style="color:#999999">;</span>
    console<span style="color:#999999">.</span><span style="color:#f92672">log</span><span style="color:#999999">(</span>arguments<span style="color:#999999">.</span>constructor <span style="color:#a67f59">===</span> Array<span style="color:#999999">)</span><span style="color:#999999">;</span> <span style="color:#708090">//true</span>
    console<span style="color:#999999">.</span><span style="color:#f92672">log</span><span style="color:#999999">(</span>Array<span style="color:#999999">.</span><span style="color:#f92672">isArray</span><span style="color:#999999">(</span>arguments<span style="color:#999999">)</span><span style="color:#999999">)</span><span style="color:#999999">;</span>        <span style="color:#708090">//false</span>
<span style="color:#999999">}</span>
<span style="color:#f92672">fn</span><span style="color:#999999">(</span><span style="color:#ae81ff">1</span><span style="color:#999999">,</span><span style="color:#ae81ff">2</span><span style="color:#999999">,</span><span style="color:#ae81ff">3</span><span style="color:#999999">,</span><span style="color:#ae81ff">4</span><span style="color:#999999">)</span><span style="color:#999999">;</span>
</code></span>

5. 类数组和数组的区别是什么?

类数组:

1)拥有length属性,其它属性(索引)为非负整数(对象中的索引会被当做字符串来处理);

2)不具有数组所具有的方法;

类数组是一个普通对象,而真实的数组是Array类型。

常见的类数组有: 函数的参数 arguments, DOM 对象列表(比如通过 document.querySelectorAll 得到的列表), jQuery 对象 (比如 $(“div”)).

类数组可以转换为数组:

<span style="color:#1c1f21"><code class="language-javascript"><span style="color:#708090">//第一种方法</span>
Array<span style="color:#999999">.</span>prototype<span style="color:#999999">.</span>slice<span style="color:#999999">.</span><span style="color:#f92672">call</span><span style="color:#999999">(</span>arrayLike<span style="color:#999999">,</span> start<span style="color:#999999">)</span><span style="color:#999999">;</span>
<span style="color:#708090">//第二种方法</span>
<span style="color:#999999">[</span><span style="color:#a67f59">...</span>arrayLike<span style="color:#999999">]</span><span style="color:#999999">;</span>
<span style="color:#708090">//第三种方法:</span>
Array<span style="color:#999999">.</span><span style="color:#36bcd6">from</span><span style="color:#999999">(</span>arrayLike<span style="color:#999999">)</span><span style="color:#999999">;</span>
</code></span>

PS: 任何定义了遍历器(Iterator)接口的对象,都可以用扩展运算符转为真正的数组。

Array.from方法用于将两类对象转为真正的数组:类似数组的对象(array-like object)和可遍历(iterable)的对象。


6. == 和 === 有什么区别?

=== 不需要进行类型转换,只有类型相同并且值相等时,才返回 true.

== 如果两者类型不同,首先需要进行类型转换。具体流程如下:

  1. 首先判断两者类型是否相同,如果相等,判断值是否相等.
  2. 如果类型不同,进行类型转换
  3. 判断比较的是否是 null 或者是 undefined, 如果是, 返回 true .
  4. 判断两者类型是否为 string 和 number, 如果是, 将字符串转换成 number
  5. 判断其中一方是否为 boolean, 如果是, 将 boolean 转为 number 再进行判断
  6. 判断其中一方是否为 object 且另一方为 string、number 或者 symbol , 如果是, 将 object 转为原始类型再进行判断
<span style="color:#1c1f21"><code class="language-javascript"><span style="color:#36bcd6">let</span> person1 <span style="color:#a67f59">=</span> <span style="color:#999999">{</span>
    age<span style="color:#999999">:</span> <span style="color:#ae81ff">25</span>
<span style="color:#999999">}</span>
<span style="color:#36bcd6">let</span> person2 <span style="color:#a67f59">=</span> person1<span style="color:#999999">;</span>
person2<span style="color:#999999">.</span>gae <span style="color:#a67f59">=</span> <span style="color:#ae81ff">20</span><span style="color:#999999">;</span>
console<span style="color:#999999">.</span><span style="color:#f92672">log</span><span style="color:#999999">(</span>person1 <span style="color:#a67f59">===</span> person2<span style="color:#999999">)</span><span style="color:#999999">;</span> <span style="color:#708090">//true,注意复杂数据类型,比较的是引用地址</span>
</code></span>

思考: [] == ![]

我们来分析一下: [] == ![] 是true还是false?

  1. 首先,我们需要知道 ! 优先级是高于 == (更多运算符优先级可查看: 运算符优先级)
  2. ![] 引用类型转换成布尔值都是true,因此![]的是false
  3. 根据上面的比较步骤中的第五条,其中一方是 boolean,将 boolean 转为 number 再进行判断,false转换成 number,对应的值是 0.
  4. 根据上面比较步骤中的第六条,有一方是 number,那么将object也转换成Number,空数组转换成数字,对应的值是0.(空数组转换成数字,对应的值是0,如果数组中只有一个数字,那么转成number就是这个数字,其它情况,均为NaN)
  5. 0 == 0; 为true

7. ES6中的class和ES5的类有什么区别?

  1. ES6 class 内部所有定义的方法都是不可枚举的;
  2. ES6 class 必须使用 new 调用;
  3. ES6 class 不存在变量提升;
  4. ES6 class 默认即是严格模式;
  5. ES6 class 子类必须在父类的构造函数中调用super(),这样才有this对象;ES5中类继承的关系是相反的,先有子类的this,然后用父类的方法应用在this上。

8. 数组的哪些API会改变原数组?

修改原数组的API有:

splice/reverse/fill/copyWithin/sort/push/pop/unshift/shift

不修改原数组的API有:

slice/map/forEach/every/filter/reduce/entries/find

注: 数组的每一项是简单数据类型,且未直接操作数组的情况下(稍后会对此题重新作答)。


9. let、const 以及 var 的区别是什么?

  • let 和 const 定义的变量不会出现变量提升,而 var 定义的变量会提升。
  • let 和 const 是JS中的块级作用域
  • let 和 const 不允许重复声明(会抛出错误)
  • let 和 const 定义的变量在定义语句之前,如果使用会抛出错误(形成了暂时性死区),而 var 不会。
  • const 声明一个只读的常量。一旦声明,常量的值就不能改变(如果声明是一个对象,那么不能改变的是对象的引用地址)

10. 在JS中什么是变量提升?什么是暂时性死区?

变量提升就是变量在声明之前就可以使用,值为undefined。

在代码块内,使用 let/const 命令声明变量之前,该变量都是不可用的(会抛出错误)。这在语法上,称为“暂时性死区”。暂时性死区也意味着 typeof 不再是一个百分百安全的操作。

<span style="color:#1c1f21"><code class="language-javascript"><span style="color:#36bcd6">typeof</span> x<span style="color:#999999">;</span> <span style="color:#708090">// ReferenceError(暂时性死区,抛错)</span>
<span style="color:#36bcd6">let</span> x<span style="color:#999999">;</span>
</code></span>
<span style="color:#1c1f21"><code class="language-javascript"><span style="color:#36bcd6">typeof</span> y<span style="color:#999999">;</span> <span style="color:#708090">// 值是undefined,不会报错</span>
</code></span>

暂时性死区的本质就是,只要一进入当前作用域,所要使用的变量就已经存在了,但是不可获取,只有等到声明变量的那一行代码出现,才可以获取和使用该变量。


11. 如何正确的判断this? 箭头函数的this是什么?

this的绑定规则有四种:默认绑定,隐式绑定,显式绑定,new绑定.

  1. 函数是否在 new 中调用(new绑定),如果是,那么 this 绑定的是新创建的对象【前提是构造函数中没有返回对象或者是function,否则this指向返回的对象/function】。
  2. 函数是否通过 call,apply 调用,或者使用了 bind (即硬绑定),如果是,那么this绑定的就是指定的对象。
  3. 函数是否在某个上下文对象中调用(隐式绑定),如果是的话,this 绑定的是那个上下文对象。一般是 obj.foo()
  4. 如果以上都不是,那么使用默认绑定。如果在严格模式下,则绑定到 undefined,否则绑定到全局对象。
  5. 如果把 null 或者 undefined 作为 this 的绑定对象传入 call、apply 或者 bind, 这些值在调用时会被忽略,实际应用的是默认绑定规则。
  6. 箭头函数没有自己的 this, 它的this继承于上一层代码块的this。

测试下是否已经成功Get了此知识点(浏览器执行环境):

<span style="color:#1c1f21"><code class="language-javascript"><span style="color:#36bcd6">var</span> number <span style="color:#a67f59">=</span> <span style="color:#ae81ff">5</span><span style="color:#999999">;</span>
<span style="color:#36bcd6">var</span> obj <span style="color:#a67f59">=</span> <span style="color:#999999">{</span>
    number<span style="color:#999999">:</span> <span style="color:#ae81ff">3</span><span style="color:#999999">,</span>
    fn1<span style="color:#999999">:</span> <span style="color:#999999">(</span><span style="color:#36bcd6">function</span> <span style="color:#999999">(</span><span style="color:#999999">)</span> <span style="color:#999999">{</span>
        <span style="color:#36bcd6">var</span> number<span style="color:#999999">;</span>
        <span style="color:#36bcd6">this</span><span style="color:#999999">.</span>number <span style="color:#a67f59">*=</span> <span style="color:#ae81ff">2</span><span style="color:#999999">;</span>
        number <span style="color:#a67f59">=</span> number <span style="color:#a67f59">*</span> <span style="color:#ae81ff">2</span><span style="color:#999999">;</span>
        number <span style="color:#a67f59">=</span> <span style="color:#ae81ff">3</span><span style="color:#999999">;</span>
        <span style="color:#36bcd6">return</span> <span style="color:#36bcd6">function</span> <span style="color:#999999">(</span><span style="color:#999999">)</span> <span style="color:#999999">{</span>
            <span style="color:#36bcd6">var</span> num <span style="color:#a67f59">=</span> <span style="color:#36bcd6">this</span><span style="color:#999999">.</span>number<span style="color:#999999">;</span>
            <span style="color:#36bcd6">this</span><span style="color:#999999">.</span>number <span style="color:#a67f59">*=</span> <span style="color:#ae81ff">2</span><span style="color:#999999">;</span>
            console<span style="color:#999999">.</span><span style="color:#f92672">log</span><span style="color:#999999">(</span>num<span style="color:#999999">)</span><span style="color:#999999">;</span>
            number <span style="color:#a67f59">*=</span> <span style="color:#ae81ff">3</span><span style="color:#999999">;</span>
            console<span style="color:#999999">.</span><span style="color:#f92672">log</span><span style="color:#999999">(</span>number<span style="color:#999999">)</span><span style="color:#999999">;</span>
        <span style="color:#999999">}</span>
    <span style="color:#999999">}</span><span style="color:#999999">)</span><span style="color:#999999">(</span><span style="color:#999999">)</span>
<span style="color:#999999">}</span>
<span style="color:#36bcd6">var</span> fn1 <span style="color:#a67f59">=</span> obj<span style="color:#999999">.</span>fn1<span style="color:#999999">;</span>
fn1<span style="color:#999999">.</span><span style="color:#f92672">call</span><span style="color:#999999">(</span><span style="color:#36bcd6">null</span><span style="color:#999999">)</span><span style="color:#999999">;</span>
obj<span style="color:#999999">.</span><span style="color:#f92672">fn1</span><span style="color:#999999">(</span><span style="color:#999999">)</span><span style="color:#999999">;</span>
console<span style="color:#999999">.</span><span style="color:#f92672">log</span><span style="color:#999999">(</span>window<span style="color:#999999">.</span>number<span style="color:#999999">)</span><span style="color:#999999">;</span>
</code></span>

如果this的知识点,您还不太懂,请戳: 嗨,你真的懂this吗?


12. 词法作用域和this的区别。

  • 词法作用域是由你在写代码时将变量和块作用域写在哪里来决定的
  • this 是在调用时被绑定的,this 指向什么,完全取决于函数的调用位置(关于this的指向问题,本文已经有说明)

13. 谈谈你对JS执行上下文栈和作用域链的理解。

执行上下文就是当前 JavaScript 代码被解析和执行时所在环境, JS执行上下文栈可以认为是一个存储函数调用的栈结构,遵循先进后出的原则。

  • JavaScript执行在单线程上,所有的代码都是排队执行。
  • 一开始浏览器执行全局的代码时,首先创建全局的执行上下文,压入执行栈的顶部。
  • 每当进入一个函数的执行就会创建函数的执行上下文,并且把它压入执行栈的顶部。当前函数执行-完成后,当前函数的执行上下文出栈,并等待垃圾回收。
  • 浏览器的JS执行引擎总是访问栈顶的执行上下文。
  • 全局上下文只有唯一的一个,它在浏览器关闭时出栈。

作用域链: 无论是 LHS 还是 RHS 查询,都会在当前的作用域开始查找,如果没有找到,就会向上级作用域继续查找目标标识符,每次上升一个作用域,一直到全局作用域为止。


题难不难?不难!继续挑战一下!难!知道难,就更要继续了!

14. 什么是闭包?闭包的作用是什么?闭包有哪些使用场景?

闭包是指有权访问另一个函数作用域中的变量的函数,创建闭包最常用的方式就是在一个函数内部创建另一个函数。

闭包的作用有:

  1. 封装私有变量
  2. 模仿块级作用域(ES5中没有块级作用域)
  3. 实现JS的模块

15. call、apply有什么区别?call,aplly和bind的内部是如何实现的?

call 和 apply 的功能相同,区别在于传参的方式不一样:

  • fn.call(obj, arg1, arg2, …),调用一个函数, 具有一个指定的this值和分别地提供的参数(参数的列表)。

  • fn.apply(obj, [argsArray]),调用一个函数,具有一个指定的this值,以及作为一个数组(或类数组对象)提供的参数。

call核心:

  • 将函数设为传入参数的属性
  • 指定this到函数并传入给定参数执行函数
  • 如果不传入参数或者参数为null,默认指向为 window / global
  • 删除参数上的函数
<span style="color:#1c1f21"><code class="language-javascript">Function<span style="color:#999999">.</span>prototype<span style="color:#999999">.</span><span style="color:#f92672">call</span> <span style="color:#a67f59">=</span> <span style="color:#36bcd6">function</span> <span style="color:#999999">(</span>context<span style="color:#999999">)</span> <span style="color:#999999">{</span>
    <span style="color:#708090">/** 如果第一个参数传入的是 null 或者是 undefined, 那么指向this指向 window/global */</span>
    <span style="color:#708090">/** 如果第一个参数传入的不是null或者是undefined, 那么必须是一个对象 */</span>
    <span style="color:#36bcd6">if</span> <span style="color:#999999">(</span><span style="color:#a67f59">!</span>context<span style="color:#999999">)</span> <span style="color:#999999">{</span>
        <span style="color:#708090">//context为null或者是undefined</span>
        context <span style="color:#a67f59">=</span> <span style="color:#36bcd6">typeof</span> window <span style="color:#a67f59">===</span> <span style="color:#78ab12">'undefined'</span> <span style="color:#a67f59">?</span> global <span style="color:#999999">:</span> window<span style="color:#999999">;</span>
    <span style="color:#999999">}</span>
    context<span style="color:#999999">.</span>fn <span style="color:#a67f59">=</span> <span style="color:#36bcd6">this</span><span style="color:#999999">;</span> <span style="color:#708090">//this指向的是当前的函数(Function的实例)</span>
    <span style="color:#36bcd6">let</span> rest <span style="color:#a67f59">=</span> <span style="color:#999999">[</span><span style="color:#a67f59">...</span>arguments<span style="color:#999999">]</span><span style="color:#999999">.</span><span style="color:#f92672">slice</span><span style="color:#999999">(</span><span style="color:#ae81ff">1</span><span style="color:#999999">)</span><span style="color:#999999">;</span><span style="color:#708090">//获取除了this指向对象以外的参数, 空数组slice后返回的仍然是空数组</span>
    <span style="color:#36bcd6">let</span> result <span style="color:#a67f59">=</span> context<span style="color:#999999">.</span><span style="color:#f92672">fn</span><span style="color:#999999">(</span><span style="color:#a67f59">...</span>rest<span style="color:#999999">)</span><span style="color:#999999">;</span> <span style="color:#708090">//隐式绑定,当前函数的this指向了context.</span>
    <span style="color:#36bcd6">delete</span> context<span style="color:#999999">.</span>fn<span style="color:#999999">;</span>
    <span style="color:#36bcd6">return</span> result<span style="color:#999999">;</span>
<span style="color:#999999">}</span>

<span style="color:#708090">//测试代码</span>
<span style="color:#36bcd6">var</span> foo <span style="color:#a67f59">=</span> <span style="color:#999999">{</span>
    name<span style="color:#999999">:</span> <span style="color:#78ab12">'Selina'</span>
<span style="color:#999999">}</span>
<span style="color:#36bcd6">var</span> name <span style="color:#a67f59">=</span> <span style="color:#78ab12">'Chirs'</span><span style="color:#999999">;</span>
<span style="color:#36bcd6">function</span> <span style="color:#f92672">bar</span><span style="color:#999999">(</span>job<span style="color:#999999">,</span> age<span style="color:#999999">)</span> <span style="color:#999999">{</span>
    console<span style="color:#999999">.</span><span style="color:#f92672">log</span><span style="color:#999999">(</span><span style="color:#36bcd6">this</span><span style="color:#999999">.</span>name<span style="color:#999999">)</span><span style="color:#999999">;</span>
    console<span style="color:#999999">.</span><span style="color:#f92672">log</span><span style="color:#999999">(</span>job<span style="color:#999999">,</span> age<span style="color:#999999">)</span><span style="color:#999999">;</span>
<span style="color:#999999">}</span>
bar<span style="color:#999999">.</span><span style="color:#f92672">call</span><span style="color:#999999">(</span>foo<span style="color:#999999">,</span> <span style="color:#78ab12">'programmer'</span><span style="color:#999999">,</span> <span style="color:#ae81ff">20</span><span style="color:#999999">)</span><span style="color:#999999">;</span>
<span style="color:#708090">// Selina programmer 20</span>
bar<span style="color:#999999">.</span><span style="color:#f92672">call</span><span style="color:#999999">(</span><span style="color:#36bcd6">null</span><span style="color:#999999">,</span> <span style="color:#78ab12">'teacher'</span><span style="color:#999999">,</span> <span style="color:#ae81ff">25</span><span style="color:#999999">)</span><span style="color:#999999">;</span>
<span style="color:#708090">// 浏览器环境: Chirs teacher 25; node 环境: undefined teacher 25</span>

</code></span>

apply:

apply的实现和call很类似,但是需要注意他们的参数是不一样的,apply的第二个参数是数组或类数组.

<span style="color:#1c1f21"><code class="language-javascript">Function<span style="color:#999999">.</span>prototype<span style="color:#999999">.</span><span style="color:#f92672">apply</span> <span style="color:#a67f59">=</span> <span style="color:#36bcd6">function</span> <span style="color:#999999">(</span>context<span style="color:#999999">,</span> rest<span style="color:#999999">)</span> <span style="color:#999999">{</span>
    <span style="color:#36bcd6">if</span> <span style="color:#999999">(</span><span style="color:#a67f59">!</span>context<span style="color:#999999">)</span> <span style="color:#999999">{</span>
        <span style="color:#708090">//context为null或者是undefined时,设置默认值</span>
        context <span style="color:#a67f59">=</span> <span style="color:#36bcd6">typeof</span> window <span style="color:#a67f59">===</span> <span style="color:#78ab12">'undefined'</span> <span style="color:#a67f59">?</span> global <span style="color:#999999">:</span> window<span style="color:#999999">;</span>
    <span style="color:#999999">}</span>
    context<span style="color:#999999">.</span>fn <span style="color:#a67f59">=</span> <span style="color:#36bcd6">this</span><span style="color:#999999">;</span>
    <span style="color:#36bcd6">let</span> result<span style="color:#999999">;</span>
    <span style="color:#36bcd6">if</span><span style="color:#999999">(</span>rest <span style="color:#a67f59">===</span> undefined <span style="color:#a67f59">||</span> rest <span style="color:#a67f59">===</span> <span style="color:#36bcd6">null</span><span style="color:#999999">)</span> <span style="color:#999999">{</span>
        <span style="color:#708090">//undefined 或者 是 null 不是 Iterator 对象,不能被 ...</span>
        result <span style="color:#a67f59">=</span> context<span style="color:#999999">.</span><span style="color:#f92672">fn</span><span style="color:#999999">(</span>rest<span style="color:#999999">)</span><span style="color:#999999">;</span>
    <span style="color:#999999">}</span><span style="color:#36bcd6">else</span> <span style="color:#36bcd6">if</span><span style="color:#999999">(</span><span style="color:#36bcd6">typeof</span> rest <span style="color:#a67f59">===</span> <span style="color:#78ab12">'object'</span><span style="color:#999999">)</span> <span style="color:#999999">{</span>
        result <span style="color:#a67f59">=</span> context<span style="color:#999999">.</span><span style="color:#f92672">fn</span><span style="color:#999999">(</span><span style="color:#a67f59">...</span>rest<span style="color:#999999">)</span><span style="color:#999999">;</span>
    <span style="color:#999999">}</span>
    <span style="color:#36bcd6">delete</span> context<span style="color:#999999">.</span>fn<span style="color:#999999">;</span>
    <span style="color:#36bcd6">return</span> result<span style="color:#999999">;</span>
<span style="color:#999999">}</span>
<span style="color:#36bcd6">var</span> foo <span style="color:#a67f59">=</span> <span style="color:#999999">{</span>
    name<span style="color:#999999">:</span> <span style="color:#78ab12">'Selina'</span>
<span style="color:#999999">}</span>
<span style="color:#36bcd6">var</span> name <span style="color:#a67f59">=</span> <span style="color:#78ab12">'Chirs'</span><span style="color:#999999">;</span>
<span style="color:#36bcd6">function</span> <span style="color:#f92672">bar</span><span style="color:#999999">(</span>job<span style="color:#999999">,</span> age<span style="color:#999999">)</span> <span style="color:#999999">{</span>
    console<span style="color:#999999">.</span><span style="color:#f92672">log</span><span style="color:#999999">(</span><span style="color:#36bcd6">this</span><span style="color:#999999">.</span>name<span style="color:#999999">)</span><span style="color:#999999">;</span>
    console<span style="color:#999999">.</span><span style="color:#f92672">log</span><span style="color:#999999">(</span>job<span style="color:#999999">,</span> age<span style="color:#999999">)</span><span style="color:#999999">;</span>
<span style="color:#999999">}</span>
bar<span style="color:#999999">.</span><span style="color:#f92672">apply</span><span style="color:#999999">(</span>foo<span style="color:#999999">,</span> <span style="color:#999999">[</span><span style="color:#78ab12">'programmer'</span><span style="color:#999999">,</span> <span style="color:#ae81ff">20</span><span style="color:#999999">]</span><span style="color:#999999">)</span><span style="color:#999999">;</span>
<span style="color:#708090">// Selina programmer 20</span>
bar<span style="color:#999999">.</span><span style="color:#f92672">apply</span><span style="color:#999999">(</span><span style="color:#36bcd6">null</span><span style="color:#999999">,</span> <span style="color:#999999">[</span><span style="color:#78ab12">'teacher'</span><span style="color:#999999">,</span> <span style="color:#ae81ff">25</span><span style="color:#999999">]</span><span style="color:#999999">)</span><span style="color:#999999">;</span>
<span style="color:#708090">// 浏览器环境: Chirs programmer 20; node 环境: undefined teacher 25</span>
</code></span>

bind

bind 和 call/apply 有一个很重要的区别,一个函数被 call/apply 的时候,会直接调用,但是 bind 会创建一个新函数。当这个新函数被调用时,bind() 的第一个参数将作为它运行时的 this,之后的一序列参数将会在传递的实参前传入作为它的参数。

<span style="color:#1c1f21"><code class="language-javascript">Function<span style="color:#999999">.</span>prototype<span style="color:#999999">.</span><span style="color:#f92672">bind</span> <span style="color:#a67f59">=</span> <span style="color:#36bcd6">function</span><span style="color:#999999">(</span>context<span style="color:#999999">)</span> <span style="color:#999999">{</span>
    <span style="color:#36bcd6">if</span><span style="color:#999999">(</span><span style="color:#36bcd6">typeof</span> <span style="color:#36bcd6">this</span> <span style="color:#a67f59">!==</span> <span style="color:#78ab12">"function"</span><span style="color:#999999">)</span><span style="color:#999999">{</span>
       <span style="color:#36bcd6">throw</span> <span style="color:#36bcd6">new</span> TypeError<span style="color:#999999">(</span><span style="color:#78ab12">"not a function"</span><span style="color:#999999">)</span><span style="color:#999999">;</span>
    <span style="color:#999999">}</span>
    <span style="color:#36bcd6">let</span> self <span style="color:#a67f59">=</span> <span style="color:#36bcd6">this</span><span style="color:#999999">;</span>
    <span style="color:#36bcd6">let</span> args <span style="color:#a67f59">=</span> <span style="color:#999999">[</span><span style="color:#a67f59">...</span>arguments<span style="color:#999999">]</span><span style="color:#999999">.</span><span style="color:#f92672">slice</span><span style="color:#999999">(</span><span style="color:#ae81ff">1</span><span style="color:#999999">)</span><span style="color:#999999">;</span>
    <span style="color:#36bcd6">function</span> <span style="color:#f92672">Fn</span><span style="color:#999999">(</span><span style="color:#999999">)</span> <span style="color:#999999">{</span><span style="color:#999999">}</span><span style="color:#999999">;</span>
    Fn<span style="color:#999999">.</span>prototype <span style="color:#a67f59">=</span> <span style="color:#36bcd6">this</span><span style="color:#999999">.</span>prototype<span style="color:#999999">;</span>
    <span style="color:#36bcd6">let</span> <span style="color:#f92672">bound</span> <span style="color:#a67f59">=</span> <span style="color:#36bcd6">function</span><span style="color:#999999">(</span><span style="color:#999999">)</span> <span style="color:#999999">{</span>
        <span style="color:#36bcd6">let</span> res <span style="color:#a67f59">=</span> <span style="color:#999999">[</span><span style="color:#a67f59">...</span>args<span style="color:#999999">,</span> <span style="color:#a67f59">...</span>arguments<span style="color:#999999">]</span><span style="color:#999999">;</span> <span style="color:#708090">//bind传递的参数和函数调用时传递的参数拼接</span>
        context <span style="color:#a67f59">=</span> <span style="color:#36bcd6">this</span> <span style="color:#36bcd6">instanceof</span> Fn <span style="color:#a67f59">?</span> <span style="color:#36bcd6">this</span> <span style="color:#999999">:</span> context <span style="color:#a67f59">||</span> <span style="color:#36bcd6">this</span><span style="color:#999999">;</span>
        <span style="color:#36bcd6">return</span> self<span style="color:#999999">.</span><span style="color:#f92672">apply</span><span style="color:#999999">(</span>context<span style="color:#999999">,</span> res<span style="color:#999999">)</span><span style="color:#999999">;</span>
    <span style="color:#999999">}</span>
    <span style="color:#708090">//原型链</span>
    bound<span style="color:#999999">.</span>prototype <span style="color:#a67f59">=</span> <span style="color:#36bcd6">new</span> Fn<span style="color:#999999">(</span><span style="color:#999999">)</span><span style="color:#999999">;</span>
    <span style="color:#36bcd6">return</span> bound<span style="color:#999999">;</span>
<span style="color:#999999">}</span>

<span style="color:#36bcd6">var</span> name <span style="color:#a67f59">=</span> <span style="color:#78ab12">'Jack'</span><span style="color:#999999">;</span>
<span style="color:#36bcd6">function</span> <span style="color:#f92672">person</span><span style="color:#999999">(</span>age<span style="color:#999999">,</span> job<span style="color:#999999">,</span> gender<span style="color:#999999">)</span><span style="color:#999999">{</span>
    console<span style="color:#999999">.</span><span style="color:#f92672">log</span><span style="color:#999999">(</span><span style="color:#36bcd6">this</span><span style="color:#999999">.</span>name <span style="color:#999999">,</span> age<span style="color:#999999">,</span> job<span style="color:#999999">,</span> gender<span style="color:#999999">)</span><span style="color:#999999">;</span>
<span style="color:#999999">}</span>
<span style="color:#36bcd6">var</span> Yve <span style="color:#a67f59">=</span> <span style="color:#999999">{</span>name <span style="color:#999999">:</span> <span style="color:#78ab12">'Yvette'</span><span style="color:#999999">}</span><span style="color:#999999">;</span>
<span style="color:#36bcd6">let</span> result <span style="color:#a67f59">=</span> person<span style="color:#999999">.</span><span style="color:#f92672">bind</span><span style="color:#999999">(</span>Yve<span style="color:#999999">,</span> <span style="color:#ae81ff">22</span><span style="color:#999999">,</span> <span style="color:#78ab12">'enginner'</span><span style="color:#999999">)</span><span style="color:#999999">(</span><span style="color:#78ab12">'female'</span><span style="color:#999999">)</span><span style="color:#999999">;</span>	
</code></span>

16. new的原理是什么?通过new的方式创建对象和通过字面量创建有什么区别?

new:

  1. 创建一个新对象。
  2. 这个新对象会被执行[[原型]]连接。
  3. 属性和方法被加入到 this 引用的对象中。并执行了构造函数中的方法.
  4. 如果函数没有返回其他对象,那么this指向这个新对象,否则this指向构造函数中返回的对象。
<span style="color:#1c1f21"><code class="language-javascript"><span style="color:#36bcd6">function</span> <span style="color:#36bcd6">new</span><span style="color:#999999">(</span>func<span style="color:#999999">)</span> <span style="color:#999999">{</span>
    <span style="color:#36bcd6">let</span> target <span style="color:#a67f59">=</span> <span style="color:#999999">{</span><span style="color:#999999">}</span><span style="color:#999999">;</span>
    target<span style="color:#999999">.</span>__proto__ <span style="color:#a67f59">=</span> func<span style="color:#999999">.</span>prototype<span style="color:#999999">;</span>
    <span style="color:#36bcd6">let</span> res <span style="color:#a67f59">=</span> func<span style="color:#999999">.</span><span style="color:#f92672">call</span><span style="color:#999999">(</span>target<span style="color:#999999">)</span><span style="color:#999999">;</span>
    <span style="color:#36bcd6">if</span> <span style="color:#999999">(</span><span style="color:#36bcd6">typeof</span><span style="color:#999999">(</span>res<span style="color:#999999">)</span> <span style="color:#a67f59">==</span> <span style="color:#78ab12">"object"</span> <span style="color:#a67f59">||</span> <span style="color:#36bcd6">typeof</span><span style="color:#999999">(</span>res<span style="color:#999999">)</span> <span style="color:#a67f59">==</span> <span style="color:#78ab12">"function"</span><span style="color:#999999">)</span> <span style="color:#999999">{</span>
    	<span style="color:#36bcd6">return</span> res<span style="color:#999999">;</span>
    <span style="color:#999999">}</span>
    <span style="color:#36bcd6">return</span> target<span style="color:#999999">;</span>
<span style="color:#999999">}</span>
</code></span>

字面量创建对象,不会调用 Object构造函数, 简洁且性能更好;

new Object() 方式创建对象本质上是方法调用,涉及到在proto链中遍历该方法,当找到该方法后,又会生产方法调用必须的 堆栈信息,方法调用结束后,还要释放该堆栈,性能不如字面量的方式。

通过对象字面量定义对象时,不会调用Object构造函数。


17. 谈谈你对原型的理解?

在 JavaScript 中,每当定义一个对象(函数也是对象)时候,对象中都会包含一些预定义的属性。其中每个函数对象都有一个prototype 属性,这个属性指向函数的原型对象。使用原型对象的好处是所有对象实例共享它所包含的属性和方法。


18. 什么是原型链?【原型链解决的是什么问题?】

原型链解决的主要是继承问题。

每个对象拥有一个原型对象,通过 proto (读音: dunder proto) 指针指向其原型对象,并从中继承方法和属性,同时原型对象也可能拥有原型,这样一层一层,最终指向 null(Object.proptotype.__proto__ 指向的是null)。这种关系被称为原型链 (prototype chain),通过原型链一个对象可以拥有定义在其他对象中的属性和方法。

构造函数 Parent、Parent.prototype 和 实例 p 的关系如下:(p.__proto__ === Parent.prototype)


19. prototype 和 __proto__ 区别是什么?

prototype是构造函数的属性。

__proto__ 是每个实例都有的属性,可以访问 [[prototype]] 属性。

实例的__proto__ 与其构造函数的prototype指向的是同一个对象。

<span style="color:#1c1f21"><code class="language-javascript"><span style="color:#36bcd6">function</span> <span style="color:#f92672">Student</span><span style="color:#999999">(</span>name<span style="color:#999999">)</span> <span style="color:#999999">{</span>
    <span style="color:#36bcd6">this</span><span style="color:#999999">.</span>name <span style="color:#a67f59">=</span> name<span style="color:#999999">;</span>
<span style="color:#999999">}</span>
Student<span style="color:#999999">.</span>prototype<span style="color:#999999">.</span><span style="color:#f92672">setAge</span> <span style="color:#a67f59">=</span> <span style="color:#36bcd6">function</span><span style="color:#999999">(</span><span style="color:#999999">)</span><span style="color:#999999">{</span>
    <span style="color:#36bcd6">this</span><span style="color:#999999">.</span>age<span style="color:#a67f59">=</span><span style="color:#ae81ff">20</span><span style="color:#999999">;</span>
<span style="color:#999999">}</span>
<span style="color:#36bcd6">let</span> Jack <span style="color:#a67f59">=</span> <span style="color:#36bcd6">new</span> Student<span style="color:#999999">(</span><span style="color:#78ab12">'jack'</span><span style="color:#999999">)</span><span style="color:#999999">;</span>
console<span style="color:#999999">.</span><span style="color:#f92672">log</span><span style="color:#999999">(</span>Jack<span style="color:#999999">.</span>__proto__<span style="color:#999999">)</span><span style="color:#999999">;</span>
<span style="color:#708090">//console.log(Object.getPrototypeOf(Jack));;</span>
console<span style="color:#999999">.</span><span style="color:#f92672">log</span><span style="color:#999999">(</span>Student<span style="color:#999999">.</span>prototype<span style="color:#999999">)</span><span style="color:#999999">;</span>
console<span style="color:#999999">.</span><span style="color:#f92672">log</span><span style="color:#999999">(</span>Jack<span style="color:#999999">.</span>__proto__ <span style="color:#a67f59">===</span> Student<span style="color:#999999">.</span>prototype<span style="color:#999999">)</span><span style="color:#999999">;</span><span style="color:#708090">//true</span>
</code></span>

20. 使用ES5实现一个继承?

组合继承(最常用的继承方式)

<span style="color:#1c1f21"><code class="language-javascript"><span style="color:#36bcd6">function</span> <span style="color:#f92672">SuperType</span><span style="color:#999999">(</span>name<span style="color:#999999">)</span> <span style="color:#999999">{</span>
    <span style="color:#36bcd6">this</span><span style="color:#999999">.</span>name <span style="color:#a67f59">=</span> name<span style="color:#999999">;</span>
    <span style="color:#36bcd6">this</span><span style="color:#999999">.</span>colors <span style="color:#a67f59">=</span> <span style="color:#999999">[</span><span style="color:#78ab12">'red'</span><span style="color:#999999">,</span> <span style="color:#78ab12">'blue'</span><span style="color:#999999">,</span> <span style="color:#78ab12">'green'</span><span style="color:#999999">]</span><span style="color:#999999">;</span>
<span style="color:#999999">}</span>
SuperType<span style="color:#999999">.</span>prototype<span style="color:#999999">.</span><span style="color:#f92672">sayName</span> <span style="color:#a67f59">=</span> <span style="color:#36bcd6">function</span><span style="color:#999999">(</span><span style="color:#999999">)</span> <span style="color:#999999">{</span>
    console<span style="color:#999999">.</span><span style="color:#f92672">log</span><span style="color:#999999">(</span><span style="color:#36bcd6">this</span><span style="color:#999999">.</span>name<span style="color:#999999">)</span><span style="color:#999999">;</span>
<span style="color:#999999">}</span>

<span style="color:#36bcd6">function</span> <span style="color:#f92672">SubType</span><span style="color:#999999">(</span>name<span style="color:#999999">,</span> age<span style="color:#999999">)</span> <span style="color:#999999">{</span>
    SuperType<span style="color:#999999">.</span><span style="color:#f92672">call</span><span style="color:#999999">(</span><span style="color:#36bcd6">this</span><span style="color:#999999">,</span> name<span style="color:#999999">)</span><span style="color:#999999">;</span>
    <span style="color:#36bcd6">this</span><span style="color:#999999">.</span>age <span style="color:#a67f59">=</span> age<span style="color:#999999">;</span>
<span style="color:#999999">}</span>
SubType<span style="color:#999999">.</span>prototype <span style="color:#a67f59">=</span> <span style="color:#36bcd6">new</span> SuperType<span style="color:#999999">(</span><span style="color:#999999">)</span><span style="color:#999999">;</span>
SubType<span style="color:#999999">.</span>prototype<span style="color:#999999">.</span>constructor <span style="color:#a67f59">=</span> SubType<span style="color:#999999">;</span>

SubType<span style="color:#999999">.</span>prototype<span style="color:#999999">.</span><span style="color:#f92672">sayAge</span> <span style="color:#a67f59">=</span> <span style="color:#36bcd6">function</span><span style="color:#999999">(</span><span style="color:#999999">)</span> <span style="color:#999999">{</span>
    console<span style="color:#999999">.</span><span style="color:#f92672">log</span><span style="color:#999999">(</span><span style="color:#36bcd6">this</span><span style="color:#999999">.</span>age<span style="color:#999999">)</span><span style="color:#999999">;</span>
<span style="color:#999999">}</span>
</code></span>

其它继承方式实现,可以参考《JavaScript高级程序设计》


21. 什么是深拷贝?深拷贝和浅拷贝有什么区别?

浅拷贝是指只复制第一层对象,但是当对象的属性是引用类型时,实质复制的是其引用,当引用指向的值改变时也会跟着变化。

深拷贝复制变量值,对于非基本类型的变量,则递归至基本类型变量后,再复制。深拷贝后的对象与原来的对象是完全隔离的,互不影响,对一个对象的修改并不会影响另一个对象。

实现一个深拷贝:

<span style="color:#1c1f21"><code class="language-javascript"><span style="color:#36bcd6">function</span> <span style="color:#f92672">deepClone</span><span style="color:#999999">(</span>obj<span style="color:#999999">)</span> <span style="color:#999999">{</span> <span style="color:#708090">//递归拷贝</span>
    <span style="color:#36bcd6">if</span><span style="color:#999999">(</span>obj <span style="color:#a67f59">===</span> <span style="color:#36bcd6">null</span><span style="color:#999999">)</span> <span style="color:#36bcd6">return</span> <span style="color:#36bcd6">null</span><span style="color:#999999">;</span> <span style="color:#708090">//null 的情况</span>
    <span style="color:#36bcd6">if</span><span style="color:#999999">(</span>obj <span style="color:#36bcd6">instanceof</span> RegExp<span style="color:#999999">)</span> <span style="color:#36bcd6">return</span> <span style="color:#36bcd6">new</span> RegExp<span style="color:#999999">(</span>obj<span style="color:#999999">)</span><span style="color:#999999">;</span>
    <span style="color:#36bcd6">if</span><span style="color:#999999">(</span>obj <span style="color:#36bcd6">instanceof</span> Date<span style="color:#999999">)</span> <span style="color:#36bcd6">return</span> <span style="color:#36bcd6">new</span> Date<span style="color:#999999">(</span>obj<span style="color:#999999">)</span><span style="color:#999999">;</span>
    <span style="color:#36bcd6">if</span><span style="color:#999999">(</span><span style="color:#36bcd6">typeof</span> obj <span style="color:#a67f59">!==</span> <span style="color:#78ab12">'object'</span><span style="color:#999999">)</span> <span style="color:#999999">{</span>
        <span style="color:#708090">//如果不是复杂数据类型,直接返回</span>
        <span style="color:#36bcd6">return</span> obj<span style="color:#999999">;</span>
    <span style="color:#999999">}</span>
    <span style="color:#708090">/**
     * 如果obj是数组,那么 obj.constructor 是 [Function: Array]
     * 如果obj是对象,那么 obj.constructor 是 [Function: Object]
     */</span>
    <span style="color:#36bcd6">let</span> t <span style="color:#a67f59">=</span> <span style="color:#36bcd6">new</span> obj<span style="color:#999999">.</span>constructor<span style="color:#999999">(</span><span style="color:#999999">)</span><span style="color:#999999">;</span>
    <span style="color:#36bcd6">for</span><span style="color:#999999">(</span><span style="color:#36bcd6">let</span> key <span style="color:#36bcd6">in</span> obj<span style="color:#999999">)</span> <span style="color:#999999">{</span>
        <span style="color:#708090">//如果 obj[key] 是复杂数据类型,递归</span>
        t<span style="color:#999999">[</span>key<span style="color:#999999">]</span> <span style="color:#a67f59">=</span> <span style="color:#f92672">deepClone</span><span style="color:#999999">(</span>obj<span style="color:#999999">[</span>key<span style="color:#999999">]</span><span style="color:#999999">)</span><span style="color:#999999">;</span>
    <span style="color:#999999">}</span>
    <span style="color:#36bcd6">return</span> t<span style="color:#999999">;</span>
<span style="color:#999999">}</span>
</code></span>

看不下去了?别人的送分题会成为你的送命题

22. 防抖和节流的区别是什么?防抖和节流的实现。

防抖和节流的作用都是防止函数多次调用。区别在于,假设一个用户一直触发这个函数,且每次触发函数的间隔小于设置的时间,防抖的情况下只会调用一次,而节流的情况会每隔一定时间调用一次函数。

防抖(debounce): n秒内函数只会执行一次,如果n秒内高频事件再次被触发,则重新计算时间

<span style="color:#1c1f21"><code class="language-javascript"><span style="color:#36bcd6">function</span> <span style="color:#f92672">debounce</span><span style="color:#999999">(</span>func<span style="color:#999999">,</span> wait<span style="color:#999999">,</span> immediate<span style="color:#a67f59">=</span><span style="color:#ae81ff">true</span><span style="color:#999999">)</span> <span style="color:#999999">{</span>
    <span style="color:#36bcd6">let</span> timeout<span style="color:#999999">,</span> context<span style="color:#999999">,</span> args<span style="color:#999999">;</span>
        <span style="color:#708090">// 延迟执行函数</span>
        <span style="color:#36bcd6">const</span> <span style="color:#f92672">later</span> <span style="color:#a67f59">=</span> <span style="color:#999999">(</span><span style="color:#999999">)</span> <span style="color:#a67f59">=></span> <span style="color:#f92672">setTimeout</span><span style="color:#999999">(</span><span style="color:#999999">(</span><span style="color:#999999">)</span> <span style="color:#a67f59">=></span> <span style="color:#999999">{</span>
            <span style="color:#708090">// 延迟函数执行完毕,清空定时器</span>
            timeout <span style="color:#a67f59">=</span> <span style="color:#36bcd6">null</span>
            <span style="color:#708090">// 延迟执行的情况下,函数会在延迟函数中执行</span>
            <span style="color:#708090">// 使用到之前缓存的参数和上下文</span>
            <span style="color:#36bcd6">if</span> <span style="color:#999999">(</span><span style="color:#a67f59">!</span>immediate<span style="color:#999999">)</span> <span style="color:#999999">{</span>
                func<span style="color:#999999">.</span><span style="color:#f92672">apply</span><span style="color:#999999">(</span>context<span style="color:#999999">,</span> args<span style="color:#999999">)</span><span style="color:#999999">;</span>
                context <span style="color:#a67f59">=</span> args <span style="color:#a67f59">=</span> <span style="color:#36bcd6">null</span><span style="color:#999999">;</span>
            <span style="color:#999999">}</span>
        <span style="color:#999999">}</span><span style="color:#999999">,</span> wait<span style="color:#999999">)</span><span style="color:#999999">;</span>
        <span style="color:#36bcd6">let</span> <span style="color:#f92672">debounced</span> <span style="color:#a67f59">=</span> <span style="color:#36bcd6">function</span> <span style="color:#999999">(</span><span style="color:#a67f59">...</span>params<span style="color:#999999">)</span> <span style="color:#999999">{</span>
            <span style="color:#36bcd6">if</span> <span style="color:#999999">(</span><span style="color:#a67f59">!</span>timeout<span style="color:#999999">)</span> <span style="color:#999999">{</span>
                timeout <span style="color:#a67f59">=</span> <span style="color:#f92672">later</span><span style="color:#999999">(</span><span style="color:#999999">)</span><span style="color:#999999">;</span>
                <span style="color:#36bcd6">if</span> <span style="color:#999999">(</span>immediate<span style="color:#999999">)</span> <span style="color:#999999">{</span>
                    <span style="color:#708090">//立即执行</span>
                    func<span style="color:#999999">.</span><span style="color:#f92672">apply</span><span style="color:#999999">(</span><span style="color:#36bcd6">this</span><span style="color:#999999">,</span> params<span style="color:#999999">)</span><span style="color:#999999">;</span>
                <span style="color:#999999">}</span> <span style="color:#36bcd6">else</span> <span style="color:#999999">{</span>
                    <span style="color:#708090">//闭包</span>
                    context <span style="color:#a67f59">=</span> <span style="color:#36bcd6">this</span><span style="color:#999999">;</span>
                    args <span style="color:#a67f59">=</span> params<span style="color:#999999">;</span>
                <span style="color:#999999">}</span>
            <span style="color:#999999">}</span> <span style="color:#36bcd6">else</span> <span style="color:#999999">{</span>
                <span style="color:#f92672">clearTimeout</span><span style="color:#999999">(</span>timeout<span style="color:#999999">)</span><span style="color:#999999">;</span>
                timeout <span style="color:#a67f59">=</span> <span style="color:#f92672">later</span><span style="color:#999999">(</span><span style="color:#999999">)</span><span style="color:#999999">;</span>
            <span style="color:#999999">}</span>
        <span style="color:#999999">}</span>
    debounced<span style="color:#999999">.</span><span style="color:#f92672">cancel</span> <span style="color:#a67f59">=</span> <span style="color:#36bcd6">function</span> <span style="color:#999999">(</span><span style="color:#999999">)</span> <span style="color:#999999">{</span>
        <span style="color:#f92672">clearTimeout</span><span style="color:#999999">(</span>timeout<span style="color:#999999">)</span><span style="color:#999999">;</span>
        timeout <span style="color:#a67f59">=</span> <span style="color:#36bcd6">null</span><span style="color:#999999">;</span>
    <span style="color:#999999">}</span><span style="color:#999999">;</span>
    <span style="color:#36bcd6">return</span> debounced<span style="color:#999999">;</span>
<span style="color:#999999">}</span><span style="color:#999999">;</span>
</code></span>

防抖的应用场景:

  • 每次 resize/scroll 触发统计事件
  • 文本输入的验证(连续输入文字后发送 AJAX 请求进行验证,验证一次就好)

节流(throttle): 高频事件在规定时间内只会执行一次,执行一次后,只有大于设定的执行周期后才会执行第二次。

<span style="color:#1c1f21"><code class="language-javascript"><span style="color:#708090">//underscore.js</span>
<span style="color:#36bcd6">function</span> <span style="color:#f92672">throttle</span><span style="color:#999999">(</span>func<span style="color:#999999">,</span> wait<span style="color:#999999">,</span> options<span style="color:#999999">)</span> <span style="color:#999999">{</span>
    <span style="color:#36bcd6">var</span> timeout<span style="color:#999999">,</span> context<span style="color:#999999">,</span> args<span style="color:#999999">,</span> result<span style="color:#999999">;</span>
    <span style="color:#36bcd6">var</span> previous <span style="color:#a67f59">=</span> <span style="color:#ae81ff">0</span><span style="color:#999999">;</span>
    <span style="color:#36bcd6">if</span> <span style="color:#999999">(</span><span style="color:#a67f59">!</span>options<span style="color:#999999">)</span> options <span style="color:#a67f59">=</span> <span style="color:#999999">{</span><span style="color:#999999">}</span><span style="color:#999999">;</span>

    <span style="color:#36bcd6">var</span> <span style="color:#f92672">later</span> <span style="color:#a67f59">=</span> <span style="color:#36bcd6">function</span> <span style="color:#999999">(</span><span style="color:#999999">)</span> <span style="color:#999999">{</span>
        previous <span style="color:#a67f59">=</span> options<span style="color:#999999">.</span>leading <span style="color:#a67f59">===</span> <span style="color:#ae81ff">false</span> <span style="color:#a67f59">?</span> <span style="color:#ae81ff">0</span> <span style="color:#999999">:</span> Date<span style="color:#999999">.</span><span style="color:#f92672">now</span><span style="color:#999999">(</span><span style="color:#999999">)</span> <span style="color:#a67f59">||</span> <span style="color:#36bcd6">new</span> Date<span style="color:#999999">(</span><span style="color:#999999">)</span><span style="color:#999999">.</span><span style="color:#f92672">getTime</span><span style="color:#999999">(</span><span style="color:#999999">)</span><span style="color:#999999">;</span>
        timeout <span style="color:#a67f59">=</span> <span style="color:#36bcd6">null</span><span style="color:#999999">;</span>
        result <span style="color:#a67f59">=</span> func<span style="color:#999999">.</span><span style="color:#f92672">apply</span><span style="color:#999999">(</span>context<span style="color:#999999">,</span> args<span style="color:#999999">)</span><span style="color:#999999">;</span>
        <span style="color:#36bcd6">if</span> <span style="color:#999999">(</span><span style="color:#a67f59">!</span>timeout<span style="color:#999999">)</span> context <span style="color:#a67f59">=</span> args <span style="color:#a67f59">=</span> <span style="color:#36bcd6">null</span><span style="color:#999999">;</span>
    <span style="color:#999999">}</span><span style="color:#999999">;</span>

    <span style="color:#36bcd6">var</span> <span style="color:#f92672">throttled</span> <span style="color:#a67f59">=</span> <span style="color:#36bcd6">function</span> <span style="color:#999999">(</span><span style="color:#999999">)</span> <span style="color:#999999">{</span>
        <span style="color:#36bcd6">var</span> now <span style="color:#a67f59">=</span> Date<span style="color:#999999">.</span><span style="color:#f92672">now</span><span style="color:#999999">(</span><span style="color:#999999">)</span> <span style="color:#a67f59">||</span> <span style="color:#36bcd6">new</span> Date<span style="color:#999999">(</span><span style="color:#999999">)</span><span style="color:#999999">.</span><span style="color:#f92672">getTime</span><span style="color:#999999">(</span><span style="color:#999999">)</span><span style="color:#999999">;</span>
        <span style="color:#36bcd6">if</span> <span style="color:#999999">(</span><span style="color:#a67f59">!</span>previous <span style="color:#a67f59">&&</span> options<span style="color:#999999">.</span>leading <span style="color:#a67f59">===</span> <span style="color:#ae81ff">false</span><span style="color:#999999">)</span> previous <span style="color:#a67f59">=</span> now<span style="color:#999999">;</span>
        <span style="color:#36bcd6">var</span> remaining <span style="color:#a67f59">=</span> wait <span style="color:#a67f59">-</span> <span style="color:#999999">(</span>now <span style="color:#a67f59">-</span> previous<span style="color:#999999">)</span><span style="color:#999999">;</span>
        context <span style="color:#a67f59">=</span> <span style="color:#36bcd6">this</span><span style="color:#999999">;</span>
        args <span style="color:#a67f59">=</span> arguments<span style="color:#999999">;</span>
        <span style="color:#36bcd6">if</span> <span style="color:#999999">(</span>remaining <span style="color:#a67f59"><=</span> <span style="color:#ae81ff">0</span> <span style="color:#a67f59">||</span> remaining <span style="color:#a67f59">></span> wait<span style="color:#999999">)</span> <span style="color:#999999">{</span>
            <span style="color:#36bcd6">if</span> <span style="color:#999999">(</span>timeout<span style="color:#999999">)</span> <span style="color:#999999">{</span>
                <span style="color:#f92672">clearTimeout</span><span style="color:#999999">(</span>timeout<span style="color:#999999">)</span><span style="color:#999999">;</span>
                timeout <span style="color:#a67f59">=</span> <span style="color:#36bcd6">null</span><span style="color:#999999">;</span>
            <span style="color:#999999">}</span>
            previous <span style="color:#a67f59">=</span> now<span style="color:#999999">;</span>
            result <span style="color:#a67f59">=</span> func<span style="color:#999999">.</span><span style="color:#f92672">apply</span><span style="color:#999999">(</span>context<span style="color:#999999">,</span> args<span style="color:#999999">)</span><span style="color:#999999">;</span>
            <span style="color:#36bcd6">if</span> <span style="color:#999999">(</span><span style="color:#a67f59">!</span>timeout<span style="color:#999999">)</span> context <span style="color:#a67f59">=</span> args <span style="color:#a67f59">=</span> <span style="color:#36bcd6">null</span><span style="color:#999999">;</span>
        <span style="color:#999999">}</span> <span style="color:#36bcd6">else</span> <span style="color:#36bcd6">if</span> <span style="color:#999999">(</span><span style="color:#a67f59">!</span>timeout <span style="color:#a67f59">&&</span> options<span style="color:#999999">.</span>trailing <span style="color:#a67f59">!==</span> <span style="color:#ae81ff">false</span><span style="color:#999999">)</span> <span style="color:#999999">{</span>
            <span style="color:#708090">// 判断是否设置了定时器和 trailing</span>
            timeout <span style="color:#a67f59">=</span> <span style="color:#f92672">setTimeout</span><span style="color:#999999">(</span>later<span style="color:#999999">,</span> remaining<span style="color:#999999">)</span><span style="color:#999999">;</span>
        <span style="color:#999999">}</span>
        <span style="color:#36bcd6">return</span> result<span style="color:#999999">;</span>
    <span style="color:#999999">}</span><span style="color:#999999">;</span>

    throttled<span style="color:#999999">.</span><span style="color:#f92672">cancel</span> <span style="color:#a67f59">=</span> <span style="color:#36bcd6">function</span> <span style="color:#999999">(</span><span style="color:#999999">)</span> <span style="color:#999999">{</span>
        <span style="color:#f92672">clearTimeout</span><span style="color:#999999">(</span>timeout<span style="color:#999999">)</span><span style="color:#999999">;</span>
        previous <span style="color:#a67f59">=</span> <span style="color:#ae81ff">0</span><span style="color:#999999">;</span>
        timeout <span style="color:#a67f59">=</span> context <span style="color:#a67f59">=</span> args <span style="color:#a67f59">=</span> <span style="color:#36bcd6">null</span><span style="color:#999999">;</span>
    <span style="color:#999999">}</span><span style="color:#999999">;</span>

    <span style="color:#36bcd6">return</span> throttled<span style="color:#999999">;</span>
<span style="color:#999999">}</span><span style="color:#999999">;</span>

</code></span>

函数节流的应用场景有:

  • DOM 元素的拖拽功能实现(mousemove)
  • 射击游戏的 mousedown/keydown 事件(单位时间只能发射一颗子弹)
  • 计算鼠标移动的距离(mousemove)
  • Canvas 模拟画板功能(mousemove)
  • 搜索联想(keyup)
  • 监听滚动事件判断是否到页面底部自动加载更多:给 scroll 加了 debounce 后,只有用户停止滚动后,才会判断是否到了页面底部;如果是 throttle 的话,只要页面滚动就会间隔一段时间判断一次

23. 取数组的最大值(ES5、ES6)

<span style="color:#1c1f21"><code class="language-javascript"><span style="color:#708090">// ES5 的写法</span>
Math<span style="color:#999999">.</span>max<span style="color:#999999">.</span><span style="color:#f92672">apply</span><span style="color:#999999">(</span><span style="color:#36bcd6">null</span><span style="color:#999999">,</span> <span style="color:#999999">[</span><span style="color:#ae81ff">14</span><span style="color:#999999">,</span> <span style="color:#ae81ff">3</span><span style="color:#999999">,</span> <span style="color:#ae81ff">77</span><span style="color:#999999">,</span> <span style="color:#ae81ff">30</span><span style="color:#999999">]</span><span style="color:#999999">)</span><span style="color:#999999">;</span>

<span style="color:#708090">// ES6 的写法</span>
Math<span style="color:#999999">.</span><span style="color:#f92672">max</span><span style="color:#999999">(</span><span style="color:#a67f59">...</span><span style="color:#999999">[</span><span style="color:#ae81ff">14</span><span style="color:#999999">,</span> <span style="color:#ae81ff">3</span><span style="color:#999999">,</span> <span style="color:#ae81ff">77</span><span style="color:#999999">,</span> <span style="color:#ae81ff">30</span><span style="color:#999999">]</span><span style="color:#999999">)</span><span style="color:#999999">;</span>

<span style="color:#708090">// reduce</span>
<span style="color:#999999">[</span><span style="color:#ae81ff">14</span><span style="color:#999999">,</span><span style="color:#ae81ff">3</span><span style="color:#999999">,</span><span style="color:#ae81ff">77</span><span style="color:#999999">,</span><span style="color:#ae81ff">30</span><span style="color:#999999">]</span><span style="color:#999999">.</span><span style="color:#f92672">reduce</span><span style="color:#999999">(</span><span style="color:#999999">(</span>accumulator<span style="color:#999999">,</span> currentValue<span style="color:#999999">)</span><span style="color:#a67f59">=></span><span style="color:#999999">{</span>
    <span style="color:#36bcd6">return</span> accumulator <span style="color:#a67f59">=</span> accumulator <span style="color:#a67f59">></span> currentValue <span style="color:#a67f59">?</span> accumulator <span style="color:#999999">:</span> currentValue
<span style="color:#999999">}</span><span style="color:#999999">)</span><span style="color:#999999">;</span>
</code></span>

24. ES6新的特性有哪些?

  1. 新增了块级作用域(let,const)
  2. 提供了定义类的语法糖(class)
  3. 新增了一种基本数据类型(Symbol)
  4. 新增了变量的解构赋值
  5. 函数参数允许设置默认值,引入了rest参数,新增了箭头函数
  6. 数组新增了一些API,如 isArray / from / of 方法;数组实例新增了 entries(),keys() 和 values() 等方法
  7. 对象和数组新增了扩展运算符
  8. ES6 新增了模块化(import/export)
  9. ES6 新增了 Set 和 Map 数据结构
  10. ES6 原生提供 Proxy 构造函数,用来生成 Proxy 实例
  11. ES6 新增了生成器(Generator)和遍历器(Iterator)

25. setTimeout倒计时为什么会出现误差?

setTimeout() 只是将事件插入了“任务队列”,必须等当前代码(执行栈)执行完,主线程才会去执行它指定的回调函数。要是当前代码消耗时间很长,也有可能要等很久,所以并没办法保证回调函数一定会在 setTimeout() 指定的时间执行。所以, setTimeout() 的第二个参数表示的是最少时间,并非是确切时间。

HTML5标准规定了 setTimeout() 的第二个参数的最小值不得小于4毫秒,如果低于这个值,则默认是4毫秒。在此之前。老版本的浏览器都将最短时间设为10毫秒。另外,对于那些DOM的变动(尤其是涉及页面重新渲染的部分),通常是间隔16毫秒执行。这时使用 requestAnimationFrame() 的效果要好于 setTimeout();


26. 为什么 0.1 + 0.2 != 0.3 ?

0.1 + 0.2 != 0.3 是因为在进制转换和进阶运算的过程中出现精度损失。

下面是详细解释:

JavaScript使用 Number 类型表示数字(整数和浮点数),使用64位表示一个数字。


图片说明:

  • 第0位:符号位,0表示正数,1表示负数(s)
  • 第1位到第11位:储存指数部分(e)
  • 第12位到第63位:储存小数部分(即有效数字)f

计算机无法直接对十进制的数字进行运算, 需要先对照 IEEE 754 规范转换成二进制,然后对阶运算。

1.进制转换

0.1和0.2转换成二进制后会无限循环

0.1 -> 0.0001100110011001...(无限循环)
0.2 -> 0.0011001100110011...(无限循环)

但是由于IEEE 754尾数位数限制,需要将后面多余的位截掉,这样在进制之间的转换中精度已经损失。

2.对阶运算

由于指数位数不相同,运算时需要对阶运算 这部分也可能产生精度损失。

按照上面两步运算(包括两步的精度损失),最后的结果是

0.0100110011001100110011001100110011001100110011001100

结果转换成十进制之后就是 0.30000000000000004。

27. promise 有几种状态, Promise 有什么优缺点 ?

promise有三种状态: fulfilled, rejected, pending.

Promise 的优点:

  1. 一旦状态改变,就不会再变,任何时候都可以得到这个结果
  2. 可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数

Promise 的缺点:

  1. 无法取消 Promise
  2. 当处于pending状态时,无法得知目前进展到哪一个阶段

28. Promise构造函数是同步还是异步执行,then中的方法呢 ?promise如何实现then处理 ?

Promise的构造函数是同步执行的。then 中的方法是异步执行的。

promise的then实现,详见: Promise源码实现


29. Promise和setTimeout的区别 ?

Promise 是微任务,setTimeout 是宏任务,同一个事件循环中,promise.then总是先于 setTimeout 执行。


30. 如何实现 Promise.all ?

要实现 Promise.all,首先我们需要知道 Promise.all 的功能:

  1. 如果传入的参数是一个空的可迭代对象,那么此promise对象回调完成(resolve),只有此情况,是同步执行的,其它都是异步返回的。
  2. 如果传入的参数不包含任何 promise,则返回一个异步完成.
    promises 中所有的promise都“完成”时或参数中不包含 promise 时回调完成。
  3. 如果参数中有一个promise失败,那么Promise.all返回的promise对象失败
  4. 在任何情况下,Promise.all 返回的 promise 的完成状态的结果都是一个数组
<span style="color:#1c1f21"><code class="language-javascript">Promise<span style="color:#999999">.</span><span style="color:#f92672">all</span> <span style="color:#a67f59">=</span> <span style="color:#36bcd6">function</span> <span style="color:#999999">(</span>promises<span style="color:#999999">)</span> <span style="color:#999999">{</span>
    <span style="color:#36bcd6">return</span> <span style="color:#36bcd6">new</span> Promise<span style="color:#999999">(</span><span style="color:#999999">(</span>resolve<span style="color:#999999">,</span> reject<span style="color:#999999">)</span> <span style="color:#a67f59">=></span> <span style="color:#999999">{</span>
        <span style="color:#36bcd6">let</span> index <span style="color:#a67f59">=</span> <span style="color:#ae81ff">0</span><span style="color:#999999">;</span>
        <span style="color:#36bcd6">let</span> result <span style="color:#a67f59">=</span> <span style="color:#999999">[</span><span style="color:#999999">]</span><span style="color:#999999">;</span>
        <span style="color:#36bcd6">if</span> <span style="color:#999999">(</span>promises<span style="color:#999999">.</span>length <span style="color:#a67f59">===</span> <span style="color:#ae81ff">0</span><span style="color:#999999">)</span> <span style="color:#999999">{</span>
            <span style="color:#f92672">resolve</span><span style="color:#999999">(</span>result<span style="color:#999999">)</span><span style="color:#999999">;</span>
        <span style="color:#999999">}</span> <span style="color:#36bcd6">else</span> <span style="color:#999999">{</span>
            <span style="color:#36bcd6">function</span> <span style="color:#f92672">processValue</span><span style="color:#999999">(</span>i<span style="color:#999999">,</span> data<span style="color:#999999">)</span> <span style="color:#999999">{</span>
                result<span style="color:#999999">[</span>i<span style="color:#999999">]</span> <span style="color:#a67f59">=</span> data<span style="color:#999999">;</span>
                <span style="color:#36bcd6">if</span> <span style="color:#999999">(</span><span style="color:#a67f59">++</span>index <span style="color:#a67f59">===</span> promises<span style="color:#999999">.</span>length<span style="color:#999999">)</span> <span style="color:#999999">{</span>
                    <span style="color:#f92672">resolve</span><span style="color:#999999">(</span>result<span style="color:#999999">)</span><span style="color:#999999">;</span>
                <span style="color:#999999">}</span>
            <span style="color:#999999">}</span>
            <span style="color:#36bcd6">for</span> <span style="color:#999999">(</span><span style="color:#36bcd6">let</span> i <span style="color:#a67f59">=</span> <span style="color:#ae81ff">0</span><span style="color:#999999">;</span> i <span style="color:#a67f59"><</span> promises<span style="color:#999999">.</span>length<span style="color:#999999">;</span> i<span style="color:#a67f59">++</span><span style="color:#999999">)</span> <span style="color:#999999">{</span>
                <span style="color:#708090">//promises[i] 可能是普通值</span>
                Promise<span style="color:#999999">.</span><span style="color:#f92672">resolve</span><span style="color:#999999">(</span>promises<span style="color:#999999">[</span>i<span style="color:#999999">]</span><span style="color:#999999">)</span><span style="color:#999999">.</span><span style="color:#f92672">then</span><span style="color:#999999">(</span><span style="color:#999999">(</span>data<span style="color:#999999">)</span> <span style="color:#a67f59">=></span> <span style="color:#999999">{</span>
                    <span style="color:#f92672">processValue</span><span style="color:#999999">(</span>i<span style="color:#999999">,</span> data<span style="color:#999999">)</span><span style="color:#999999">;</span>
                <span style="color:#999999">}</span><span style="color:#999999">,</span> <span style="color:#999999">(</span>err<span style="color:#999999">)</span> <span style="color:#a67f59">=></span> <span style="color:#999999">{</span>
                    <span style="color:#f92672">reject</span><span style="color:#999999">(</span>err<span style="color:#999999">)</span><span style="color:#999999">;</span>
                    <span style="color:#36bcd6">return</span><span style="color:#999999">;</span>
                <span style="color:#999999">}</span><span style="color:#999999">)</span><span style="color:#999999">;</span>
            <span style="color:#999999">}</span>
        <span style="color:#999999">}</span>
    <span style="color:#999999">}</span><span style="color:#999999">)</span><span style="color:#999999">;</span>
<span style="color:#999999">}</span>
</code></span>

如果想了解更多Promise的源码实现,可以参考我的另一篇文章:Promise的源码实现(完美符合Promise/A+规范)


31.如何实现 Promise.finally ?

不管成功还是失败,都会走到finally中,并且finally之后,还可以继续then。并且会将值原封不动的传递给后面的then.

<span style="color:#1c1f21"><code class="language-javascript">Promise<span style="color:#999999">.</span>prototype<span style="color:#999999">.</span><span style="color:#f92672">finally</span> <span style="color:#a67f59">=</span> <span style="color:#36bcd6">function</span> <span style="color:#999999">(</span>callback<span style="color:#999999">)</span> <span style="color:#999999">{</span>
    <span style="color:#36bcd6">return</span> <span style="color:#36bcd6">this</span><span style="color:#999999">.</span><span style="color:#f92672">then</span><span style="color:#999999">(</span><span style="color:#999999">(</span>value<span style="color:#999999">)</span> <span style="color:#a67f59">=></span> <span style="color:#999999">{</span>
        <span style="color:#36bcd6">return</span> Promise<span style="color:#999999">.</span><span style="color:#f92672">resolve</span><span style="color:#999999">(</span><span style="color:#f92672">callback</span><span style="color:#999999">(</span><span style="color:#999999">)</span><span style="color:#999999">)</span><span style="color:#999999">.</span><span style="color:#f92672">then</span><span style="color:#999999">(</span><span style="color:#999999">(</span><span style="color:#999999">)</span> <span style="color:#a67f59">=></span> <span style="color:#999999">{</span>
            <span style="color:#36bcd6">return</span> value<span style="color:#999999">;</span>
        <span style="color:#999999">}</span><span style="color:#999999">)</span><span style="color:#999999">;</span>
    <span style="color:#999999">}</span><span style="color:#999999">,</span> <span style="color:#999999">(</span>err<span style="color:#999999">)</span> <span style="color:#a67f59">=></span> <span style="color:#999999">{</span>
        <span style="color:#36bcd6">return</span> Promise<span style="color:#999999">.</span><span style="color:#f92672">resolve</span><span style="color:#999999">(</span><span style="color:#f92672">callback</span><span style="color:#999999">(</span><span style="color:#999999">)</span><span style="color:#999999">)</span><span style="color:#999999">.</span><span style="color:#f92672">then</span><span style="color:#999999">(</span><span style="color:#999999">(</span><span style="color:#999999">)</span> <span style="color:#a67f59">=></span> <span style="color:#999999">{</span>
            <span style="color:#36bcd6">throw</span> err<span style="color:#999999">;</span>
        <span style="color:#999999">}</span><span style="color:#999999">)</span><span style="color:#999999">;</span>
    <span style="color:#999999">}</span><span style="color:#999999">)</span><span style="color:#999999">;</span>
<span style="color:#999999">}</span>
</code></span>

32. 什么是函数柯里化?实现 sum(1)(2)(3) 返回结果是1,2,3之和

函数柯里化是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数的技术。

<span style="color:#1c1f21"><code class="language-javascript"><span style="color:#36bcd6">function</span> <span style="color:#f92672">sum</span><span style="color:#999999">(</span>a<span style="color:#999999">)</span> <span style="color:#999999">{</span>
    <span style="color:#36bcd6">return</span> <span style="color:#36bcd6">function</span><span style="color:#999999">(</span>b<span style="color:#999999">)</span> <span style="color:#999999">{</span>
        <span style="color:#36bcd6">return</span> <span style="color:#36bcd6">function</span><span style="color:#999999">(</span>c<span style="color:#999999">)</span> <span style="color:#999999">{</span>
            <span style="color:#36bcd6">return</span> a<span style="color:#a67f59">+</span>b<span style="color:#a67f59">+</span>c<span style="color:#999999">;</span>
        <span style="color:#999999">}</span>
    <span style="color:#999999">}</span>
<span style="color:#999999">}</span>
console<span style="color:#999999">.</span><span style="color:#f92672">log</span><span style="color:#999999">(</span><span style="color:#f92672">sum</span><span style="color:#999999">(</span><span style="color:#ae81ff">1</span><span style="color:#999999">)</span><span style="color:#999999">(</span><span style="color:#ae81ff">2</span><span style="color:#999999">)</span><span style="color:#999999">(</span><span style="color:#ae81ff">3</span><span style="color:#999999">)</span><span style="color:#999999">)</span><span style="color:#999999">;</span> <span style="color:#708090">// 6</span>
</code></span>

引申:实现一个curry函数,将普通函数进行柯里化:

<span style="color:#1c1f21"><code class="language-javascript"><span style="color:#36bcd6">function</span> <span style="color:#f92672">curry</span><span style="color:#999999">(</span>fn<span style="color:#999999">,</span> args <span style="color:#a67f59">=</span> <span style="color:#999999">[</span><span style="color:#999999">]</span><span style="color:#999999">)</span> <span style="color:#999999">{</span>
    <span style="color:#36bcd6">return</span> <span style="color:#36bcd6">function</span><span style="color:#999999">(</span><span style="color:#999999">)</span><span style="color:#999999">{</span>
        <span style="color:#36bcd6">let</span> rest <span style="color:#a67f59">=</span> <span style="color:#999999">[</span><span style="color:#a67f59">...</span>args<span style="color:#999999">,</span> <span style="color:#a67f59">...</span>arguments<span style="color:#999999">]</span><span style="color:#999999">;</span>
        <span style="color:#36bcd6">if</span> <span style="color:#999999">(</span>rest<span style="color:#999999">.</span>length <span style="color:#a67f59"><</span> fn<span style="color:#999999">.</span>length<span style="color:#999999">)</span> <span style="color:#999999">{</span>
            <span style="color:#36bcd6">return</span> curry<span style="color:#999999">.</span><span style="color:#f92672">call</span><span style="color:#999999">(</span><span style="color:#36bcd6">this</span><span style="color:#999999">,</span>fn<span style="color:#999999">,</span>rest<span style="color:#999999">)</span><span style="color:#999999">;</span>
        <span style="color:#999999">}</span><span style="color:#36bcd6">else</span><span style="color:#999999">{</span>
            <span style="color:#36bcd6">return</span> fn<span style="color:#999999">.</span><span style="color:#f92672">apply</span><span style="color:#999999">(</span><span style="color:#36bcd6">this</span><span style="color:#999999">,</span>rest<span style="color:#999999">)</span><span style="color:#999999">;</span>
        <span style="color:#999999">}</span>
    <span style="color:#999999">}</span>
<span style="color:#999999">}</span>
<span style="color:#708090">//test</span>
<span style="color:#36bcd6">function</span> <span style="color:#f92672">sum</span><span style="color:#999999">(</span>a<span style="color:#999999">,</span>b<span style="color:#999999">,</span>c<span style="color:#999999">)</span> <span style="color:#999999">{</span>
    <span style="color:#36bcd6">return</span> a<span style="color:#a67f59">+</span>b<span style="color:#a67f59">+</span>c<span style="color:#999999">;</span>
<span style="color:#999999">}</span>
<span style="color:#36bcd6">let</span> sumFn <span style="color:#a67f59">=</span> <span style="color:#f92672">curry</span><span style="color:#999999">(</span>sum<span style="color:#999999">)</span><span style="color:#999999">;</span>
console<span style="color:#999999">.</span><span style="color:#f92672">log</span><span style="color:#999999">(</span><span style="color:#f92672">sumFn</span><span style="color:#999999">(</span><span style="color:#ae81ff">1</span><span style="color:#999999">)</span><span style="color:#999999">(</span><span style="color:#ae81ff">2</span><span style="color:#999999">)</span><span style="color:#999999">(</span><span style="color:#ae81ff">3</span><span style="color:#999999">)</span><span style="color:#999999">)</span><span style="color:#999999">;</span> <span style="color:#708090">//6</span>
console<span style="color:#999999">.</span><span style="color:#f92672">log</span><span style="color:#999999">(</span><span style="color:#f92672">sumFn</span><span style="color:#999999">(</span><span style="color:#ae81ff">1</span><span style="color:#999999">)</span><span style="color:#999999">(</span><span style="color:#ae81ff">2</span><span style="color:#999999">,</span> <span style="color:#ae81ff">3</span><span style="color:#999999">)</span><span style="color:#999999">)</span><span style="color:#999999">;</span> <span style="color:#708090">//6</span></code></span>

 

基于数据挖掘的音乐推荐系统设计与实现 需要一个代码说明,不需要论文 采用python语言,django框架,mysql数据库开发 编程环境:pycharm,mysql8.0 系统分为前台+后台模式开发 网站前台: 用户注册, 登录 搜索音乐,音乐欣赏(可以在线进行播放) 用户登陆时选择相关感兴趣的音乐风格 音乐收藏 音乐推荐算法:(重点) 本课题需要大量用户行为(如播放记录、收藏列表)、音乐特征(如音频特征、歌曲元数据)等数据 (1)根据用户之间相似性或关联性,给一个用户推荐与其相似或有关联的其他用户所感兴趣的音乐; (2)根据音乐之间的相似性或关联性,给一个用户推荐与其感兴趣的音乐相似或有关联的其他音乐。 基于用户的推荐和基于物品的推荐 其中基于用户的推荐是基于用户的相似度找出相似相似用户,然后向目标用户推荐其相似用户喜欢的东西(和你类似的人也喜欢**东西); 而基于物品的推荐是基于物品的相似度找出相似的物品做推荐(喜欢该音乐的人还喜欢了**音乐); 管理员 管理员信息管理 注册用户管理,审核 音乐爬虫(爬虫方式爬取网站音乐数据) 音乐信息管理(上传歌曲MP3,以便前台播放) 音乐收藏管理 用户 用户资料修改 我的音乐收藏 完整前后端源码,部署后可正常运行! 环境说明 开发语言:python后端 python版本:3.7 数据库:mysql 5.7+ 数据库工具:Navicat11+ 开发软件:pycharm
MPU6050是一款广泛应用在无人机、机器人和运动设备中的六轴姿态传感器,它集成了三轴陀螺仪和三轴加速度计。这款传感器能够实时监测并提供设备的角速度和线性加速度数据,对于理解物体的动态运动状态至关重要。在Arduino平台上,通过特定的库文件可以方便地与MPU6050进行通信,获取并解析传感器数据。 `MPU6050.cpp`和`MPU6050.h`是Arduino库的关键组成部分。`MPU6050.h`是头文件,包含了定义传感器接口和函数声明。它定义了类`MPU6050`,该类包含了初始化传感器、读取数据等方法。例如,`begin()`函数用于设置传感器的工作模式和I2C地址,`getAcceleration()`和`getGyroscope()`则分别用于获取加速度和角速度数据。 在Arduino项目中,首先需要包含`MPU6050.h`头文件,然后创建`MPU6050`对象,并调用`begin()`函数初始化传感器。之后,可以通过循环调用`getAcceleration()`和`getGyroscope()`来不断更新传感器读数。为了处理这些原始数据,通常还需要进行校准和滤波,以消除噪声和漂移。 I2C通信协议是MPU6050与Arduino交互的基础,它是一种低引脚数的串行通信协议,允许多个设备共享一对数据线。Arduino板上的Wire库提供了I2C通信的底层支持,使得用户无需深入了解通信细节,就能方便地与MPU6050交互。 MPU6050传感器的数据包括加速度(X、Y、Z轴)和角速度(同样为X、Y、Z轴)。加速度数据可以用来计算物体的静态位置和动态运动,而角速度数据则能反映物体转动的速度。结合这两个数据,可以进一步计算出物体的姿态(如角度和角速度变化)。 在嵌入式开发领域,特别是使用STM32微控制器时,也可以找到类似的库来驱动MPU6050。STM32通常具有更强大的处理能力和更多的GPIO口,可以实现更复杂的控制算法。然而,基本的传感器操作流程和数据处理原理与Arduino平台相似。 在实际应用中,除了基本的传感器读取,还可能涉及到温度补偿、低功耗模式设置、DMP(数字运动处理器)功能的利用等高级特性。DMP可以帮助处理传感器数据,实现更高级的运动估计,减轻主控制器的计算负担。 MPU6050是一个强大的六轴传感器,广泛应用于各种需要实时运动追踪的项目中。通过 Arduino 或 STM32 的库文件,开发者可以轻松地与传感器交互,获取并处理数据,实现各种创新应用。博客和其他开源资源是学习和解决问题的重要途径,通过这些资源,开发者可以获得关于MPU6050的详细信息和实践指南
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值