Js的基础知识为了react和webpack
为了react和webpack, 需要搞很多内容, 比如webcomponent和proxy
基础中的基础
直接阅读英文原版吧, 中文翻译让人看不懂: https://medium.com/dev-bits/a-perfect-guide-for-cracking-a-javascript-interview-a-developers-perspective-23a5c0fa4d0d
console.log(square(5));
var square = function(n) {
return n * n;
}
//这个会报错, 因为这种形式square并没有被提升上去. function xxx()={}才会提升
-
闭包是js封装的基础, 为了避免全局变量污染.
-
apply和call的第一个参数是上下文, 可以理解为this.
-
bind只有个一个参数上下文, 作用和上面一致.
-
对象是键值对, 值的范围很宽泛, 函数也没有问题的.
-
但是, get和set的语法很神奇, 并没有冒号. define property, https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty
-
object上面的一堆方法和属性要熟悉. js安排了很多静态方法和静态属性再上面.
-
正则, 这个虽然我熟悉, 但是可以参考: http://www.rexegg.com/regex-quickstart.html
-
map reduce filter
var arr = [[1, 2], [3, 4], [5, 6]]; var flattenedArray = arr.reduce((accumulator, currentValue) => { return accumulator.concat(currentValue); }, []); // returns [1, 2, 3, 4, 5, 6] flattenedArray;// [1, 2, 3, 4, 5, 6];
事件操作我还没有入门
这一篇的翻译还是不错的: https://segmentfault.com/a/1190000018257074
非常难得的是这个翻译结合了原文中的几个引文, 做了整体的翻译.
https://medium.freecodecamp.org/3-questions-to-watch-out-for-in-a-javascript-interview-725012834ccb
- 直接绑定, 这个案例写的也比我写的高效, 直接拿到了元素数组.
- 事件委托, 这个更合理了. 事件就绑定再父元素上面, 然后用e.target来处理.
//直接绑, 会有问题, 页面上面绑了太多的事件.
document.addEventListener('DOMContentLoaded', function() {
let app = document.getElementById('todo-app');
let itimes = app.getElementsByClassName('item');
for (let item of items) {
item.addEventListener('click', function(){
alert('you clicked on item: ' + item.innerHTML);
})
}
})
//委托的写法
document.addEventListener('DOMContentLoaded', function() {
let app = document.getElementById('todo-app');
app.addEventListener('click', function(e) {
if (e.target && e.target.nodeName === 'LI') {
//还可以使用element.matches语法
let item = e.target;
alert('you clicked on item: ' + item.innerHTML)
}
})
})
闭包和let我也没有入门
//下面两段代码等效
const arr = [10, 12, 15, 21];
for (var i = 0; i < arr.length; i++) {
// pass in the variable i so that each function
// has access to the correct index
setTimeout(function(i_local) {
return function() {
console.log('The index of this number is: ' + i_local);
}
}(i), 3000);
}
for (let i = 0; i < arr.length; i++) {
// using the ES6 let syntax, it creates a new binding
// every single time the function is called
// read more here: http://exploringjs.com/es6/ch_variables.html#sec_let-const-loop-heads
setTimeout(function() {
console.log('The index of this number is: ' + i);
}, 3000);
}
事件如果频繁触发, 比如滚动这种就会造成抖动. 所以需要下面两个技术:
- throttle 节流
- debounce 防抖
// fn是我们需要包装的事件回调, interval是时间间隔的阈值
function throttle(fn, interval) {
// last为上一次触发回调的时间
let last = 0
// 将throttle处理结果当作函数返回
return function () {
// 保留调用时的this上下文
let context = this
// 保留调用时传入的参数
let args = arguments
// 记录本次触发回调的时间
let now = +new Date()
// 判断上次触发的时间和本次触发的时间差是否小于时间间隔的阈值
if (now - last >= interval) {
// 如果时间间隔大于我们设定的时间间隔阈值,则执行回调
last = now;
fn.apply(context, args);
}
}
}
// 用throttle来包装scroll的回调
const better_scroll = throttle(() => console.log('触发了滚动事件'), 1000)
document.addEventListener('scroll', better_scroll)
// fn是我们需要包装的事件回调, delay是每次推迟执行的等待时间
function debounce(fn, delay) {
// 定时器
let timer = null
// 将debounce处理结果当作函数返回
return function () {
// 保留调用时的this上下文
let context = this
// 保留调用时传入的参数
let args = arguments
// 每次事件被触发时,都去清除之前的旧定时器
if(timer) {
clearTimeout(timer)
}
// 设立新定时器
timer = setTimeout(function () {
fn.apply(context, args)
}, delay)
}
}
// 用debounce来包装scroll的回调
const better_scroll = debounce(() => console.log('触发了滚动事件'), 1000)
document.addEventListener('scroll', better_scroll)
两个方案由各自的问题:
- debounce有一点问题, 如果用户一直频繁操作, 我们安排的响应就一直不出现. 这个也会让用户有功能失灵的感觉.
- throttle的问题是, 反应会比较迟钝, 我已经不滚动了, 但是还是要1s之后才有反应, 我们知道一般用户的期望响应时间是0.2s. 对于电竞职业选手反应时间会更短.
解决方案就是结合起来, 比如:
- 1s之内只要debounce能生效就让他生效,
- 如果debounce拖过了1s, 那么throttle作为底线每秒也会给用户一个反馈.
// fn是我们需要包装的事件回调, delay是时间间隔的阈值
function throttle(fn, delay) {
// last为上一次触发回调的时间, timer是定时器
let last = 0, timer = null
// 将throttle处理结果当作函数返回
return function () {
// 保留调用时的this上下文
let context = this
// 保留调用时传入的参数
let args = arguments
// 记录本次触发回调的时间
let now = +new Date()
// 判断上次触发的时间和本次触发的时间差是否小于时间间隔的阈值
if (now - last < delay) {
// 如果时间间隔小于我们设定的时间间隔阈值,则为本次触发操作设立一个新的定时器
clearTimeout(timer)
timer = setTimeout(function () {
last = now
fn.apply(context, args)
}, delay) //这里不对, 这个delay如果和前面的判断条件的delay一致, 那么, 每次都会执行下面的策略, 并不合理. 比如delay 1s, 每次都是超过1s才会有反馈, 不论用户多快的停止操作.
} else {
// 如果时间间隔超出了我们设定的时间间隔阈值,那就不等了,无论如何要反馈给用户一次响应
last = now
fn.apply(context, args)
}
}
}
// 用新的throttle包装scroll的回调
const better_scroll = throttle(() => console.log('触发了滚动事件'), 1000)
document.addEventListener('scroll', better_scroll)
再次感谢原作, 真的很用心的翻译: https://segmentfault.com/a/1190000018257074
那么问题来了, 这个能用promise/await/async写法重写吗?