61.作用域的分类
参考答案:块作用域、词法作用域、动态作用域
解析:
1 块作用域 花括号 {}
2 词法作用域(js 属于词法作用域) 作用域只跟在何处被创建有关系,跟在何处被调用没有关系
3 动态作用域 作用域只跟在何处被调用有关系,跟在何处被创建没有关系
参与互动
62.js 属于哪种作用域
参考答案:词法作用域(函数作用域)
解析:
参与互动
63.浮点数精度
参考答案:参考
参与互动
64.自执行函数? 用于什么场景?好处?
参考答案:
好处:防止变量弥散到全局,以免各种 js 库冲突。隔离作用域避免污染,或者截断作用域链,避免闭包造成引用变量无法释放。利用立即执行特性,返回需要的业务函数或对象,避免每次通过条件判断来处理
场景:一般用于框架、插件等场景
参与互动
65.多个页面之间如何进行通信
参考答案:有如下几个方式:
参与互动
66.css 动画和 js 动画的差异
参考答案:
1.代码复杂度,js 动画代码相对复杂一些 2.动画运行时,对动画的控制程度上,js 能够让动画,暂停,取消,终止,css 动画不能添加事件 3.动画性能看,js 动画多了一个 js 解析的过程,性能不如 css 动画好
解析:参考
参与互动
67.如何做到修改 url 参数页面不刷新
参考答案:
HTML5 引入了 history.pushState() 和 history.replaceState() 方法,它们分别可以添加和修改 历史 记录条目。
假设当前页面为 foo.html ,执行上述代码后会变为 bar.html ,点击浏览器后退,会变为 foo.html ,但浏览器并不会刷新。 pushState() 需要三个参数: 一个状态对象, 一个标题 (目前被忽略), 和 (可选的) 一个 URL.让我们来解释下这三个参数详细内容:
参与互动
68.数组方法 pop() push() unshift() shift()
参考答案:
参与互动
69.事件绑定与普通事件有什么区别
参考答案:
参与互动
70.IE 和 DOM 事件流的区别
参考答案:
1.事件流的区别
IE 采用冒泡型事件 Netscape 使用捕获型事件 DOM 使用先捕获后冒泡型事件 示例:
复制代码代码如下:
冒泡型事件模型: button->p->body (IE 事件流)
捕获型事件模型: body->p->button (Netscape 事件流)
DOM 事件模型: body->p->button->button->p->body (先捕获后冒泡)
2.事件侦听函数的区别
IE 使用:
DOM 使用:
bCapture 参数用于设置事件绑定的阶段,true 为捕获阶段,false 为冒泡阶段。
参与互动
1.eventLoop
2.setTimeout 误差原因
3.深浅拷贝
4.跨域原因及解决方案
5.css放在头部,js放在尾部
6.css触发bfc
7.webpack plugin和loader区别
8.前端优化
9.协商缓存
10.长列表优化
11.webview交互
12.vue响应式原理
13.原型
14.算法题:数组中有n个元素,排列
EventLoop是计算机系统的运行机制,js就是运行这个机制,因为js是单线程语言,所以一旦遇到一个耗时很长的任务就会卡住,js为了解决这个问题就有了EventLoop
Event Loop是一个程序结构,用于等待和发送消息和事件。
就是在程序中有了两个线程,一个负责应用本身,主线程,另一个负责主线程和其它进程,称为EventLoop
1、js是单线程语言
基本数据类型存放在栈中的简单数据段
引用数据类型存放在堆中的对象
因为定时器是宏任务,如果执行栈的时间大于定时器花费的时间,那么定时器的回调在 宏任务(macrotask) 里,来不及去调用,所有这个时间会有误差。所以就会有误差
宏任务是宿主发起的比如script,setTimeout
css放在头部是因为页面加载html生成dom树的时候就可以同时对dom树进行渲染,防止闪跳,白屏
js放在尾部是因为js会修改dom树,需要一个稳定的dom树
BFC是css的一个布局概念,块级格式化上下文
浮动float不为none的时候
定位为position:absolute和fixed的
display的时候
overflow不为visible
解决浮动父元素坍塌问题
解决自适应布局的问题
解决外边距垂直方向重合问题
loader是文件加载器,运行在nodejs中,并对文件进行打包,压缩转换
plugin是插件,用于拓展webpack的功能
浅拷贝有两种定于,第一种是赋值,第二种是拷贝对象的第一层属性,深层还是一样的
深拷贝是指将对象拷贝一份,无论如何修改都不会改变原有的
响应式原理就是当数据发生改变的时候视图也会跟着更新
VUE是利用了Object.defineProperty的方法里面的setter 与getter方法的观察者模式来实现。
场景:var str = “hello world!”
a.str.char() //返回指定下标的值
Str.char(2) //”l”
b.Str.indexOf() //返回指定值的下标
Str.indexOf(‘e’) //’1’
c.Str.lastIndexOf() //返回最后指定值的下标
Str.lastIndexOf(‘l’) //’9’
d.Str.concat() //拼接字符串
Str.concat(“mother fuck!”) //”hello world!mother fuck!”
Console.log(str) //”hello world!”
e.Str.substr(n,m) //从n开始截取m个字符
Str.substr(1,2) //’el’
f.Str.substring(n,m) //从n开始m结束截取字符串,不包含m
Str.substring(6,11) //”world”
g.Str.slice(n,m) //同substring,slice可以截取数组,substring不能截取数组
Str.slice(6,11) //”world”
h.Str.split //返回数组
Str.split(‘ ’) //[‘hello’, ‘world!’]
Str.aplit(‘l’) //[‘he’, ‘’, ‘o wor’, ‘d!’]
i.Str.replace() //以下三个方法都是通过正则表达式对原字符串进行更改的
j.Str.match()
k.Str.search()
场景:const obj = {x: 0, y: 1}
Const obj2 = {x: 1, z: 2,fn: {number: 1}}
a.Object.assign() //合并对象,实行的是浅拷贝
Object.assign(obj, obj2)
Console.log(obj) //{x: 1, y: 1, z: 2,fn: {number: 1}}
b.Object.create() //新建一个对象,可以使用原型链继承
Var newObj = Object.create(obj, {newValue: ‘newAdd’})
Console.log(newObj) //{newValue: ‘newAdd’}
Console.log(newObj.x) //0
c.Object.defineProperties() //往对象里面添加或修改新属性,值类型
Object.defineProperties(obj, {name: {value: ‘欧’}}) //添加属性
Console.log(obj) //{x: 0, y: 1, name: ‘欧’}
Object.defineProperties(obj, {name: {value: ‘林’, writable: true}}) //修改属性
Console.log(obj) //{x: 0, y: 1, name: ‘林’}
d.Object.defineProperty() //往对象里面添加新属性,可以是引用类型
Object.defineProperty(obj, ‘name’, {value: function() {return ‘欧’}})
Console.log(obj.name()) //’欧’
e.Object.keys() //返回对象所有key,以数组类型输出
Console.log(Object.keys(obj)) //[‘x’, ‘y’]
f.Object.values() //返回对象所有的value,以数组类型输出
Console.log(Object.values(obj)) //[0, 1]
场景:var arr = new array(1,2,3)
a.push() //向数组尾部添加元素
arr.push(4)
console.log(arr) //[1,2,3,4]
b.unshift() //向数组头部添加元素
arr.unshift(0)
console.log(arr) //[0,1,2,3]
c.pop() //删除数组尾部的元素
arr.pop()
console.log(arr) //[1,2]
d.shift() //删除数组头部的元素
arr.shift()
console.log(arr) //[2,3]
e.indexOf() //返回指定元素的下标
arr.indexOf(2) //1
f.slice(n,m) //从n开始m结束截取数组,不包括m,此方法不会更改元数组
console.log(arr.slice(1,2)) // [2]
console.log(arr) //[1,2,3]
g.splice() //删除数组指定元素
arr.splice(1) //删除从下标1开始到最后的所有元素
console.log(arr) //[1]
arr.splice(1,2) //删除从下标1开始往后的2个元素
console.log(arr) //[1]
arr.splice(1,2,3,4) //删除从下标1开始往后2个元素并用3,4替代
console.log(arr) //[1,3,4]
h.reverse() //数组翻转
arr.reverse()
console.log(arr) //[3,2,1]
i.sort() //从小到大排序数组
arr.sort()
console.log(arr) //[1,2,3]
j.forEach() //以下提供了几种遍历的方法
k.map()
l.filter() //数组过滤,如果数组的元素的对象,可以通过对象的属性名来过滤元素,用法跟C#的Linq一样。
var newArr = [{id:1,name:’元素1’},{id:2,name:’元素2’}]
console.log(newArr.filter(item =>item.id===1)) //[{id:1,name:’元素1’}]
console.log(newArr) //[{id:1,name:’元素1’},{id:2,name:’元素2’}]
m.every()
n.some()
o.find()
p.findIndex()
增删改查
场景:<div class=”div” id=”div”></div>
a.document.createElement() //创建节点
var newDiv = document.createElement()
b.document.craeteTextNode() //创建文本节点
var newDivText = document.craeteTextNode(‘这是新创建的节点’)
c.div.appendChild() //向节点添加最后一个子节点
newDiv.appendChild(newDivText)
d.document.getElementById() //通过Id获取节点
var div = document.getElementById(‘div’)
e.div.parentNode //获取父节点
f.div.childNode //获取子节点,返回一个集合
var child = div.childNodes
g.div.nextSibling,div.previousSibling,div.firstChild,div.lastChild
分别为,获取下一个兄弟节点,上一个兄弟节点,第一个子节点,最后一个子节点。
h.div.insetBefore() //插入到特定位置
div.insetBefore(newDiv, null) //插入到最后,跟appendchild用法一样
div.insetBefore(newDiv, div.firstChild) //插入到第一个子节点之前
div.insetBefore(newDiv, div.lastChild) //插入到最后节点之前
i.div.replaceChild() //替换节点
div.replaceChild(newDiv, div.firstChild) //替换第一个子节点,原节点会被删除
j.div.removeChild() //删除子节点
k.cloneNode(true/false) //克隆节点,true为深克隆,false为浅克隆
l.document.querySelector(),document.querySelectorAll() //通过css选择器搜索匹配的节点,querySelector返回匹配的第一个节点,querySelectorAll返回所有节点
document.querySelector(‘div.div’) //返回class为div的div标签节点
document.querySelector(‘#div’) //返回id为div的节点
m.document.getElementsByTagName(),document.getElementsByName(),document.getElementsByClassName() //返回符合需求的集合
n.div.setAttribute() //给元素添加属性
div.setAttribute(‘name’: ‘div’)
o.removeAttribute(),getAttribute(),hasAttribute() //各种操作属性的方法