本周发起了一个100天前端进阶计划,天天一个知识点,搞明白背后的原理,这是第一周的总结,请注意查收。前端
// base.js let count = 0; setTimeout(() => { console.log("base.count", ++count); }, 500) module.exports.count = count; // commonjs.js const { count } = require('./base'); setTimeout(() => { console.log("count is" + count + 'in commonjs'); }, 1000) // base1.js let count = 0; setTimeout(() => { console.log("base.count", ++count); }, 500) exports const count = count; // es6.js import { count } from './base1'; setTimeout(() => { console.log("count is" + count + 'in es6'); }, 1000) 复制代码
解析:git
详细分析请看 《require和import的区别》es6
console.log((function() { console.log(1); setTimeout(function() { console.log(2) }, 1000) setTimeout(function() { console.log(3) }, 0); setTimeout(function() { console.log(4) }, 0); console.log(5) })()); 复制代码
console.log((typeof null )); console.log((typeof [])); console.log((typeof Symbol())); console.log((typeof 123n) ); function foo() { console.log(111); }; console.log((typeof foo)); 复制代码
function *foo(x) { const y = 2 * (yield (x + 1)); const z = yield (y / 3); return (x + y + z); } const a = foo(5); console.log(a.next()); console.log(a.next()); console.log(a.next()); const b = foo(5); console.log(b.next()); console.log(b.next(12)); console.log(b.next(13)); 复制代码
{ value: 6, done: false } { value: NaN, done: false } { value: NaN, done: true } { value: 6, done: false } { value: 8, done: false } { value: 42, done: true } 复制代码
解析: 先看使用Generator函数生成的迭代器a
:面试
第一次调用next方法,遇到 yield 中止,返回yield表达式的值,此时为 5 + 1 = 6
;算法
第二次调用next方法,遇到 yield 中止,返回yield表达式的值,因为next方法没有带参数,上一个yield表达式返回值为undefined
, 致使y
的值等于2*undefined
即(NaN
),除以 3
之后仍是NaN
,所以返回对象的value
属性也等于NaN
。数组
第三次调用next方法,执行的是 return (x + y + z)
,此时x
的值为 5
, y
的值为 NaN
, 因为next方法没有带参数,上一个yield表达式返回值为undefined
,致使z为 undefined,返回对象的 value属性等于5 + NaN + undefined
,即 NaN浏览器
再来看看使用Generator函数生成的迭代器b
:缓存
第一次调用next方法,遇到 yield 中止,返回yield表达式的值,此时为 5 + 1 = 6
;微信
第二次调用next方法,遇到 yield 中止,返回yield表达式的值,因为next方法带有参数12
,因此上一个yield表达式返回值为12
, 所以y
的值等于2*12
即(24
),除以 3
是8
,所以返回对象的value
属性为8
。
第三次调用next方法,执行的是 return (x + y + z)
,此时x
的值为 5
, y
的值为 24
, 因为next方法带有参数13
,所以z为13
,返回对象的 value属性等于5 + 24 + 13
,即 42
详细分析请看 Generator函数详解》
let z = 1; function *foo() { const x = yield 2; z++; const y = yield (x * z); console.log(x, y, z); } const a = foo(); const b = foo(); let val1 = a.next().value; console.log(val1); let val2 = b.next().value; console.log(val2); val1 = a.next(val2 * 10).value; console.log(val1); val2 = b.next(val1 * 5).value; console.log(val2); a.next(val2 / 2); b.next(val1 / 4); 复制代码
解析
*foo()
的两个实例同时启用,两个next()
分别从yield 2
语句获得2
val2 * 10
也就是2 * 10
,发送到第一个生成器实例 a
, 由于x获得的值20
。z
从1
增长到2
,而后 20 * 2
经过 yield
发出,将val1
设置为40
val1 * 5
也就是 40 * 5
,发送到第二个生成器实例 b
,所以x获得的值200
。z
再从 2
递增到3
,而后 200*3
经过 yield
发出,将val2
设置为 600
val2 / 2
也就是 600 / 2
发动到第一个生成器实例 a
, 所以 y获得值 300
, 而后打印出 x y z
的值分别为 20, 300, 3
。
val1 / 4
也就是 40 / 4
, 发送到第二个生成器实例 b
, 所以 y
获得的值10
, 而后打印出 x y z
的值分别为 200, 10, 3
。
详细分析请看 《Generator函数》
JavaScript有八种内置类型
除对象外,其余统称为“基本类型”。
注意新增的
symbol
和BigInt
typeof
原理: 不一样的对象在底层都表示为二进制,在Javascript中二进制前(低)三位存储其类型信息。
typeof null 为"object", 缘由是由于 不一样的对象在底层都表示为二进制,在Javascript中二进制前(低)三位都为0的话会被判断为Object类型,null的二进制表示全为0,天然前三位也是0,因此执行typeof时会返回"object"。
关键词:JavaScript数据类型的相关底层机制
instanceof
的语法:
object instanceof constructor // 等同于 constructor.prototype.isPrototypeOf(object) 复制代码
instanceof
原理: 检测 constructor.prototype
是否存在于参数 object的 原型链上。instanceof
查找的过程当中会遍历object
的原型链,直到找到 constructor
的 prototype
,若是查找失败,则会返回false
,告诉咱们,object
并不是是 constructor
的实例。
对象的Symbol.hasInstance
属性,指向一个内部方法。当其余对象使用instanceof
运算符,判断是否为该对象的实例时,会调用这个方法。好比,foo instanceof Foo
在语言内部,实际调用的是FooSymbol.hasInstance。
class MyClass { [Symbol.hasInstance](foo) { return foo instanceof Array; } } [1, 2, 3] instanceof new MyClass() // true 复制代码
关键词:instanceof 用法,原型链,
Symbol.hasInstance
。详细分析请查看《 typeof和instanceof原理》
setTimeout(function fn(){ console.log('我被调用了'); setTimeout(fn, 100); },100); 复制代码
setTimeout(()=> {}, 0)
执行该语句时,是当即把当前定时器代码推入事件队列,当定时器在事件列表中知足设置的时间值时将传入的函数加入任务队列,以后的执行就交给任务队列负责。可是若是此时任务队列不为空,则需等待,因此执行定时器内代码的时间可能会大于设置的时间。
HTML5标准规定了setTimeout()的第二个参数的最小值(最短间隔)不得低于4毫秒。 当指定的时间低于该时间时,浏览器会用最小容许的时间做为setTimeout的时间间隔,也就是说即便咱们把setTimeout的延迟时间设置为0,实际上可能为 4毫秒后才事件推入任务队列。
requestAnimationFrame
是浏览器用于定时循环操做的一个接口,相似于setTimeout,主要用途是按帧对网页进行重绘。requestIdleCallback()
经常使用来切割长任务,利用空闲时间执行,避免主线程长时间阻塞。
for...of 不仅是用来遍历数组的,只要有iterator
接口的数据结构均可以用它来遍历。一个数据结构只要部署了Symbol.iterator
属性,就被视为具备 iterator
接口。iterator
的实现思想来源于 单向链表
。
关键词:
iterator
,Symbol.iterator
, 单向链表。详细分析请看 《for...of原理解析》
function makeIterator(array) { var nextIndex = 0; return { next: function() { return nextIndex < array.length ? { value: array[nextIndex++], done: false } : { value: undefined, done: true }; } }; } const it = makeIterator(['a', 'b']); it.next() // { value: "a", done: false } it.next() // { value: "b", done: false } it.next() // { value: undefined, done: true } 复制代码
详细分析请看 《for...of原理解析》
暂停执行(yield)
和恢复执行(next)
函数体内外的数据交换
(next
返回值的value
,是向外输出
数据,next
方法的参数
,是向内输入
数据)和错误处理机制
(Generator 函数内部还能够部署错误处理代码,捕获函数体外抛出的错误)更多请查看 Generator函数详解》
给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。
若是你最多只容许完成一笔交易(即买入和卖出一支股票),设计一个算法来计算你所能获取的最大利润。
注意你不能在买入股票前卖出股票。
示例 1:
输入: [7,1,5,3,6,4] 输出: 5 解释: 在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。 注意利润不能是 7-1 = 6, 由于卖出价格须要大于买入价格。 复制代码
示例 2:
输入: [7,6,4,3,1] 输出: 0 解释: 在这种状况下, 没有交易完成, 因此最大利润为 0。 复制代码
答案: 买卖股票的最佳时机
给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。
设计一个算法来计算你所能获取的最大利润。你能够尽量地完成更多的交易(屡次买卖一支股票)。
注意:你不能同时参与多笔交易(你必须在再次购买前出售掉以前的股票)。
示例 1:
输入: [7,1,5,3,6,4] 输出: 7 解释: 在第 2 天(股票价格 = 1)的时候买入,在第 3 天(股票价格 = 5)的时候卖出, 这笔交易所能得到利润 = 5-1 = 4 。 随后,在第 4 天(股票价格 = 3)的时候买入,在第 5 天(股票价格 = 6)的时候卖出, 这笔交易所能得到利润 = 6-3 = 3 。 复制代码
示例 2:
输入: [1,2,3,4,5] 输出: 4 解释: 在第 1 天(股票价格 = 1)的时候买入,在第 5 天 (股票价格 = 5)的时候卖出, 这笔交易所能得到利润 = 5-1 = 4 。 注意你不能在第 1 天和第 2 天接连购买股票,以后再将它们卖出。 由于这样属于同时参与了多笔交易,你必须在再次购买前出售掉以前的股票。 复制代码
示例 3:
输入: [7,6,4,3,1] 输出: 0 解释: 在这种状况下, 没有交易完成, 因此最大利润为 0。 复制代码
答案: 《买卖股票的最佳时机》
将两个有序链表合并为一个新的有序链表并返回。新链表是经过拼接给定的两个链表的全部节点组成的。 示例:
输入:1->2->4, 1->3->4 输出:1->1->2->3->4->4 复制代码
答案:合并两个有序链表
给定一个整数数组 nums ,找到一个具备最大和的连续子数组(子数组最少包含一个元素),返回其最大和。 示例:
输入: [-2,1,-3,4,-1,2,1,-5,4], 输出: 6 解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。 复制代码
答案:最大子序和
从扑克牌中随机抽5张牌,判断是否是一个顺子,即这5张牌是否是连续的。2~10为数字自己,A为1,J为11,Q为12,K为13,而大、小王为 0 ,能够当作任意数字。A 不能视为 14。
示例 1: 输入: [1,2,3,4,5] 输出: True 示例 2: 输入: [0,0,1,2,5] 输出: True 复制代码
限制: 1.数组长度为 5 2.数组的数取值为 [0, 13] .
答案:扑克牌中的顺子
给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。
示例 1:
输入: "abcabcbb" 输出: 3 解释: 由于无重复字符的最长子串是 "abc",因此其长度为 3。 复制代码
示例 2:
输入: "bbbbb" 输出: 1 解释: 由于无重复字符的最长子串是 "b",因此其长度为 1。 复制代码
示例 3:
输入: "pwwkew" 输出: 3 解释: 由于无重复字符的最长子串是 "wke",因此其长度为 3。请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。 复制代码
答案:无重复字符的最长子串
最新发起了一个100天前端进阶计划,致力于弄明白每一个知识点背后的原理。这是第一周的总结,原本想直接粘贴一下原先的标题并附上原文连接。后来想仍是找几道关于本周内容的一些面试题(大部分为原文中的例子),方便检测一下本身的掌握程度。一共21道,看看本身能得几分。算法题最多要在半个小时以内写出最优解,上面提供的答案并必定是最好的,若是有问题或者更好的解法欢迎你们留言指出。或者你最新碰到的相似的面试题,也能够提供给我进行补充。
最近发起了一个100天前端进阶计划,主要是深挖每一个知识点背后的原理,欢迎关注 微信公众号「牧码的星星」,咱们一块儿学习,打卡100天。