JS基础+WEBAPI
1、js中基本数据类型和复杂数据类型有哪些,其中检测对应的数据类型的方法有哪些?
基本数据类型
string、number、boolean、null、nudefined、symbol(es6新增)
检测数据类型方法: typeof、Object.prototype.toString.call()
复杂数据类型
object、function、array
检测数据类型方法:
typeof: 只能正确检测出function,检测其他复杂数据类型返回的都是object
instanceof: 是通过原型链的方式判断数据类型)
Array.isArray(): 判断某个值是否为数组)
Object.prototype.toString.call(): 返回当前方法的执行主体【方法中的this】所属类的详细信息,返回值的类型为string类型
2、请说出return,break,continue的区别和用法
-
continue
continue:中止本次循环,继续下次循环。continue以后的循环体中的语句不会继续执行,下次循环继续执行,循环体外面的会执行
continue语句只用在for、while、do-while等循环体中,常与if条件语句一起使用,用来加速循环,其实就是continue跳过一次循环以及后面的语句,进行下次循环 -
break
break:直接结束一个循环,跳出循环体。break以后的循环体中的语句不会继续执行,循环体外面的会执行
break语句通常用在循环语句和开关语句中,当break语句用于do-while、for、while循环语句中时,可使程序终止循环而执行循环后面的语句, 通常break语句总是与if语句联在一起,即满足条件时便跳出循环
注意:
- break语句对if-else的条件语句不起作用。
- 在多层循环中, 一个break语句只向外跳一层
-
return
return:结束所在函数(无论是在多少层的嵌套下),return结束的是所在的函数,如果是函数套函数,结束的仅仅是最里层的函数
return语句是将函数的值返回
return后面不跟值,则直接终止该函数,返回的是undefined
3、请说出for…in…和for…of…的区别
for-in是ES5标准,遍历的是key(可遍历对象、数组或字符串的key)// 示例
const obj = {id:1,name:'jack',gender: 'man'}
var arr = ['a','b','c','d']
for (let key in obj) {
console.log(key) // id name gender
}
for (let key in arr) {
console.log(key) // 0 1 2 3
}
for-of是ES6标准,遍历的是value(可遍历数组或字符串的value)
// 示例
for (let key of obj) {
console.log(key) // Uncaught TypeError: obj is not iterable
}
for (let key of arr) {
console.log(key) // a b c d
}
- for in遍历的是数组的索引(即键名),而for of遍历的是数组元素值。
- for-in总是得到对象的key或数组、字符串的下标,不能直接进行几何运算。
- for-of总是得到数组、字符串的值,另外还可以用于遍历Map和Set
4、请说出JS的执行机制和栈,堆的区别和作用?
栈、堆
- 堆(heap)和栈(stack)
栈(stack)会自动分配内存空间,会自动释放。堆(heap)动态分配的内存,大小不定也不会自动释放。 - 基本类型和引用类型
基本类型:简单的数据段,存放在栈内存中,占据固定大小的空间。
引用类型:指那些可能由多个值构成的对象,保存在堆内存中,包含引用类型的变量实际上保存的不是变量本身,而是指向该对象的指针。 - 传值和传址
从一个向另一个变量复制引用类型的值,复制的其实是指针,因此两个变量最终指向同一个对象。即复制的是栈中的地址而不是堆中的对象。
从一个变量复向另一个变量复制基本类型的值,会创建这个值的副本。 - 堆和栈的大小
程序运行时,每个线程分配一个stack,每个进程分配一个heap,即stack是线程独占的,heap是线程共用的。此外,stack创建的时候,大小是确定的,数据超过这个大小,就发生stack overflow错误,而heap的大小是不确定的,需要的话可以不断增加。stack的限制大小可以采取递归的方式进行测试
JS的执行机制
js 中任务分为同步任务与异步任务
同步任务指的是,在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务;异步任务指的是,不进入主线程、而进入"任务队列"(task queue)的任务,只有"任务队列"通知主线程,某个异步任务可以执行了,该任务才会进入主线程执行。
异步执行的运行机制如下:
- 所有同步任务都在主线程上执行,形成一个执行栈(execution context stack)。
- 主线程之外,还存在一个"任务队列"(task queue)。只要异步任务有了运行结果,就在"任务队列"之中放置一个事件。
- 一旦"执行栈"中的所有同步任务执行完毕,系统就会读取"任务队列",看看里面有哪些事件。那些对应的异步任务,于是结束等待状态,进入执行栈,开始执行。
- 主线程不断重复上面的第三步。
5、请写出es5中常用的字符串的方法和数组的方法,数值的方法,?(不少于10个,必须写出数组,字符串之间相互转换的方法)
数组中常用的方法
方法 | 作用 |
---|---|
Array.isArray(arr) | 判断变量是不是一个数组 |
toString() | 把数组转换为字符串,使用逗号分隔 |
valueOf() | 返回数组对象本身 |
pop() | 返回数组中最后一个字,且会修改数组的长度 删除最后一个元素 |
shift() | 取出数组中的第一个元素,修改数组的长度 删除第一个元素 |
push() | 返回数组最新的长度,可以设置多个参数 依次往后追加元素 |
unshift() | 返回数组最新长度,可传多个参数 |
reverse() | 翻转数组 |
concat() | 把两个数组拼接到一块,返回一个新数组 |
slice(startindex, endindex) | 从当前数组中截取一个新的数组 第一个参数表示开始索引位置, 第二个参数代表结束索引位置 |
splice(startindex, deletCont, options) | 删除或者替换数组中的某些值 第一个参数代表从哪开始删除✔ 第二个参数代表一共删除几个✔ 第三个参数代表要替换的值 |
indexOf(content[index]) | 从头开始找找数组中的某个值, 找到返回索引位置, 如果没有找到返回 - 1 |
lastIndexof() | 从数组的末尾开始找数组中的某个值, 找到返回索引位置, 如果没有找到返回 - 1 |
join(‘字符’) | 将数组中的每一个元素通过给定字符链接为字符串 |
sort(function (a, b) | 数组排序【降序 return b - a,升序 return a - b】,默认按照字符的Unicode进行排序 |
filter((ele, i)=>{return true}) | 遍历数组,返回符合条件的值组成的新数组,参数为函数 |
forEach((ele, i)=>{}) | 遍历数组,ele 为数组内每一项,i为索引 |
some((ele, i)=>{‘条件’}) | 遍历数组,判断每一项是否符合函数给定条件,找到符合则返回true,仅返回一次, 否则返回false |
find((ele, i)=>{}) | 返回通过测试(函数内判断)的数组的第一个元素的值,没有符合条件的元素返回 undefined 空数组不执行,不改变原数组 |
map((ele, i)=>{}) | 返回一个新数组,数组中的元素为原始数组元素调用函数处理后的值 |
reduce((ele, i)=>{}) | 接收一个函数作为累加器,数组中的每个值(从左到右)开始缩减,最终计算为一个值 |
字符串中常用方法
方法 | 作用 |
---|---|
charAt(index) | 获取指定位置处的字符 |
charCodeAt(索引值) | 返回索引对应的字符的ASCII码 参数 索引 返回值:对应的字符的ASCii码 |
str[index] | 获取指定位置的字符 (H5中的方法) |
concat() | 拼接字符串 等效于 + |
slice(strat, end) | 从指定位置开始,截取字符串到结束位置,end值取不到 |
substring(start, end) | 从指定位置开始,截取字符串到结束位置, end值取不到 |
substr(start, length) | 从指定位置开始,截取length长度个字 字符串截取 |
indexOf(字符) | 返回字符在字符串中的位置【首次】 查找元素 未找到返回-1 |
lastIndexOf(字符) | 从后往前找,只找第一个匹配的字符【尾次 查找元素 未找到返回-1 |
trim() | 只能去除字符串前后空白 |
toLocaleUpperCase() | 转化为大写 |
toLocaleLowerCase() | 转化为小写 |
replace(a, b) | 用b替换a 字符串替换 第一个参数可为正则表达式,第二个参数可为函数 |
split() | 以一个分割符,将一个字符串串分割成一个数组 |
padStart(2,0) | 第一个参数为判断该字符串的长度,第二个参数为若该字符串长度不足2则在前面补0 |
padEnd(4,12) | 第一个参数为判断该字符串的长度,第二个参数为若该字符串长度不足4则在后面补12 |
JSON.parse() | 转换数据格式为对象格式 |
JSON.stringify() | 将数据转换为json字符串格式 |
6、请说出JS中内置对象有哪些,常用的是哪几个一般用来做什么操作
Math对象
Math.floor() 向下取整
Math.ceil() 向上取整
Math.random() 取0-1之间的随机小数
Math.round() 四舍五入
Date日期对象
new Date() 创建一个日期对象
getFullYear() 返回年份
getMonth() 返回月份数(0-11),想要得到几月,需要加一
getDay() 返回一周的第几天(0-6),想要得到星期几,需要加一
getDate() 返回日
7、函数的封装方式有哪些,如何定义一个函数,执行的方式有几种,如何实现了高内聚,低耦合?
函数封装方式
1.函数封装法:function aa(){}
2.封装成对象:let fn = {
f1(){},
f2(){},
…
}
3.封装成构造函数: function Fn(){}
4.类的方法: class Father {
constructor(){},
f1(){}
}
执行的方式
1.对象内的调用: obj.fn()
2.普通调用: fn()
3.递归调用:
fn(){
if(...) return
else {
return fn()
}
}
4.立即执行函数: ( function(){…} )() ( function (){…} () )
高内聚,低耦合
高内聚定义
1、确定要完成模块的功能点
2、除了完成本职功能外,不提供其他功能
3、要满足可读性、可扩展性、可复用、可维护性要求
4、向外提供服务时最好是面向接口编程
低耦合定义
1、要求模块之间的依赖、感知、连接尽量低
2、要求能适应变化,因为技术更新太快,但是思想上差不多
3、模块间的低耦合体现在不同模块的内部的高内聚要求,模块功能尽量独立
4、模块间的依赖尽量通过接口,对象组合优于继承
如何实现高内聚,低耦合
1、如何按功能进行模块化的分离。
2、对分离出来的模块化进行抽象,模块在设计时访问域的定义要划分好,防止因为访问域的定义而对模块的信息造成破坏
8、谈一谈你理解的arguments类数组对象,你一般用他来做什么操作,实现了什么功能
arguments存放用户传入函数的所有实参,它是内置对象,不需要声明直接使用(只能在函数内部使用)
arguments是伪数组,可按遍历数组的方式遍历里面的每个元素
9、请写出获取单个DOM元素和多个DDOM元素的方法,同时写出,如何给获取的DOM元素添加样式
通过ID获取(getElementById)
通过name属性(getElementsByName)
通过标签名(getElementsByTagName)// 可获取多个
通过类名(getElementsByClassName) // 可获取多个
通过选择器获取一个元素(querySelector)
通过选择器获取一组元素(querySelectorAll) // 可获取多个
获取html的方法(document.documentElement)
样式属性操作
- 修改单个CSS样式属性可使用 产生的是行内样式 Css权重较高 例: 元素.style.height = ‘200px’;
样式需采用驼峰命名法 比如 fontSize \ backgroundColor - 需要修改多个CSS样式属性,可使用添加或修改类名的方法
若要修改或添加多个CSS样式属性,可设置一个类名,类名书写样式,然后将类名添加到元素中 适用于多个样式或复杂的样式属性
10、请写出原生JS以及H5中操作自定义属性的方法(获取和自定义)
自定义属性操作
1、获取元素的属性值
元素.属性 用于获取元素自带的属性 或 element.getAttribute(‘属性’) 可用于获取我们自己添加的属性,即自定义属性
声明一个自定义属性
setAttribute(‘属性名’, 值)
移除一个自定义属性
removeAttribute(“属性的名字”) 移除自定义属性
//dataset是一个集合里面存放了所有以data开头的自定义属性 只能获取以data-开头的自定义属性
例如:
获取自定义属性 data-index = 1
可用 元素.dataset.index 或 元素.dataset[‘index’]
设置自定义属性
元素.dataset.text = 1 //设置了一个自定义属性为 data-text = 1
11、请写出节点操作,父节点,返回所有子节点,返回第一个子节点等方法,同时写出创建,添加节点的方法,并说出他在DOM中表达的意义
//父节点
parentNode // 可得到离元素最近的父级节点 如果找不到父节点就返回为空 null
//子节点
childNode // 得到所有的子节点,包含文本节点 和 元素节点 是一个集合
children // 返回所有子元素节点,其他节点不返回
firstChild // 返回第一个子节点 找不到则返回null,同样,也包含所有节点 不管是元素节点还是文本节点
lastChild // 返回最后一个子节点 找不到则返回null,同样,也包含所有节点 不管是元素节点还是文本节点
firstElementChild // 返回第一个子元素节点
lastElementChild // 返回最后一个子元素节点
//兄弟节点
nextSibling //获取下一个兄弟节点 包含文本节点 或元素节点
previousSibling //获取上一个兄弟节点 包含文本节点 或元素节点
nextElementSibling //获取下一个兄弟元素节点 若找不到则为空
previousElementSibling //获取上一个兄弟元素节点 若找不到则为空
//创建元素节点
var liv = document.createElement('li'); //创建了一个li
//添加节点
node.appendChild(
child
) //将一个节点添加到指定父节点的子节点列表 ‘末尾’ 类似Css中after伪元素 node父级 child子级
node.insertBefore(child, "指定元素") //将一个节点添加到指定父节点的子节点列表 ‘前面’ 类似Css中before伪元素 node父级 child子级
//删除节点
node.removeChild(child) //删除父节点中的某个子节点 node父级 child子级
//复制节点
node.cloneNode(); //使用方法: 父元素.children[0].cloneNode(); 将父元素中的第一个孩子复制,可赋值给一个变量,追加到页面中
//括号为空 或 里面是false,只复制标签,不复制里面的内容 ;
//若括号里面填写true, 可以复制标签,同时复制里面的内容
12、请写出你所知道的移动端的事件和PC端的常用的事件,并说出他们的区别
点击事件 click区别
在pc端是点击事件,但是在移动端是单击事件;
在移动端的项目中会区分单击做什么和双击做什么,所以移动端的浏览器在识别click的时候,只有确定是单击后才会把它执行;
在移动端使用click会存在300ms的延迟,浏览器在第一次点击结束后,还需要等到300ms看是否触发了第二次点击,如果触发了第二次点击就不属于click了,没有触发第二次点击才属于click
替换移动端的click事件: touch事件
touchstart 手指按到屏幕上
touchmove 手指在屏幕上滑动
touchend 手指离开屏幕
touchcancel 当触摸点被中断时会触发
pc端常用的事件:
click 当鼠标点击时触发
mouseover 当鼠标指针移动到元素上时触发
mouseout 当鼠标指针移出元素时触发
mouseenter 当鼠标指针移动到元素上时触发(不支持冒泡)
mouseleave 当鼠标指针移出元素上时触发(不支持冒泡)
mousemove 当鼠标指针移动到元素上时触发
mousedown 当元素上按下鼠标按钮时触发
mouseup 当在元素上释放鼠标按钮时触发
mousewheel 当鼠标滚轮正在被滚动时运行的脚本
keydown 在用户按下按键时触发
keyup 当用户释放按键时触发
load 页面结束加载之后触发
scroll 当元素滚动条被滚动时运行的脚本
blur 元素失去焦点时运行的脚本
focus 当元素获得焦点时运行的脚本
change 在元素值被改变时运行的脚本
移动端常用的事件:
click 当点击时触发(单击)
load 页面结束加载之后触发
scroll 当元素滚动条被滚动时运行的脚本
blur 元素失去焦点时运行的脚本
focus 当元素获得焦点时运行的脚本
change 在元素值被改变时运行的脚本
input 代替keyup、keydown
touch 事件模型 处理单手指操作
gesture 事件模型 处理多手指操作
13、请写出前端常用的储存方式和其用法,和常用的定时器的用法
// 延时器
setTimeout(函数,[延迟的毫秒数]) 只调用一次
// 定时器
setInterval(回调函数, [间隔的毫秒数]) 会重复调用
//停止 setTimeout setInterval定时器
clearTimeout(timeoutID / 定时器的名字)
本地存储
sessionStorage 和 localStorage
//获取: localStorage.getItem(键); sessionStorage.getItem(键);
//设置: localStorage.setItem(键,值); sessionStorage.setItem(键,值);
//移除: localStorage.removeItem(键); sessionStorage.removeItem(键);
//删除所有数据: localStorage.clear(); sessionStorage.clear();
sessionStorage 和 localStorage 区别
生命周期为关闭浏览器窗口 生命周期永久,除非手动删除否则关闭页面也会存在 在同一个页面(窗口)下数据可以共享 可以多窗口(页面)共享(同一浏览器可以共享)
以键值对的形式储存使用 以键值对的形式储存使用
14、请写出你所知道的键盘事件的常用方法以及location对象的常用的几种用法
localStorage
//获取: localStorage.getItem(键);
//设置: localStorage.setItem(键,值);
//移除: localStorage.removeItem(键);
//删除所有数据: localStorage.clear();
键盘事件
键盘事件 触发条件
onkeyup 某个键盘按键被松开时触发
onkeydown 某个键盘按键被按下时触发 按键按下不松时,会一直触发事件
onkeypress 某个键盘按键被按下时触发 但是它不识别功能键 比如 ctrl shift 箭头等 按键按下不松时,会一直触发事件
//三个事件执行顺序:先执行keydown 再执行keypress 最后执行keyup
//keypress和keydown 在文本框中的特点:他们两个事件触发的时候,文字还没有落在文本框 中 先触发程序,文字还未落在文本框中,无法取到值
//keyup事件触发的时候,文字已经落入文本框中了
键盘事件对象 keyCode 返回该键的ASCII值
组合键
altkey 判断是否按下alt键 常用于实现组合键 效果
shiftkey 判断是否按下shift键 常用于实现组合键 效果
ctrlkey 判断是否按下ctrl键 常用于实现组合键 效果
15、请说出DOM事件委托的原理有什么优缺点,以及js事件流模型是什么
DOM事件委托原理: 不给每个子节点单独设置事件监听器,而是事件监听器设置在其父节点上,然后利用冒泡原理影响设置每个子节点。
案例:给ul注册点击事件,然后利用事件对象的target来找到当前点击的li,因为点击li,事件就会冒泡到li上,ul有注册事件,就会触发事件监听器
作用:只操作了一次DOM,提高了程序的性能
例:
ul.addEventListener('click', function (e) {
//可以使ul中当前点击的li的背景颜色改为pink色
e.target.style.backgroundColor = 'pink';
})
JS事件流模型
-
事件冒泡(fasle/不写):当触发一个节点的事件是,会从当前节点开始,依次触发其祖先节点的同类型事件,直到DOM根节点。
-
事件捕获(true):当初发一个节点的事件时,会从DOM根节点开始,依次触发其祖先节点的同类型事件,直到当前节点自身。
-
什么时候事件冒泡?什么时候事件捕获?
① 当使用addEventListener绑定事件,第三个参数传为true时表示事件捕获;
② 除此之外的所有事件绑定均为事件冒泡。 -
阻止事件冒泡:
① IE10之前,e.cancelBubble = true;
② IE10之后,e.stopPropagation(); -
阻止默认事件:
① IE10之前:e.returnValue = false;
② IE10之后:e.preventDefault();
除onblur、onfocus、onmouseenter、onmouseleave事件外,其它事件都有冒泡或捕获阶段,当父元素,子元素都有事件时,若点击子元素时,不触发父元素上的事件,需要阻止冒泡,父元素上的事件,则会点击除子元素外的父元素部份时触发
16、请说出JS中你遇到的兼容性问题,不少于3个
js中的一些兼容性问题:
1)获取滚动高度:
document.documentElement.scrollTop||document.body.scrollTop
2)获取样式兼容:
window.getComputedStyle(element)[styleName] 支持IE9及以上版本
解决方法:
function getStyle(dom, styleName){
return dom.currentStyle ? dom.currentStyle[styleName] : getComputedStyle(dom)[styleName];
}
3)事件对象兼容
window.event只能在IE下运行,而不能在Firefox下运行,这是因为Firefox的event只能在事件发生的现场使用。Firefox必须从源处加入event作参数传递。IE忽略该参数,用window.event来读取该event。
解决方法:
event = event || window.event;
4)event.pageX和event.pageY:获取鼠标相对于整个文档的水平及垂直坐标
event.pageX和event.pageY,IE9之前的版本不支持
解决方法:
event.clientX+(document.documentElement.scrollLeft||document.body.scrollLeft);
event.clientY+(document.documentElement.scrollTop||document.body.scrollTop);
5) 阻止事件冒泡兼容
stopPropagation() 和 cancelBubble,前者是方法,是标准的写法,后者是属性,赋值true表示阻止,是IE的写法。
解决方法:
判断stopPropagation是否存在,如果存在则用标准写法否则则用IE的写法,不可反过来判断。
event.stopPropagation ? event.stopPropagation() : event.cancelBubble=true;
6)阻止默认行为兼容
preventDefault()和returnValue()前者标准写法,后者IE写法。
解决方法:
常规方法
event.preventDefault?event.preventDefault():event.returnValue=false;
非常规方法:直接在事件处理程序中return false;
17、cookie在浏览器中是如何储存的,如何处理安全性问题,防止攻击,禁止获取cookie?
// Cookie的存储位置:
内存cookie,是指没有设在cookie的Expires的属性,此时cookie将停留在客户端的内存中。
硬盘cookie,是指设置了cookie的Expires属性,此时cookie将保存到硬盘上。
// 安全性问题处理
一、对保存到cookie里面的敏感信息必须加密
二、设置HttpOnly为true
1、该属性值的作用就是防止Cookie值被页面脚本读取。
2、但是设置HttpOnly属性,HttpOnly属性只是增加了攻击者的难度,Cookie盗窃的威胁并没有彻底消除,因为cookie还是有可能传递的过程中被监听捕获后信息泄漏。
三、设置Secure为true
1、给Cookie设置该属性时,只有在https协议下访问的时候,浏览器才会发送该Cookie。
2、把cookie设置为secure,只保证cookie与WEB服务器之间的数据传输过程加密,而保存在本地的cookie文件并不加密。如果想让本地cookie也加密,得自己加密数据。
四、给Cookie设置有效期
1、如果不设置有效期,万一用户获取到用户的Cookie后,就可以一直使用用户身份登录。
2、在设置Cookie认证的时候,需要加入两个时间,一个是“即使一直在活动,也要失效”的时间,一个是“长时间不活动的失效时间”,并在Web应用中,首先判断两个时间是否已超时,再执行其他操作。
18、重排和重绘在页面中代表什么意思,你是如何去理解的?
当DOM的变化引发了元素几何属性的变化,比如改变元素的宽高,元素的位置,导致重新计算元素的几何属性,并重新构建渲染DOM,这个过程称为“重排”。完成重排后,要将重新构建的DOM渲染到屏幕上,这个过程就是“重绘”。
重排负责元素的几何属性更新,重绘负责元素的样式更新。而且,重排必然带来重绘,但是重绘未必带来重排