1 事件捕获和事件冒泡
事件流: 当一个HTML元素产生一个事件时,该事件会在元素节点与根节点之间的路径传播,路径所经过的节点都会收到该事件,这个传播的过程叫做DOM事件流
事件冒泡正如其名,向鱼类吐泡泡一样。当点击上面div时,最先接收到click事件的是div元素本身。因为它是文本中当前所交互的元素里嵌套最深的那个元素。随后沿着DOM树一路往上到body,到html,到document为止。
事件捕获中最先获取交互事件的时document,再然后是沿着DOM树一直往下直到作为目标的所交互元素。
所有现代浏览器都支持事件冒泡。
DOM2级事件规定了事件流的三个阶段:事件捕获阶段、处于目标阶段、事件冒泡阶段。
三个阶段的作用分别是:提供拦截事件的机会,实际的目标接收到事件,对事件做出响应。
在事件捕获阶段中,事件本身不会接触到目标元素。但是在事件处理过程中,处于目标阶段会被视为冒泡阶段的一部分。另外DOM2明确规定“捕获阶段不会接触到事件目标”,然而浏览器厂商们并没有理会。也因此在事件捕获阶段以及事件冒泡阶段都有机会在事件目标上进行事件处理。
2 promise理解
1、主要用于异步计算
2、可以将异步操作队列化,按照期望的顺序执行,返回符合预期的结果
3、可以在对象之间传递和操作promise,帮助我们处理队列
解决嵌套层次深不好解决异步回调的问题解决不好维护的问题
Promise.all([p1, p2, p3])用于将多个promise实例,包装成一个新的Promise实例,返回的实例就是普通的promise
它接收一个数组作为参数
数组里可以是Promise对象,也可以是别的值,只有Promise会等待状态改变
当所有的子Promise都完成,该Promise完成,返回值是全部值得数组
有任何一个失败,该Promise失败,返回值是第一个失败的子Promise结果
3 跨域
跨域是指一个域下的文档或脚本试图去请求另一个域下的资源,这里跨域是广义的。
我们通常所说的跨域是狭义的,是由浏览器同源策略限制的一类请求场景。
同源策略:是一种约定,由Netscape公司1995年引入浏览器,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,浏览器很容易受到XSS、CSFR等攻击。所谓同源是指"协议+域名+端口"三者相同,即便两个不同的域名指向同一个ip地址,也非同源。
同源策略限制以下几种行为:
1.) Cookie、LocalStorage 和 IndexDB 无法读取
2.) DOM 和 Js对象无法获得
3.) AJAX 请求不能发送
跨域解决方案 :
1、 通过jsonp跨域
2、 document.domain + iframe跨域
3、 location.hash + iframe
4、 window.name + iframe跨域
5、 postMessage跨域
6、 跨域资源共享(CORS)
7、 nginx代理跨域
8、 nodejs中间件代理跨域
9、 WebSocket协议跨域
跨域解决方案
4 浏览器内核
IE:Trident
FireFox: Gecko
Opera: Presto(目前使用的是Blink内核)
Chrome : Webkit
5 get和post区别
1. get提交的瞬狙会放在url中,以?分割URL和传输数据,参数之间以&相连,GET提交的数据会在地址栏 中显示出来,而POST提交,地址栏不会改变。
2.GET提交的数据大小有限制(因为浏览器对URL的长度有限制),而POST方法提交的数据没有限制.
3.POST的安全性要比GET的安全性高。
6 this问题大全
1.this指向问题
一直是指向一个对象,
全局状态指向的是 window,函数内的this指向的是当前函数所属对象;
2 call,apply,bind异同
都能改变this指向,call和apply返回的是函数的调用,bind返回的是函数,必须调用才行
举个例子:A.protoType.call(this),A.protoType.apply(this)
A。protoType.bind(this)()
7 判断类型
String
一个字符串始终是一个字符串,所以这一块是很容易。除非使用new(new String)调用,否则typeof将返回“object”。所以也要包含那些可以使用的字符串instanceof。
?
1
2
3
4
// Returns if a value is a string
function isString (value) {
return typeof value === ‘string’ || value instanceof String;
}
Number
From typeof more things than just an ordinary number will return “number” like NaN and Infinity. To know if a value really is a number the function isFinite is also required.
从类型更多的东西,而不仅仅是普通的数字将返回像NaN和无限的“数字”。要知道值是否真的是数字,函数isFinite也是必需的。
1
2
3
4
// Returns if a value is really a number
function isNumber (value) {
return typeof value === ‘number’ && isFinite(value);
}
Array
在javascript 数组中不是像java和其他语言中那样的真正数组。它们实际上是对象,因此typeof将为它们返回“对象”。要知道某些东西是否真的是一个数组,它的构造函数可以与Array进行比较。
?
1
2
3
4
5
6
7
// Returns if a value is an array
function isArray (value) {
return value && typeof value === ‘object’ && value.constructor === Array;
}
// ES5 actually has a method for this (ie9+)
Array.isArray(value);
Function
?
1
2
3
4
// Returns if a value is a function
function isFunction (value) {
return typeof value === ‘function’;
}
Object
很多东西都是javascript中的对象。要知道值是否是可以具有属性并循环的对象,可以将其构造函数与Object进行比较。它不适用于从类创建的对象,因此可以使用instanceof运算符。
?
1
2
3
4
// Returns if a value is an object
function isObject (value) {
return value && typeof value === ‘object’ && value.constructor === Object;
}
Null & undefined
大多数情况下,您不需要显式检查null和undefined,因为它们都是假值。然而,要做到这一点,下面的功能就可以了。
?
1
2
3
4
5
6
7
8
9
// Returns if a value is null
function isNull (value) {
return value === null;
}
// Returns if a value is undefined
function isUndefined (value) {
return typeof value === ‘undefined’;
}
Boolean
对于布尔值, typeof就足够了,因为它返回true和false的“boolean”。
?
1
2
3
4
// Returns if a value is a boolean
function isBoolean (value) {
return typeof value === ‘boolean’;
}
RegExp
RegExp是对象,因此唯一需要检查的是构造函数是否为RegExp。
?
1
2
3
4
// Returns if a value is a regexp
function isRegExp (value) {
return value && typeof value === ‘object’ && value.constructor === RegExp;
}
Error
javascript中的错误与许多其他编程语言中的“异常”相同。它们有几种不同的形式,例如Error,TypeError和RangeError。一个instanceof语句对他们来说已经足够了,但我们还要确保我们还检查错误所具有的“message”属性。
?
1
2
3
4
// Returns if value is an error object
function isError (value) {
return value instanceof Error && typeof value.message !== ‘undefined’;
}
Date
日期实际上不是javascript中的数据类型。但要知道是否有某个Date对象,可以使用instanceof进行检查。
?
1
2
3
4
// Returns if value is a date object
function isDate (value) {
return value instanceof Date;
}
Symbol
?
1
2
3
4
// Returns if a Symbol
function isSymbol (value) {
return typeof value === ‘symbol’;
}
但是你可能会发现,typeof在判断null、array、object以及函数实例(new + 函数)时,得到的都是object。这使得在判断这些数据类型的时候,得不到真是的数据类型。由此引出instanceof。
instance中文翻译为实例,因此instanceof的含义就不言而喻,判断该对象是谁的实例,同时我们也就知道instanceof是对象运算符。
这里的实例就牵扯到了对象的继承,它的判断就是根据原型链进行搜寻,在对象obj1的原型链上如果存在另一个对象obj2的原型属性,那么表达式(obj1 instanceof obj2)返回值为true;否则返回false。
想必到这里大家也都明白两者的含义和用法,总之,typeof和instanceof都是用来判断变量类型的,两者的区别在于:
typeof判断所有变量的类型,返回值有number,boolean,string,function,object,undefined。
typeof对于丰富的对象实例,只能返回"Object"字符串。
instanceof用来判断对象,代码形式为obj1 instanceof obj2(obj1是否是obj2的实例),obj2必须为对象,否则会报错!其返回值为布尔值。
instanceof可以对不同的对象实例进行判断,判断方法是根据对象的原型链依次向下查询,如果obj2的原型属性存在obj1的原型链上,(obj1 instanceof obj2)值为true。
8原型链和继承
JavaScript只有一种结构:对象。每个对象都有一个私有属性:proto,这个属性指向它构造函数的原型对象(Prototype)。它的原型对象也有一个属于自己的原型对象,这样层层向上只至这个原型对象的属性为null。根据定义null没有自己的原型对象,它是这个原型链中的最后一个环节。
几乎所有的JavaScript中的对象都是位于原型链顶端的Object的实例。
9 数组扁平化
就它啦: let arr = [3, 12, 1, 2, [3, 4, 4, [5, 4,6, [8,9,7, 8, [9, 10, 11]]]]];
第一种方法,直接调用arr的flat方法
arr = arr.flat(Infinity);
有个小点儿要说明。arr.flat()默认只展开一级,默认括号内为 1
那么上面的arr展开为
flat(2)为
为了一步到位,直接flat(Infinity);
还有一件事,如果数组内有空的选项,则会被删除
let arr1 = [1, 1, , 2]
arr1 = arr1.flat(Infinity);
console.log(arr1)
打印出只有[1, 1, 2]
然后如何数组去重呢:
new Set(arr)
返回的是一个对象 , 伪数组
如何将变成数组呢?
两种方法:
1.展开运算符
[…new Set(arr)] 使其变成数组
2.Array.from() 可将一个 伪数组对象或者可遍历对象转换成一个真正的数组
即
Array.from(new Set(arr))
Array.from有三个参数,Array.from(arrayLike[, mapFn[, thisArg]]),arrayLike:想要转换成数组的伪数组对象或可迭代对象;mapFn:如果指定了该参数,新数组中的每个元素会执行该回调函数;thisArg:可选参数,执行回调函数 mapFn 时 this 对象。该方法的返回值是一个新的数组实例(真正的数组)。
arr = Array.from(new Set(arr)).sort((a, b) => a - b)
就能够实现扁平化,去重并排序
第二种方法:
arr.toString(arr) arr,就是要扁平化的那个数组,名字任意起
数组toString之后,不管你有多少级,最后都会直接以逗号分隔的字符串,没有中括号和所谓的层级了,相当于直接的扁平化了
arr = arr.toString().split(’,’).map( item => {
return Number(item)
})
arr.toString(arr)
arr.toString(arr).split(’,’)
这里一定要写成split(’,’) 逗号不能省。
然后使用map进行遍历,让每一项都变成 数字类型
有个小细节:
不写则会 split(’’)的逗号则会:
因为:
split()
如果把空字符串 ("") 用作 separator,那么 stringObject 中的每个字符之间都会被分割
参数
描述
separator
必需。字符串或正则表达式,从该参数指定的地方分割 stringObject。
howmany
可选。该参数可指定返回的数组的最大长度。如果设置了该参数,返回的子串不会多于这个参数指定的数组。如果没有设置该参数,整个字符串都会被分割,不考虑它的长度。
返回值
一个字符串数组。该数组是通过在 separator 指定的边界处将字符串 stringObject 分割成子串创建的。返回的数组中的字串不包括 separator 自身。
记住最后一句话就够了:返回的数组中的字串不包括 separator 自身。
第三种方法:
arr = JSON.stringify(arr).replace(/([|])/g, ‘’).split(’,’).map( item => {
return Number(item)
})
第四种方法:
while(arr.some( item => Array.isArray(item))){
arr = [].concat(…arr);
}
这里使用了 some 如果满足条件就返回 布尔值true
Array.isArray(item)是判断item 是否是数组的,最有效的方式
如果为真,说明当前item项为数组
…arr 展开运算符 将当前item数组展开,并使用concat,将 展开的各项,添加到前面的数组内 【】
第五种方法:老老实实递归
let result = [];
function fn(array){
for(let i = 0; i < array.length; i++){
let item = array[i];
if(Array.isArray(array[i])){
fn(item);
}else{
result.push(item)
}
}
return result;
}
fn(arr)
就一句话:记得return !!!
第六种方法:reduce
const flatten = (arr) => {
return arr.reduce((prev, next) => {
return prev.concat(Object.prototype.toString.call(next) === ‘[object Array]’ ? flatten(next): next)
}, [])
}
console.log(flatten(arr))
平常使用就直接简单粗暴,arr.flat(Infinity) ,内部也是执行了递归。
10 字符串去重,数组去重
字符串排序:字符串的一个方法,localeCompare; 或者转化为数组在进行排序
11节流和防抖
节流:上拉加载…
防抖:搜索功能…
面试问题:
问: 项目中做过哪些?
回答:性能优化
函数节流:让一个函数不要执行得太频繁,减少一些过快的调用来节流。
核心就是:
让一个函数不要执行得太频繁,减少一些过快的调用来节流。
防抖:事件保持触发,一定时间内没有触发
核心:在一定时间段的连续函数调用,只让其执行一次
追问:在什么项目用到过?
假设我们网站有个搜索框,用户输入文本我们会自动联想匹配出一些结果供用户选择。
我们可能首先想到的做法就是监听keypress事件,然后异步去查询结果。
这个方法本身是没错的,但是如果用户快速的输入了一连串的字符,假设是10个字符,那么就会在瞬间触发了10次的请求,这无疑不是我们想要的。
我们想要的是用户停止输入的时候才去触发查询的请求,这时候函数防抖可以帮到我们。
节流应用场景:
滚动浏览器滚动条的时候,更新页面上的某些布局内容或者去调用后台的某接口查询内容。
同样的,如果不对函数调用的频率加以限制的话,那么可能我们滚动一次滚动条就会产生N次的调用了。
但是这次的情况跟上面的有所不同,我们不是要在每完成等待某个时间后去执行某函数,而是要每间隔某个时间去执行某函数,避免函数的过多执行。
12 async/await
13 常用的数组方法
14 webpack有几种 hash
15 data为什么会返回一个函数
16 margin重叠
17