JS面试题
//经典面试题
async function async1 () {
console.log('async1 start') //2
//await后面都是回调内容--微任务
await async2() // 这一句会同步执行,返回 Promise ,其中的 `console.log('async2')` 也会同步执行
console.log('async1 end') //6 上面有 await ,下面就变成了“异步”,类似 cakkback 的功能(微任务)
}
async function async2 () {
console.log('async2')//3
}
console.log('script start')//1
setTimeout(function () { // 异步,宏任务
console.log('setTimeout')//8
}, 0)
async1()
//初始化promise时,传入的函数会立刻被执行
new Promise (function (resolve) { // 返回 Promise 之后,即同步执行完成,then 是异步代码
console.log('promise1') //4 Promise 的函数体会立刻执行
resolve()
}).then (function () { // 异步,微任务
console.log('promise2')//7
})
console.log('script end')//5
// 同步代码执行完之后,屡一下现有的异步未执行的,按照顺序
// 1. async1 函数中 await 后面的内容 —— 微任务
// 2. setTimeout —— 宏任务
// 3. then —— 微任务
//除了宏任务和微任务其他都是同步的
从JS基础知识到JS Web API
- JS基础知识,规定语法(ECMA 262标准)
- JS Web API,网页操作的API(w3c标准)
- 前者是后者的基础,两者结合才能真正实际应用
JS基础知识
- 变量类型计算
- 原型和原型链
- 作用域和闭包
JS Web API
- DOM
- BOM
- 事件绑定
- ajax
- 存储
前言
- vue和React框架应用广泛,封装了DOM操作
- 但是DOM操作一直都是前段工程师的基础,必备知识
- 只会vue而不会DOM操作的前端程序员,不会长久
题目
- DOM是那种数据结构
- dom树
- DOM操作常用的API
- attr 和 property 的区别?
- attr对dom结构的节点的属性修改,修改html属性,会改变html结构
- property对js变量修改,修改对象属性值,不会体现到html中
- property 和 attribute 都可能引起dom重新渲染,优选property
- 一次性插入多个DOM节点,考虑性能
- dom节点缓存
- fragment
知识点
-
dom本质
- 从html文件解析出来的树
-
dom节点操作
-
获取dom节
-
attribute
- 对dom结构的节点的属性修改,修改html属性,会改变html结
-
property
- 对js变量修改,修改对象属性,不会体现到html
-
property 和 attribute 都可能引起dom重新渲染,优选property
-
9-3
-
dom结构操作
-
新增/插入节
-
获取子元素列表,获取父元素列表
-
利用nodeType检查文本元素还是普通dom节点
-
如果节点是一个元素节点,nodeType 属性返回 1。
-
如果节点是属性节点, nodeType 属性返回 2。
-
如果节点是一个文本节点,nodeType 属性返回 3。
-
-
删除子元素
-
dom性能
-
dom操作非常‘昂贵’,避免频繁的dom操作
-
对dom查询做缓存
-
for循环中如果条件是需要对
dom
的length
进行计算,那就要把dom
的length
计算写在for循环外边,定义一个新的变量保存,然后在for
循环中使用这个自己定义的变量,可以避免因多次dom
查询带来的性能消
-
-
将频繁操作改为一次性操作
- 如要创建多个新的
dom
挂到原有的dom
节点上,可以先通过document.createDocumentFragment()
创建一个文档片段,然后再把新创建的节点通过for
循环和appendChild
添加到文档片段上,最后将文档片段通过appendChild
插入到最初指定的dom节点
- 如要创建多个新的
-
BOM操作
题目
- 如何识别浏览器的类型
- 分析拆解url各个部分
知识点:
-
navigator
- userAgent: 属性是一个只读的字符串,声明了浏览器用于 HTTP 请求的用户代理头的值。
-
scree
-
location
-
histor
事件
题目
-
编写一个通用的事件监听函数
-
描述事件冒泡的流程
- 基于dom树形结构
- 事件会顺着触发元素往上冒泡
- 应用场景:代理
-
无限下拉的图片列表,如何监听每个图片的点击?
-
事件代理
-
用e.target获取触发元素
-
用matches来判断是否触发元素
<button id="btn1">一个按钮</button> <div id="div3"> <a href="#">a1</a><br> <a href="#">a2</a><br> <a href="#">a3</a><br> <a href="#">a4</a><br> <button>加载更多...</button> </div> function bindEvent(elem, type, selector, fn) { console.log(selector); console.log(fn); if (fn == null) { fn = selector; selector = null } elem.addEventListener(type, event => { const target = event.target; console.log(target); if (selector) { // 代理绑定 if (target.matches(selector)) { fn.call(target, event) } } else { // 普通绑定 fn.call(target, event) } }) } // 普通绑定 const btn1 = document.getElementById('btn1') bindEvent(btn1, 'click', function (event) { // console.log(event.target) // 获取触发的元素 event.preventDefault() // 阻止默认行为 alert(this.innerHTML) }) // 代理绑定 const div3 = document.getElementById('div3') bindEvent(div3, 'click', 'a', function (event) { event.preventDefault() alert(this.innerHTML) })
-
知识点
-
事件绑定
//通用事件绑定函数 function bindEvent(elem,type,fn){ elem.addEventListener(type,fn); } const btn1 = document.getElementById('btn1'); bindEvent(btn1,'click',event=>{ event.preventDefault() alert('clicked') })
-
事件冒泡
<style> #div1 { width: 400px; height: 400px; background-color: red; } #div2 { width: 100px; height: 100px; background-color: pink; } </style> </head> <body> <div id="div1"> div1 <div id="div2">div2</div> </div> <a href="http://www.baidu.com" id="baidu">百度</a> <script> baidu.onclick = function (e) { //window.event 兼容ie let ev = window.event || e; if (ev.preventDefault){ ev.preventDefault(); } else{ //兼容ie ev.cancelValue = false; } }; div1.onclick = function () { alert(1); }; div2.onclick = function (e) { alert(2); let ev = window.event || e; if (ev.stopPropagation) { ev.stopPropagation(); } else { //兼容ie ev.cancelable; } //stopPropagation w3c标准浏览器 //ie 非w3c标准 } </script>