前端 html 、 js 、css 面试题

2022年05月14日 阅读数:3
这篇文章主要向大家介绍前端 html 、 js 、css 面试题,主要内容包括基础应用、实用技巧、原理机制等方面,希望对大家有所帮助。

文章目录

一、基本数据类型

String、Number、Boolean、Null、Undefined、Symbol(ES6)
基本数据类型是指存放在栈中的简单数据段,数据大小肯定,内存空间大小能够分配,它们是直接按值存放的,因此能够直接按值访问。javascript

二、引用数据类型

Object(在JS中除了基本数据类型之外的都是对象,Array是对象,Function是对象,正则表达式是对象)
引用类型是存放在堆内存中的对象,变量实际上是保存的在栈内存中的一个指针(保存的是堆内存中的引用地址),这个指针指向堆内存。css

三、JS 的栈和堆

在 JS 中每个数据都须要一个内存空间,这个空间被分为两种:栈内存(stack)、堆内存(heap)。
1)、栈:html

自动分配相对固定大小的内存空间,并由系统自动释放,这样内存能够及时获得回收,相对堆更容易管理内存空间;
基础数据类型都是存储在栈内存里面的.,每个数据占据的内存空间大小是肯定的(引用类型的地址也存在栈里);
js能够直接访问栈里存储的数据;
栈是线性结构,先进后出,便于管理;前端

2)、堆:html5

动态分配内存,内存大小不一,也不会自动释放.;
引用内存数据存储在堆中,可是引用类型的数据地址指针是存储在栈里面的;
咱们要访问引用类型须要如今栈里面获取对象地址,而后根据地址找到堆里面对应的数据,不能够直接访问堆里面的数据;
杂乱无序,方便存储和开辟内存空间;java

四、深拷贝和浅拷贝

浅拷贝: 只是将数据中全部的数据引用下来,依旧指向同一个存放地址,拷贝以后的数据修改以后,也会影响到原数据的中的对象数据
深拷贝: 将数据中全部的数据拷贝下来,对拷贝以后的数据进行修改不会影响到原数据node

浅拷贝方法:jquery

一、赋值运算
二、扩展运算符 (…)
三、Object.assign( target, …sources)
四、concat、 解构赋值等webpack

深拷贝方法:es6

一、递归
二、JSON.parse( JSON.stringify( a ) ):这个方法没法转化 function 和 undefined。

五、宏任务和微任务

JS 是单线程的,任务按顺序一个一个执行,避免一个任务消耗时间太长后面任务只能等待;因此将 JS 分为同步任务和异步任务,而异步任务中又分为宏任务和微任务两种;

1)、宏任务由宿主(浏览器、node)发起的;微任务由 JS 引擎发起;
2)、宏任务(setTimeout、setInterval、postMessage、script 、setImmediate(node)),微任务(promise.then、process.nextTick(node)、MutaionObserver);
3)、同一层级,先执行微任务,在执行宏任务;

六、typeof返回那些数据类型

object、undefined、string、number、boolean、function

七、原型 和 原型链

1)、原型的五条规则

一、全部的引用类型均可以自定义添加属性
二、全部的引用类型都有本身的隐式原型(proto)
三、函数都有本身的显式原型(prototype)
四、全部的引用类型的隐式原型都指向对应构造函数的显示原型
五、使用引用类型的某个自定义属性时,若是没有这个属性,会去该引用类型的proto(也就是对应构造函数的prototype)中去找

2)、原型理解
原型:一个简单的对象,用于实现对象的属性继承
构造函数:能够经过 new 新建一个对象函数
实例:经过构造函数new出来的对象

实例.proto === 原型
实例.constructor === 构造函数
原型.constructor === 构造函数
构造函数.prototype === 原型
顶层Object prototype.proto == null

在这里插入图片描述
3)、原型链理解
原型链是由原型对象组成,每一个对象都有_proto_属性指向建立该对象的构造函数的原型,_proto_把对象链接起来组成原型链。(实现继承和共享属性)
属性查找机制:查找对象属性时,实例对象自身不存在该属性,则沿着原型链往上一级查找找到则输出找不到继续往上一级查找,直到顶级的原型对象还没找到则输出undefined。
属性修改机制:只会修改实例对象自己属性。如不存在,则添加该属性。能够用b.prototype.x = 2修改属性值,而后全部继承于该对象的属性都会改变。
在这里插入图片描述
步骤:cat没有price,根据_proto_找到animal.prototype,若是animal.prototype找不到则根据_proto_找到Object prototype,Object prototype的_proto_是null
cat.proto = animal.prototype //20
步骤:tidy根据_proto_找到dog.prototype = animal,若是找不到则根据animal._proto_往上面找
tidy.proto=dog.prototype = animal //1000

八、js事件循环

1)、js 是单线程的:由于 js 主要用途是与用户互动和操做 dom 的,因此它必须是单线程的,防止两个线程同时操做 dom 浏览器没法知道以哪个为准。

2)、任务队列:

一、单线程就意味着,全部任务须要排队,前一个任务结束,才会执行后一个任务。若是前一个任务耗时很长,后一个任务就不得不一直等着。
二、js 把任务分红两种,一种是同步任务,另外一种是异步任务。同步任务在主线程上排队执行,只有前一个任务执行完毕,才能执行后一个任务;异步任务不进入主线程、而进入"任务队列"(task queue),只有"任务队列"通知主线程,某个异步任务能够执行了,该任务才会进入主线程执行。

3)、js 运行机制:

一、全部同步任务在主线程上执行;
二、主线程以外还有一个任务队列,异步任务有了运行结果就在任务队列里面放置一个事件;
三、同步任务执行完毕以后,系统会读取任务队列里存放发事件,把对应的异步任务推到主线程开始执行;
四、主线程任务执行完毕以后,继续从任务队列里面读取事件;

只要主线程空了,就会去读取"任务队列",这就是JavaScript的运行机制。这个过程会不断重复,整个的这种运行机制又称为Event Loop(事件循环)。

九、闭包

闭包就是能够读取其余函数内部的变量;JavaScript语言中,闭包就是“定义在一个函数内部的函数”,主要的用途是设计私有的方法和变量;主要运用的框架是 jquery。

特色

能够在函数外部访问函数内部的局部变量;
局部变量会常驻在内存中,实现数据共享(会形成内存泄露);

使用场景

匿名自执行函数
结果缓存
实现类和继承
封装私有变量
回调:定义行为,而后把它关联到某个用户事件上。
setTimeout:原生的setTimeout传递的第一个函数不能带参数,经过闭包能够实现传参效果。
函数防抖

问题1:多个子函数指向同一个父级,父级变量修改时,全部子函数都受影响
变量经过函数参数的形式传入。
问题2:清除闭包的缓存
在使用完以后将局部变量设置为null或者删除掉。

十、new运算符执行过程

生成新对象
连接到原型:obj.proto = Object.prototype(this指向这个新对象)
绑定this:apply(执行代码给this赋值)
返回新对象

十一、cookie、session和token区别

token和session安全性高,cookie能够分析存放在本地cookie进行cookie欺骗和截获
token不必定须要存储,session 必须存在服务器
token能够跨域,session和域名绑定

参考:web 开发用到的几种会话跟踪技术

十二、JWT

JWT:Json Web Token,是基于 JSON 的一个公开规范,这个规范容许咱们使用 JWT 在用户和服务器之间传递安全可靠的信息,他的两大使用场景是:认证和数据交换

使用:由服务端根据规范生成一个令牌(token),而且发放给客户端。此时客户端请求服务端的时候就能够携带者令牌,以令牌来证实本身的身份信息。

做用:保持登陆状态 的办法,经过token来表明用户身份。

组成:JWT实际上就是一个字符串,它由三部分组成:头部、载荷与签名

头部:声明类型 和 声明加密的算法的JSON,而后进行base64加密的字符串
载荷:存放有效信息的地方的JSON,而后进行base64加密的字符串
签名:这个部分须要base64加密后的头部和载荷链接组成的字符串,而后经过头部中声明的加密方式进行加盐secret组合加密

优势:

一、jwt基于json,很是方便解析
二、能够再令牌中自定义丰富的内容,易扩展(payload能够扩展)
三、经过签名,让JWT防止被篡改,安全性高
四、资源服务使用JWT可不依赖认证服务便可完成受权

1三、数组去重

下面是我总结的几种方法以及实现代码,能够直接查看!
数组去重方法总结(10种)

1四、判断数组是数组

一、isArray
二、instanceof
三、constructor
四、Object.getPrototypeOf()

检测数组的6种方法

1五、ES6

1)、let 、const
声明的变量无变量提高,且会被锁定在声明的代码块中,变量声明前都是暂时性死区;
const 声明的对象只是引用没法修改,对象内部结构是能够改变的,可使用 Object.freeze()来锁定对象,只锁定一层,多层级对象须要递归锁定。

function freeze(obj){
	let name = Object.getOwnPropertyNmaes(obj);
	name.forEach(name =>{
		let prop = obj[name];
		if(typeof prop == 'objdet' && prop != null){
			freeze(prop);
		}
	})
	return Object.freeze(prop);
}

2)、解构赋值:能够方便的从数组或者对象中快速提取值赋给定义的变量

let [a, b, c] = [1, 2, 3];
// a = 1
// b = 2
// c = 3
let { foo, bar } = { foo: 'aaa', bar: 'bbb' };
// foo = 'aaa'
// bar = 'bbb'
let { baz : foo } = { baz : 'ddd' };
// foo = 'ddd'

3)、symbol:原始数据类型不能够用 new 构建,表示独一无二的值,能够做为对象的key,不被常规方法遍历出来,只能用 Object.getOwnPropertySymbols()或者 Reflect.ownKeys ()返回所有 key。

// 相同参数 Symbol() 返回的值不相等
 Symbol("kk") !=  Symbol("kk")

//做为对象的属性名只能用方括号
let sy = Symbol('key1')
let obj = {}
obj[sy] = 'ss'
console.log(obj) //{symbol(key1):'ss'}

Symbol.for() 和 Symbol.keyFor()
Symbol.for(): Symbol 中是否有该字符串参数做为名称的 Symbol 值,若是有即返回该 Symbol 值,若没有则新建并返回一个以该字符串参数为名称的 Symbol 值,并登记在全局环境中供搜索;
Symbol.keyFor() 返回一个已登记的 Symbol 类型值的 key;必定是登记过的才会返回;

let s1 = Symbol('foo');
let s2 = Symbol.for('foo');
let s3 = Symbol.for('foo');
s1 === s2 // false
s2 === s3 // true

Symbol.keyFor(s1) // undefiend
Symbol.keyFor(s2) // "foo"

4)、Map 和 set: Map 通常用来存储须要频繁取用的数据, Set 通常用来判断某个值是否存在其中.
Map:保存键值对,具备极快的查找速度
Map和Object的区别:

Object的键只能是字符串或者Symbol,Map的键能够是任意值。
Map中的键值是有序的(FIFO 原则)相似于数组,而添加到Object中的键则不是。
Map的键值对个数能够从 size 属性获取,而 Object 的键值对个数只能手动计算。
Object 都有本身的原型,原型链上的键名有可能和你本身在对象上的设置的键名产生冲突。

Map对象的属性和方法

size:返回Map对象键值对个数
set(key,value):添加新元素
get(key):经过key值查找对应的值并返回
has(key):判断是否有key对应的属性,返回布尔值(强等判断===)(能够用NaN作key,不能够用{}、函数作key)
delete(key):删除key对应的数据
clear():清空Map全部元素

Map遍历方法

keys():返回键名的遍历器
values():返回键值的遍历器
entries():返回键值对的遍历器(Iterator)
forEach():使用回调函数遍历每一个成员
for…of:遍历每一个成员

Map对象操做

与Array的转换:Map 构造函数能够将一个 二维 键值对数组转换成一个 Map 对象;Array.from 函数以及扩展运算符[…map]能够将一个 Map 对象转换成一个二维键值对数组
合并:若是有重复的键值,则后面的会覆盖前面的

**Set:**容许你存储任何类型的惟一值,不管是原始值或者是对象引用。
在Set里面 +0和-0、undefined、NaN 都是不会重复的。

Set对象的属性和方法

size:返回Set实例的成员总数。
add(value):添加某个值,返回 Set 结构自己(能够链式调用)。
delete(value):删除某个值,删除成功返回true,不然返回false。
has(value):返回一个布尔值,表示该值是否为Set的成员。
clear():清除全部成员,没有返回值。

5)、Proxy和Reflect
Proxy 代理对象的各类内置方法,get set construct等,相似于拦截器。它不直接操做对象,而是像代理模式,经过对象的代理对象进行操做,在进行这些操做时,能够添加一些须要的额外操做。

//target 即目标对象, handler 是一个对象(get、set方法进行拦截和修改,apply、call拦截函数的调用),声明了代理 target 的指定行为。
let proxy = new Proxy(target, handler)

Reflect 则做为Object的替代者,Object上的一些静态方法被移植到了Reflect上。能够用于获取目标对象的行为。
(get、set、has、construct、apply、defineProperty、deleteProperty、ownKeys、isExtensible、preventExtensions、getOwnPropertyDescriptor、getPrototypeOf、Reflect)

6)、字符串

include():是否找到参数字符串;str.include(‘参数字符串’)
startsWith():参数是否在字符串头部;str.startsWith(‘参数字符串’)
endsWith():参数是否在字符串尾部;str.endsWith(‘参数字符串’)
repeat():将字符串重复指定次数返回;str.repeat(重复次数) :小数向下取整、NaN取0、负数和infinity报错
padStart():用参数从头部补全字符串;str.padStart(指定字符串补全长度,参数字符串)
padEnd():用参数从尾部补全字符串;str.padEnd(指定字符串补全长度,参数字符串)
模板字符串

注意:补全长度小于等于原字符串长度返回原字符串;原字符串加上补全字符串长度大于指定长度,则截去超出位数的补全字符串:;经常使用于补全位数

7)、数字

Number.isFinite():数值是否为有限
Number.parseInt():数字转成指定整数
Math.trunc():取整数部分
Math.fround():取小数部分
Math.sign():判断数字的符号(正、负、0)。

8)、对象

属性、方法名简写:const person = {age, name}
对象拓展运算符(…):取出参数对象全部可遍历属性而后拷贝到当前对象,也可合并对象(能够覆盖相同属性)
Object.assign(target,resource):将源对象的全部可枚举属性复制到目标对象中
Object.is(value1,value2):比较两个值是否严格相等,与(===)基本相似

9)、数组

Array.of():将参数中全部值做为元素造成数组
Array.from():将类数组对象或可迭代对象(Map、Set、字符串)转化为数组
find():查找数组中符合条件的元素,如有多个符合条件的元素,则返回第一个元素
findIndex():查找数组中符合条件的元素索引,如有多个符合条件的元素,则返回第一个元素索引
fill(替换值,开始索引,结束索引):将必定范围索引的数组元素内容填充为单个指定的值
entries():遍历键值对
keys():遍历键名
values():遍历键值
includes():数组是否包含指定值
flat(num):将多维数组降指定参数维度;自动过滤空位,Infinity 必然获得一维数组
flatMap():先对数组中每一个元素进行了的处理,再对数组执行 flat() 方法
扩展运算符(…):跟对象同样

10)、函数

函数参数默认值
不定参数:表示不肯定参数个数(…变量名)
箭头函数:自身没有this,this指向外部环境

11)、迭代器(Iterator)
新的遍历机制,做用是使各类数据结构可被便捷的访问,它是经过一个键为Symbol.iterator 的方法来实现。
可迭代的数据:Array、String、Map、Set、DOM元素、arguments;可使用 for…of 遍历
普通对象不可迭代

let arr = [1,2,3,4,5];
let it = arr[Symbol.iterator]();
it.next()
//{value:1,done:false}

12)、class类
本质是 function ,用来定义类;
内置 constructor 方法,建立类的实例化对象时调用;静态方法使用 static

class example{
	constructor(){} //构造函数方法
	static sun(){} //静态方法
	list(){} //原型方法
}
example.sun() //执行静态方法
let it = new example()//调取constructor
it.list() //执行原型方法

注意:

class 的实例化必须经过 new 关键字。
经过 extends 实现类的继承。
子类 constructor 方法中必须有 super ,且必须出如今 this 以前。

13)、模块化:export 和 import 组成

模块能够导入导出各类类型的变量;import 命令会提高到整个模块的头部,首先执行;屡次重复执行同一句 import 语句,那么只会执行一次.;import 是静态执行,因此不能使用表达式和变量
不一样模块导出接口名称命名重复, 可使用 as 从新定义变量名:export {a as b} ;import {a as b} from xxx;a重命名为b
在一个文件或模块中,export、import 能够有多个,export default 仅有一个

export { foo, bar } from "methods";
// 约等于下面两段语句,不过上面导入导出方式该模块没有导入 foo 与 bar
import { foo, bar } from "methods";
export { foo, bar };

14)、promise对象
三种状态:pending(进行中)、fulfilled(已成功)和 rejected(已失败)
缺点:

没法取消 Promise ,一旦新建它就会当即执行,没法中途取消。
若是不设置回调函数,Promise 内部抛出的错误,不会反应到外部。
当处于 pending 状态时,没法得知目前进展到哪个阶段(刚刚开始仍是即将完成)。

方法:

then()
catch()
all()
race()
finally()

可参考:ES6 Promise基础知识总结

15)、Generator 和 yield
能够生成一个迭代器(Iterator),每次iterator.next()返回yield的产出值,且中断程序执行。换句话说:能够经过 yield 关键字,把函数的执行流挂起,为改变执行流程提供了可能,从而为异步编程提供解决方案。

组成: function 后面,函数名以前有个 * ;函数内部有 yield 表达式。

function* func(){
	console.log(1)
	yield '1';
	console.log(2)
	yield '2';
}
let fn = func();
fn.next() //1 
fn.next() //2

1六、promise如何终止链式调用

1)、经过reject来中断(特定条件知足后)

return Promise.reject('break without exception.')

2)、经过抛出一个异常来终止

throw "we need break";

3)、返回“pending”状态的Promise对象

Promise.resolve().then(() => {
	console.log('ok1')
	return new Promise(()=>{}) // 返回“pending”状态的Promise对象
}).then(() => {
	// 后续的函数不会被调用
	console.log('ok2')
}).catch(err => {
	console.log('err->', err)
})

4)、Promise.race:最早改变状态的实例返回的值将会是race的返回值。

let p1 = new Promise((resolve, reject) => {
	resolve('ok1')
})
let p2 = new Promise((resolve, reject) => {
	setTimeout(() => {resolve('ok2')}, 10)
})
Promise.race([p2, p1]).then((result) => {
	console.log(result) //ok1
}).catch((error) => {
	console.log(error)
})

1七、promise和async/await区别

1)、promise:异步编程的解决方案,为了解决传统的callback函数回调地狱问题,支持链式调用,三种状态(),存放着将来将要执行的结果,结果不可逆,业务复杂时须要不停的then,这样不美观;

2)、async/await:基于promise 的异步解决方案,遵循 Generator 函数的语法糖,拥有内置执行器,不须要额外的调用会自动执行和返回结果,返回的是一个 promise 对象;解决promise里面不停使用then的问题;

区别:

一、promise是ES6,async/await是ES8
二、async/await基于promise实现的,它不能用于普通的回调函数
三、promise链式调用,本身catch异常,async要在函数内catch
四、async/await使得异步代码看起来像同步代码
五、async/await与Promise同样,是非阻塞的
六、须要注意的是async指定了函数 才能在那个函数里面写await

1八、如何让 a== 1 && a== 2 成立?(js)

利用 js 的隐式类型转换 valueOf() 和 toString(),Symbol.toPrimitive()

var a = {
	value: 0,
	valueOf () {
		return ++this.value;
	}
}
if (a == 1 && a == 2 && a == 3) {
	console.log('成立');
}

利用数组转化字符串会隐式调用join()

let a = [1, 2, 3]
a['join'] = function () {
	return this.shift()
}
if (a == 1 && a == 2 && a == 3) {
	console.log('成立')
}

1九、ES5继承和ES6继承区别

继承:拥有另外一个对象的方法和属性
1)、ES5:基于原型链,让原型对象等于另外一个类的实例;(call改变this指向)
先建立子类,在实例化父类并添加到子类的this中。
父.call(子) => 子.prototype = new 父()
2)、ES6:基于class个extends,子类经过执行super方法继承父类的this对象。
父类先建立出来,在实例化子类经过调用super方法访问父类,而后修改子类的this;

20、判断是不是整数?(js)

1)、除以1,余数为0

function isInteger(obj) { return obj%1 === 0 }

2)、取整后还等于本身

function isInteger(obj) { return Math.floor(obj) === obj }

3)、ES6提供了Number.isInteger

2一、this指向

可查阅:javascript的this指向问题

2二、箭头函数能够作构造函数吗?能够经过call修改this吗?为何?

箭头函数表达式的语法比函数表达式更简洁,而且没有本身的this,arguments,super或new.target。箭头函数表达式更适用于那些原本须要匿名函数的地方,而且它不能用做构造函数。

箭头函数特色:

没有本身的 this,this指向外部环境,经过 call() 或 apply() 方法调用一个函数时只能传递参数,不能绑定 this;所以第一个参数会被忽略。
箭头函数没有 prototype 属性;可是有 prop 属性,因此箭头函数自己是存在原型链的,它也有本身的构造函数,可是原型链到箭头函数就中止了,因此不能做为构造函数。
没有本身的 arguments,在箭头函数中访问arguments实际上得到的是外层局部(函数)执行环境中的值

2三、for循环里面加定时器

for(var i = 0;i<4;i++){
	setTimeout(function(){
		console.log(i)
	})
}
//3 3 3 3

由于 var 定义的 i 是全局变量,加上定时器是异步操做,等循环结束以后定时器里面的 i 都变成了3。

若是想返回 0,1,2,3该如何修改呢?
1)、利用闭包
每次循环都把 i 值保存下来

for(var i = 0; i < 5; i++) {
    (function(i) {
        setTimeout(function () {
            console.log(i);
        });
    })(i)
}    

2)、将 var 换成 let
由于 let 关键字劫持了循环的块做用域,产生相似闭包的效果;

3)、try…catch
catch后面的花括号是一个块做用域,和let的效果同样;在try语句块里抛出循环变量i,而后在catch的块做用域里接收到传过来的i,就能够将循环变量保存下来,实现相似闭包和let的效果。

for(var i = 0; i < 4; i++) {
   try {
        throw(i)
    } catch(j) {
        setTimeout(function () {
            console.log(j);
        });
    }
} 

2四、执行上下文、执行栈

1)、执行上下文类型:全局上下文、函数上下文(能够把执行上下文理解为一段代码执行须要准备的环境)

  • 全局上下文:基础的上下文,函数中的代码都要在全局执行上下文中。它建立全局对象(window);将 this 指向 window,var 和 function 定义的变量提高,添加为 window 的属性和方法;一个程序中只能存在一个全局执行上下文。
  • 函数上下文:每次函数调用时都会建立一个新的 执行上下文;

2)、执行上下文生命周期:建立-执行-回收

一、变量声明提高:var 声明的变量会被提高了
二、函数声明提高:函数声明(function aa() {})的函数会被提高,函数表达式(var aa = function () {})声明的则会将变量提高
三、当函数和变量同名且都会提高的状况下,函数优先级高;变量声明先提高,而后被函数声明覆盖掉,可是变量能够从新赋值
四、this的值在执行的时候才会肯定,定义的时候不能肯定。

3)、执行栈:

一、在全局代码执行前,JS 会建立一个栈来存储管理全部的执行上下文对象;
二、建立一个全局执行上下文来执行全局代码并放入执行栈底部;
三、当遇到函数被调用时开始将函数代码封装为执行上下文放入执行栈;(函数有调用关系的话则会排队执行)
四、JS 调用老是从栈顶开始调用执行,执行完以后出栈,等待垃圾回收;
五、全局上下文在浏览器窗口关闭后出栈;

(var声明的变量存储在变量环境,函数声明、let和const存储在词法环境)

2五、script标签上面的属性

async:可选,异步加载,不妨碍页面中的其余操做,加载完以后当即执行;对外部文件有效
defer:可选,异步加载,不妨碍页面中的其余操做,延迟到文档彻底被解析和显示以后再执行;只对外部脚本文件有效。

2六、判断两个对象相等

1)、经过JSON.stringify(obj)来判断两个对象转后的字符串是否相等
优势:用法简单,对于顺序相同的两个对象能够快速进行比较获得结果
缺点:当两个对比的对象中key的顺序不是彻底相同时会比较出错

2)、Object.keys()

// 列出全部的键,接着遍历数组
function ifCompare(object1, object2) {
	var o1keys = Object.keys(object1);
	var o2keys = Object.keys(object2);
	if (o2keys.length !== o1keys.length) return false;
	for (let i = 0; i <= o1keys.length - 1; i++) {
		let key = o1keys[i];
		if (!o2keys.includes(key)) return false;
		if (object2[key] !== object1[key]) return false;
	}
	return true;
}

3)、ES6

Object.entries(object1).toString() === Object.entries(object2).toString();

2七、JS模块化规范

JS常规实现模块化:

一、直接全局写方法做为模块:能够直接调用,可是污染了全局变量,模块和成员直接看不出直接的关系;
二、对象写法:会暴露全部模块成员,内部可被改写;
三、当即执行函数(闭包):外部没法读取内部变量;

1)、AMD(异步加载模块)
AMD 规范须要用到 RequireJS库,主要用于浏览器端的模块化规范;RequireJS是依赖前置,先去执行依赖的模块,而后再执行当前模块。

定义模块:define([依赖的模块],function(){自定义模块})
引入模块:require([依赖的模块], function(){ //回调 })

// math.js
define(function (){
  var add = function (x,y){
   return x+y;
  };
  return {
   add: add
  };
});
// main.js
require(['math'], function (math){
  alert(math.add(1,1));
});

优缺点:

优:适合浏览器环境的异步加载,能够并行加载多个模块;
缺:书写困难,提升开发成本,不符合通用的模块化思惟;

2)、CMD(异步加载模块)
CMD规范和AMD很类似,简单,并与CommonJS和Node.js的 Modules 规范保持了很大的兼容性;在CMD规范中,一个模块就是一个文件
定义模块使用全局函数define,其接收 factory 参数,factory 能够是一个函数,也能够是一个对象或字符串;
factory 是一个函数,有三个参数,function(require, exports, module):

require 是一个方法,接受模块标识做为惟一参数,用来获取其余模块提供的接口:require(id)
exports 是一个对象,用来向外提供模块接口
module 是一个对象,上面存储了与当前模块相关联的一些属性和方法

define(function(require,exports,module){
	let a = require('./b');
})

优缺点:

优:依赖就近,延迟执行,能够很容易在 Node.js 中运行;
缺:依赖 SPM 打包,模块的加载逻辑偏重;

3)、CommonJS(同步加载模块):
CommonJS 主要用于服务端的模块化规范,好比:node、webpack;
CommonJS定义的模块分为三种:模块引用(require);模块定义(exports);模块标识(module)。require()用来同步引入外部模块,exports对象用于导出当前模块,或者当前的模块的方法和变量,module对象表明模块自己;

let list = require('list.js');
let coint = 0;
exports.info = function(){}; //处处单个
module.exports = {//导出多个
	count
}

优缺点:

优:简单易用,便于服务器模块的复用
缺:同步加载,不适合浏览器上使用,由于会出现阻塞加载(模块都是放在服务器上的,加载会很快,浏览器端想获取的话会受到网速的限制,因此会出现阻塞现象)

4)、UMD
UMD是AMD和CommonJS的糅合,先判断是否支持Node.js的模块(exports)是否存在,存在则使用Node.js模块模式;在判断是否支持AMD(define是否存在),存在则使用AMD方式加载模块。

5)、ES6模块化(import 、export )
ES6 在语言标准的层面上,实现了模块功能,并且实现得至关简单,彻底能够取代 CommonJS 和 AMD 规范,成为浏览器和服务器通用的模块解决方案。
ES6 模块设计思想:尽可能的静态化、使得编译时就能肯定模块的依赖关系,以及输入和输出的变量(CommonJS和AMD模块,都只能在运行时肯定这些东西)。

优缺点:

优:容易进行静态分析,面向将来的ES标准
缺:兼容性尚未作好

AMD 与 CMD 的区别

AMD推崇依赖前置;CMD推崇依赖就近,只有在用到某个模块的时候再去require
CMD是延迟执行;AMD是提早执行,requireJS从2.0开始能够延迟执行
CMD的API推崇职责单一,没有全局的require;AMD的API默认是一个当多个用

require 和 import 的区别
require用于CommonJs规范,import使用于Es6模块规范;因此二者的区别实质是两种规范的区别;
1)require

对于基本数据类型,属于复制。即会被模块缓存;同时,在另外一个模块能够对该模块输出的变量从新赋值。
对于复杂数据类型,属于浅拷贝。因为两个模块引用的对象指向同一个内存空间,所以对该模块的值作修改时会影响另外一个模块。
当使用require命令加载某个模块时,就会运行整个模块的代码。
当使用require命令加载同一个模块时,不会再执行该模块,而是取到缓存之中的值。也就是说,CommonJS模块不管加载多少次,都只会在第一次加载时运行一次,之后再加载,就返回第一次运行的结果,除非手动清除系统缓存。
循环加载时,属于加载时执行。即脚本代码在require的时候,就会所有执行。一旦出现某个模块被"循环加载",就只输出已经执行的部分,还未执行的部分不会输出。

2)import

ES6模块中的值属于【动态只读引用】。
对于只读来讲,即不容许修改引入变量的值,import的变量是只读的,不管是基本数据类型仍是复杂数据类型。
原始值发生变化,import加载的值也会发生变化。不管是基本数据类型仍是复杂数据类型。
循环加载时,ES6模块是动态引用。只要两个模块之间存在某个引用,代码就可以执行。

须要知道 import/export 最终都是编译为 require/exports 来执行的。

2八、判断对象是空

1)、将对象转化为json字符串,再判断该字符串是否为"{}"

var data = {};
var b = (JSON.stringify(data) == "{}");
conosle.log(b)

2)、for in 循环判断

var obj = {};
var b = function() {
	for(var key in obj) {
		return false;//进了循环说明不是空
	}
	return true;
}
conosle.log(b)

3)、jquery的isEmptyObject方法

var data = {};
var b = $.isEmptyObject(data);
conosle.log(b)

4)、Object.getOwnPropertyNames()方法

var data = {};
var arr = Object.getOwnPropertyNames(data);
console.log(arr.length == 0)

5)、使用ES6的Object.keys()方法

var data = {};
var arr = Object.keys(data);
console.log(arr.length == 0)

2九、Instanceof的原理,如何实现

原理:从当前引用的proto一层一层顺着原型链往上找,可否找到对应的prototype,找到了就返回true。
实现: L的 proto 是否是强等于 R.prototype,不等于再找 L.proto .proto 直到 proto 为 null 。

//console.log(L instanceof R)
function instance_of(L, R) {//L 表示左表达式,R 表示右表达式 
    var O = R.prototype;   // 取 R 的显示原型 
    L = L.__proto__;  // 取 L 的隐式原型
    while (true) {    
        if (L === null)      
             return false;   
        if (O === L)  // 当 O 显式原型 严格等于  L隐式原型 时,返回true
             return true;   
        L = L.__proto__;  
    }
}

30、封装promise定时器

function timeout(delay = 100) {
	return new Promise(resolve => {
		setTimeout(resolve, delay)
	})
};
timeout(2000).then(()=>{
	console.log('sssss')
})

3一、事件委托原理,为何用事件委托?

原理:利用事件冒泡原理将触发子元素的事件绑定到父元素上,利用e.target获取子元素实现事件触发
用处:因为对新生成的子元素没法绑定事件 这个时候就能够用事件委托的方法实现动态添加的新元素的触发事件

3二、多线程和单线程

1)、多线程:程序执行时,能够同时运行多个不一样的线程来执行不一样的任务。
优势:
提升cpu利用率;
提升程序的效率;
缺点:
占用内存随线程数增长;
线程太多控制复杂;
多线程须要协调管理,须要CPU时刻跟踪线程;
对共享资源的访问会相互影响;
2)、单线程:程序执行时,必须前面处理好了才能执行后面的。

3三、进程和线程的区别

两个名词都是CPU工做时间片的一个描述
进程:程序开始运行时,它就是一个进程;描述了CPU在运行指令及加载和保存上下文所需的时间,放在应用上来讲表明了一个程序
线程:是进程中的更小单位,描述了执行一段指令所需的时间
(在浏览器中来讲,打开一个tab实际上是建立了一个进程,一个进程有多个线程,js引擎单线程、http请求线程等)

3四、针对前端js单线程和Web Worker多线程

js单线程却能够执行异步任务,主要是是js存在事件循环(enent loop)和任务队列(task queue)。
js当前线程中没有任何同步代码后才会执行异步代码;setTimeout是异步代码,只有等js空闲才会执行。
web worker是H5新标准,为js创造多线程环境;容许主线程建立worker线程,主线程运行同时worker线程在后台运行二者互不干扰;worker线程运行完会把结果返回给主线程。
web worker通常处理计算密集或高延迟任务,保证主线程流畅。
建立worker:var worker = new Worker(js文件路径)
web Worker使用
参考:HTML Web Workers
webworkers限制:同源限制;没法使用document、window、alert、confirm;没法加载本地资源

3五、函数柯里化

函数先填充几个参数,返回一个新的函数的技术
做用:在不侵入函数的前提下为函数预置通用参数,供屡次使用

const add = function add(x){
	return function(y){
		return x + y;
	}
}
const add1 = add(1);
add1(2) //3
add1(20) // 21

(add里面传递参数是x,add1里面参数是y)

3六、防抖与节流

是一种经常使用的高频触发优化方式(延时器setTimeout)
1)、防抖:
在第一次触发事件时,不当即执行函数,而是给出一个期限值好比200ms,而后200ms内没有再次触发滚动事件,那么就执行函数;在200ms内再次触发滚动事件,那么当前的计时取消,从新开始计时(经常使用于输入框)

function debounce = (fn, delay) => {
	var delay = delay || 500;
	var timer;
	return function() {
		var th = this;
		var args = arguments;
		if(timer) {
			clearTimeout(timer);
		}
		timer = setTimeout(function() {
			timer = null;
			fn.apply(th, args);
		}, delay);
	};
}

节流:每隔一段时间后执行一次,下降频率(每次触发事件都判断当前是否有等待执行的延时函数);经常使用于滚动

function throttle = (fn, interval) => {
	var last;
	var timer;
	var interval = interval || 500;
	return function() {
		var th = this;
		var args = arguments;
		var now = +new Date();
		if(last && now - last < interval) {
			clearTimeout(timer);
			timer = setTimeout(function() {
				last = now;
				fn.apply(th, args);
			}, interval);
		} else {
			last = now;
			fn.apply(th, args);
		}
	}
}

3七、for of 遍历对象

for…of…: 它是es6新增的一个遍历方法,但只限于迭代器(iterator), 因此普通的对象用for…of遍历是会报错的。下面来讲明一下如何用for…of…遍历普通对象

1)、类数组对象:用Array.from转成数组便可

var obj = {
    0:'one',
    1:'two',
    length: 2
};
obj = Array.from(obj);
for(var k of obj){
    console.log(k)
}

2)、非类数组对象:添加一个[Symbol.iterator]属性,并指向一个迭代器便可

var obj = {
    a:1,
    b:2,
    c:3
};
obj[Symbol.iterator] = function*(){
    var keys = Object.keys(obj);
    for(var k of keys){
        yield [k,obj[k]]
    }
};
for(var [k,v] of obj){
    console.log(k,v);
}

3八、怎样在ES5中实现 let 和 const

1)、能够经过匿名函数和闭包的形式来模拟let,用匿名函数的做用域来模拟块级做用域

(function(){
	var a = 3;
	console.log(a) //3
})
console.log(a) //undefined

2)、const:除了块级做用域,还不能修改,不能重复声明

数据属性
定义在对象内部的数据有四个特征:

configurable:是否能够被 delete 删除或者改变特征值
enumerable:是否能经过 for-in 循环遍历返回属性
writable:是否能够修改属性的值
value:保存这个属性的数据值

function _const(key, value) {
  window[key] = value;
  Object.defineProperty(window, key, {
    enumerable: false,
    configurable: false,
    get: function () {
      return value;
    },
    set: function (newValue) {
      if (newValue !== value) {
        throw TypeError("这是只读变量,不可修改");
      } else {
        return value;
      }
    },
  });
}
_const('a',1)
_const('a',2) //报错

3九、ES5模拟箭头函数

箭头函数是没有本身的 this 的,使得this被强制绑定到第一个外层做用域,同时也不容许 new 箭头函数

function newArrowCheck(innerThis, outThis) {
    if (innerThis !== outThis) {
      throw new TypeError("Cannot instantiate an arrow function");
    }
}
var outThis = this;
var arrow = function arrow(b){
	newArrowCheck(this,outThis);
	return b;
}.bind(this);

先记录函数外部做用于的this
将外部的this经过bind绑定到arrow内部
arrow内部对比外部this和内部this,一致则通行,不一致则报错,这样arrow内部使用的就是外部环境的this了

40、balel编译原理

babel是一个转译器,由于它只是把同种语言的高版本规则翻译成低版本规则,而不像编译器那样,输出的是另外一种更低级的语言代码。
可是和编译器相似,babel的转译过程也分为三个阶段:parsing、transforming、generating,以ES6代码转译为ES5代码为例,babel转译的具体过程以下:

一、ES6代码输入
二、babylon进行解析,获得AST
三、plugin用babel-traverse对AST树进行遍历转译 ,获得新的AST树
四、用babel-generator经过AST树生成ES5代码

4一、前端缓存

浏览器第一次向服务器发起请求拿到结果,会根据 http 头的缓存标识决定是否缓存结果,是则将结果和缓存标识存入浏览器缓存中;
1)、http缓存:强缓存、协商缓存
强缓存:200
Expires:表明资源过时时间,由服务器返回提供(http1.0),在与max-age(http1.1)共存的状况下,优先级要低
Cache-Control:

  • no-store:全部内容不缓存
  • no-cache:缓存,可是每次缓存都会请求浏览器判断缓存资源是不是最新
  • max-age=x(秒):请求缓存后 x 秒内不在发起请求(http1.1)
  • s-maxage=x:代理服务器(CDN)请求源站缓存后 x 秒不在发起请求(只对 CDN 有效)
  • public:客户端和代理服务器(CDN)均可缓存
  • private:只有客户端能够缓存

协商缓存:304

  • Last-Modified / If-Modified-Since:第一次访问一个资源的时候,服务器返回最后修改时间 Last-Modified,再次请求时请求头里会带上 If-Modified-Since,值为上次请求服务器返回的 Last-Modified;对比值是否相同(相同则没修改),确认资源在这段时间是否修改过,没有返回304,有返回200,获取最新资源。
  • Etag / If-None-Match:Etag是经过一个校验码来对比资源是否更改过的,一个资源修改时校验码会改变。第一次请求,服务器返回一个 Etag字段,再次请求时请求头会带上 If-None-Match,值是上次返回的 Etag,而后对比。

2)、浏览器缓存:本地缓存(cookie、localStorage、sessionStorage)、默认缓存
本地存储小容量
cookie:4kb,请求时传递给服务器
localStorage:5M,永久存储
sessionStorage:5M,当标签页被关闭时,SessionStorage也会被清除

本地存储大容量:(在线编辑浏览器或者网页邮箱)
WebSql:50M左右,关系型数据库,已被 W3C 废弃。
IndexDB:50M左右,非关系型数据库,正常使用。

往返缓存:又被称为 BFCache,是浏览器前进后退按钮上为了提高渲染速度的一种策略;当用户前往新页面的时候,将当前页面的DOM保存到 BFCache 中,用户后退时直接从 BFCache 中加载,节省请求时间。

3)、缓存的好处

一、减少服务器压力
二、节省客户端流量,避免重复请求一样的内容

4二、重绘和回流

重绘:当render tree中的一些元素须要更新属性,而这些属性只是影响元素的外观,风格,而不会影响布局的,好比background-color。则就叫称为重绘。

回流:当render tree中的一部分(或所有)由于元素的规模尺寸,布局,隐藏等改变而须要从新构建。这就称为回流(reflow)。

回流必将引发重绘,而重绘不必定会引发回流。

4三、Canvas和svg的区别

canvas是H5提供的新绘图方法,svg很早就出现了
canvas基于像素点,是位图,放大缩小会失真,svg是用html标签绘制,放大缩小不会失真
canvas在js里面绘制,svg在html里面
canvas支持颜色比svg多
canvas没法修改已经绘制的图像,svg能够获取到标签进行修改

4四、浏览器最小字体是多少,如何实现10px

Chrome浏览器最小是12px
用Chrome的私有属性禁用浏览器文字大小调整的功能:-webkit-text-size-adjust:none;
或者

display:inline-bilck;
transform: scale(0.5)

4五、页面加载过程(url输入)

向浏览器输入地址
浏览器根据DNS服务器解析获得域名下的IP地址
向这个地址服务器发送HTTP请求
服务器接收到,处理并返回HTTP请求
浏览器接收服务器返回内容并渲染

4六、浏览器渲染过程

解析HTML生成DOM树,解析CSS生成CSSOM树(二者互不影响)
将DOM和CSSOM树结合,生成渲染树(只包含可见节点)
根据生成的渲染树,获得节点的几何信息进行布局,也叫回流
根据渲染树和回流获得的几何信息获得节点的像素进行重绘
将像素发送给 GPU ,而后经过操做系统的 Native GUI 的API 绘制
渲染过程(HTML、CSS)中遇到 js 会先暂停,等 js 执行完毕才会恢复构建
js 能够改变HTML 和 CSS ,因此须要在 HTML 和 CSS 构建完毕以后加载
若是CSS尚未构建完,js 想修改它,浏览器会延迟脚本执行和DOM 构建,直到完成 CSSOM的下载和构建在执行 js
script 标签加 async :异步加载js ,加载完就执行; defer:异步加载 js,等文本渲染结束后执行;

4七、常见状态码:

200:OK(请求成功)
204:No Content(服务器已经成功处理,可是未返回内容)
304:Not Modified(缓存未修改,服务器不返回资源,从缓存拿取)
400:Bad Request (客户端请求的语法错误)
401:Unauthorized(请求要求用户身份认证)
402:Payment Required (保留,未来使用)
403:Forbidden (服务器拒绝请求)
404:Not Found (接口不存在)
500:Internal Server Error(服务出错)
502:Bad Gateway(网关、代理服务器请求时出错)

4八、cookie 的属性有哪些,什么状况下属性不能够改变?

name(String ): cookie 名称,一旦建立不可改
value(Object): cookie 值
maxAge(int):Cookie失效时间,秒(正数,则Cookie在maxAge秒以后失效;负数,该Cookie为临时Cookie,关闭浏览器即失效)
secure(boolean):Cookie是否仅被使用安全协议传输。安全协议有HTTPS,SSL等
domain(String ):能够访问该Cookie的域名
path(String ):该Cookie使用路径
comment(String ):该Cookie的用处说明
version(int):该Cookie使用的版本号
size(int):大小

4九、对称加密和不对称加密

1)、对称加密:最快速、最简单的加密方式,加密和解密用的一样的密钥;
对称加密通常使用相对较小的密钥,通常在256B;由于密钥越大,加密越强,可是速度越慢;密钥的大小须要考虑安全性也要照顾到效率;

2)、不对称加密:为数据的加密与解密提供了一个很是安全的方法,它使用了一对密钥:公钥(public key)和私钥(private key);
私钥只能由一方安全保管,不能外泄,而公钥则能够发给任何请求它的人。

总结:

对称加密加密与解密使用的是一样的密钥,因此速度快,但因为须要将密钥在网络传输,因此安全性不高。
非对称加密使用了一对密钥,公钥与私钥,因此安全性高,但加密与解密速度慢。
解决的办法是将对称加密的密钥使用非对称加密的公钥进行加密,而后发送出去,接收方使用私钥进行解密获得对称加密的密钥,而后双方可使用对称加密来进行沟通。

50、元素在图层里的顺序

背景 => z-index为负 => 块级元素 => 浮动元素 => 行内元素 => z-index为正

5一、1px问题

1)、媒体查询利用设备像素比缩放,设置小数像素(小数像素兼容差)
2)、viewport + rem 方案(适合新项目,不适合老项目改动)
3)、设置border-image(须要精确的图片,圆角可能模糊)
4)、background-image渐变(没法实现圆角)
5)、box-shadow(没有圆角问题,缺点是颜色很差控制)
6)、transform:scale(0.5)(比较推荐)

5二、优雅降级和渐进加强(css)

优雅降级:向下兼容,先构建站点的完整功能,后针对浏览器测试和修复。(高版本->低版本)
渐进加强:向上兼容,先针对低版本浏览器构建页面,后针对高版本浏览器追加功能达到更好的体验。(低版本->高版本)

5三、margin合并

当两个垂直外边距(兄弟元素、父子元素)相遇时,它们将合并,合并后的外边距的高度等于高度较大的边距;水平方向不会合并。

一、只设置一个元素的边距
二、触发BFC

5四、margin塌陷

当给一个块级元素的第一个子元素设置margin-top时会带动父级盒子一块儿下移

一、父级元素设置边框或者padding边距(不推荐使用)
二、触发BFC

5五、BFC(块级格式上下文)

具备 BFC 特性的元素能够看做是隔离了的独立容器,容器里面的元素不会在布局上影响到外面的元素,而且 BFC 具备普通容器所没有的一些特性。

触发:

body 根元素
浮动元素:float 除 none 之外的值
绝对定位元素:position (absolute、fixed)
display 为 inline-block、table-cells、flex
overflow 除了 visible 之外的值 (hidden、auto、scroll)

特色:

同一个 BFC 下外边距会发生折叠
BFC 能够包含浮动的元素(清除浮动;父元素添加,防止子元素脱离文档流)
BFC 能够阻止元素被浮动元素覆盖

5六、水平垂直居中

1)、利用lineheight
适用行内块元素

{
	height:200px;
	line-height:200px;
	text-align:center;
}

2)、flex布局

{
	display: flex;
	justify-content: center;
    align-items: center;
}

3)、absolute + transform
须要给父元素添加 relative

	position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);

4)、absolute + margin auto
须要给父元素添加 relative

	position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    margin: auto;

5)、absolute + 负margin
须要给父元素添加 relative,而且已知子元素宽高(100px)

 	position: absolute;;
    top: 50%;
    left: 50%;
    margin-left: -50px;
    margin-top: -50px;

6)、css-table

.father {
    display: table-cell;
    text-align: center;
    vertical-align: middle;
}
.sun{
    display: inline-block;
}

5七、H5和CSS3

1)、H5

一、语义标签(有利于代码可读性和SEO):header、aside、time、footer等
二、新表单元素:type、email验证、url验证、autofocus等
三、canvas标签:绘制图像
四、支持内联SVG
五、拖放(drag、drop)
六、地理位置(Geolocation):用于定位用户的位置
七、视频和音频(video、Audio)
八、本地存储:sessionStorage、localStorage和indexedDB增强本地存储
九、Web SQL数据库
十、Web Workers:运行在后台的 JavaScript,不会影响页面的性能
十一、离线web应用:在没有网络状态能够运行应用
十二、SSE(服务器发送事件):网页自动获取来自服务器的更新
1三、WebSocket:单个 TCP 链接上进行全双工通信的协议

2)、CSS3

一、边框:圆角、阴影、边界图片
二、背景:图片、尺寸、定位区域、绘制区域
三、渐变
四、文本效果:阴影、换行、单词拆分
五、字体:加粗、样式、拉伸
六、2D 、3D
七、过渡:transition
八、动画:animation、@keyframes

5八、CSS样式叠加的结果

若是多个样式有重合,浏览器会根据权重的大小进行样式覆盖

一、!important,加在样式属性值后,权重值为 10000
二、内联样式,如:style=””,权重值为1000
三、ID选择器,如:#content,权重值为100
四、类,伪类和属性选择器,如: content、:hover 权重值为10
五、标签选择器和伪元素选择器,如:div、p、:before 权重值为1
通用选择器(*)、子选择器(>)、相邻选择器(+)、同胞选择器(~)、权重值为0

5九、移动端适配方案(vw)