Web前端面试题大全1000+面试题附答案详解,最全面详细,看完稳了

进大厂是大部分程序员的梦想,而进大厂的门槛也是比较高的,所以这里整理了一份阿里、美团、滴滴、头条等大厂面试大全,其中概括的知识点有:HTML、CSS、JavaScript、HTTP、TCP协议、浏览器、Vue、数据结构和算法等技术栈共有1000+道面试题。

对于Web前端的朋友来说应该是最全面最完整的面试备战仓库,为了更好地整理每个模块,我也参考了很多网上的优质博文和项目,力求不漏掉每一个知识点,很多朋友靠着这些内容进行复习,拿到了BATJ等大厂的offer, 也已经帮助了很多的前端学习者,希望也能帮助到你

因为文件太多,全部展示会影响篇幅,暂时就展示部分截图。欢迎大家一起交流,后台小信封【学习】撩我领取!

面试题整理十分全面,文末还有答案解析!(文章比较长,耐心看完,让你面试提升一大截!)

1.html语义化

2.canvas相关

3.svg和canvas的区别?

4. html5有哪些新特性?

5.如何处理HTML5新标签的浏览器兼容问题?

6.说说title和alt属性

7.HTML全局属性(global attribute)有哪些

1.让一个元素水平垂直居中,到底有多少种方案?

2.浮动布局的优点?有什么缺点?清除浮动有哪些方式?

3.使用display:inline-block会产生什么问题?解决方法?

4.布局题:div垂直居中,左右10px,高度始终为宽度一半

5.盒模型

6.cSS如何进行品字布局?

7.CSS如何进行圣杯布局

8.CSS如何实现双飞翼布局?

9.什么是BFC?

10.触发条件

11.BFC渲染规则

12.应用场景

13.画一个对话框

14.画一个平行四边形

15.用一个div画五角星

1.JS原始数据类型有哪些?引用数据类型有哪些?

2.说出下面运行的结果,解释原因。

3.null是对象吗?为什么?

4.\’1\’.toString0为什么可以调用?

5.0.1+0.2为什么不等于0.3?

6.什么是BigInt?

7.为什么需要BigInt?8.如何创建并使用BigInt?

9.typeof是否能正确判断类型?

10. instanceof能否判断基本数据类型?

11.能不能手动实现一下instanceof的功能?

12.Object.is和===的区别?

13.[]==![结果是什么?为什么?

14.JS中类型转换有哪几种?

15.==和===有什么区别?

16.对象转原始类型是根据什么流程运行的?

17.如何让if(a == 1 && a == 2)条件成立?

18.什么是闭包?

19.闭包产生的原因?

20.闭包有哪些表现形式?

21.如何解决下面的循环输出问题?

22.原型对象和构造函数有何关系?

23.能不能描述—下原型链?

24.JS如何实现继承?

25.函数的arguments为什么不是数组?如何转化成数组?

26. forEach中return有效果吗?如何中断forEach循环?

27.JS判断数组中是否包含某个值

28.JS中flat—数组扁平化

29.什么是高阶函数

30.数组中的高阶函数

31.能不能实现数组map方法?

32.能不能实现数组reduce方法?

33.能不能实现数组push.pop方法?

34.能不能实现数组filter方法?

35.能不能实现数组splice方法?

36.能不能实现数组sort方法?

37.能不能模拟实现一个new的效果?

38.能不能模拟实现一个bind的效果?

39.能不能实现一个call/apply 函数?

40.谈谈你对JS中this的理解

41.JS中浅拷贝的手段有哪些?

42.能不能写一个完整的深拷贝?

43.数据是如何存储的?

44.V8引擎如何进行垃圾内存的回收?

45.描述一下V8执行一段JS代码的过程?

46.宏任务(MacroTask)引入

47.微任务(MicroTask)引入

48.理解EventLoop:浏览器

49.理解EventLoop: nodejs

50.nodejs和浏览器关于eventLoop的主要区别

51.关于process.nextTick的一点说明

52.nodejs中的异步、非阻塞I/O是如何实现的?

53.JS异步编程有哪些方案?为什么会出现这些方案?

54.能不能简单实现一下node 中回调函数的机制?

55.Promise凭借什么消灭了回调地狱?

56.为什么Promise要引入微任务?

57.Promise如何实现链式调用?

58.实现Promise的resolve.reject和finally

59.现Promise的all和race

60.谈谈你对生成器以及协程的理解

61.如何让Generator 的异步代码按顺序执行完毕?

62.解释一下async/await的运行机制。

63. forEach中用await会产生什么问题?怎么解决这个问题?

64.关于JS中一些重要的api实现

65.事件流向

66.事件委托

1.HTTP报文结构是怎样的?

2.HTTP有哪些请求方法?

3.GET和POST有什么区别?

4.如何理解URI?

5.如何理解HTTP状态码?

6.简要概括一下 HTTP的特点?HTTP有哪些缺点?

7.对Accept系列字段了解多少?

8.对于定长和不定长的数据,HTTP是怎么传输的?

9.HTTP如何处理大文件的传输?

10.HTTP中如何处理表单数据的提交?

11.HTTP1.1如何解决HTTP的队头阻塞问题?

12.对Cookie了解多少?

13.如何理解HTTP代理?

14.如何理解HTTP缓存及缓存代理?

15.为什么产生代理缓存?

16.源服务器的缓存控制

17.客户端的缓存控制

18.什么是跨域?浏览器如何拦截响应?如何解决?

19.传统RSA握手

20.RSA和ECDHE 握手过程的区别

21.TLS 1.3做了哪些改进?

22.HTTP/2有哪些改进?

23.HTTP/2中的二进制帧是如何设计的?

1.能不能说一说TCP和UDP的区别?

2.说说TCP三次握手的过程?

3.为什么是三次而不是两次、四次?

4.三次握手过程中可以携带数据么?

5.同时打开会怎样?

6.说说TCP四次挥手的过程

7.为什么是四次挥手而不是三次?

8.同时关闭会怎样?

9.说说半连接队列和SYN Flood攻击的关系

10.如何应对SYIN Flood 攻击?

11.介绍一下TCP报文头部的字段

12.说说TCP快速打开的原理(TFO)

13.能不能说说TCP报文中时间戳的作用?

14.TCP的超时重传时间是如何计算的?

15.能不能说一说TCP的流量控制?

16.能不能说说TCP的拥塞控制?

17.能不能说说Nagle算法和延迟确认?

18.如何理解TCP的keep-alive?

1.能不能说─说浏览器爱存?

2能不能说—说浏览器的本地存储?各自优劣如何?

3.说—说从输入URL到页面呈现发生了什么?(网络)

4.说—说从输入URL到页面呈现发生了什么?(解析算法)

5.说一说从输入URL到页面呈现发生了什么?(渲染过程)

6.谈谈你对重绘和回流的理解

7.能不能说一说XSS攻击?

8.能不能说一说CSRF攻击?

9.HTTPS为什么让数据传输更安全?

10.能不能实现事件的防抖和节流?

11.能不能实现图片懒加载?

1.什么是MVVM?

2.mvvm和mvc区别?它和其它框架jquery)的区别是什么?哪些场景适合?

3.组件之间的传值?

4.Vue双向绑定原理

5.描述下vue 从初始化页面–修改数据–刷新页面U的过程?

6.你是如何理解Vue的响应式系统的?

7.虚拟DOM实现原理

8.Vue 中 key 值的作用?

9.Vue的生命周期

10. Vue 组件间通信有哪些方式?

11.vue 中怎么重置data?

12.组件中写name选项有什么作用?

13. vue-router有哪些钩子函数?

14. route和router的区别是什么?

15.说一下Vue和React的认识,做一个简单的对比

16.Vue 的nextTick的原理是什么?

17.Vuex有哪几种属性?

18. vue首屏加载优化

19. vuex

20.v-show和v-if指令的共同点和不同点

链表

1.简单的反转链表

2.区间反转

3.两个—组翻转链表

4.K个一组翻转链表

5.如何检测链表形成环?

6.如何找到环的起点

7.合并两个有序链表

8.合并K个有序链表

9.判断回文链表

栈和队列

1.有效括号

2.多维数组flatten

3.普通的层次遍历

4.二叉树的锯齿形层次遍历

5.二叉树的右视图

6.完全平方数

7.单词接龙

8.优先队列

9.关于堆的说明

10.实现一个最大堆

11.实现优先队列

12.前K个高频元素

13.合并K个排序链表

14.什么是双端队列?

15.滑动窗口最大值

16.栈实现队列

17.队列实现栈

二叉树

1.前序遍历

2.中序遍历

3.后序遍历

4.最大深度

5.最小深度

6.对称二叉树

7.二叉树的最近公共祖先

8.二叉搜索树的最近公共祖先

9.二叉树的直径

10.二叉树的所有路径

11.二叉树的最大路径和

12.验证二叉搜索树

13.将有序数组转换为二叉搜索树

14.二叉树展开为链表

15.不同的二叉搜索树П

所有的面试题目都不是一成不变的,上面的面试题只是给大家一个借鉴作用,最主要的是给自己增加知识的储备,有备无患。上面分享的2024最新1000+前端面试题的答案都整理成了PDF文档。

最新2024整理收集的一些前端学习资料(都整理成文档),有很多干货,包含HTML、CSS、JavaScript、HTTP、TCP协议、浏览器、Vue、数据结构和算法等详细讲解,也有详细的学习规划图,面试题整理等,

人生短暂,别稀里糊涂的活一辈子,不要将就。最近还有很多小伙伴想要学习Web前端进阶,不知道去哪领取,我这里有很多PDF资料,面试真题及答案应有尽有,

都是最近几年我在京东从事5年工作经验总结!面试常见的问题。程序员必备的技能核心知识点,这些对你的帮助都是很大的,通过我的学习笔记已经有很多人进入了梦寐以求的互联网大厂。

成功率高达85%!我就是有这个自信说出这话!有句话叫舍不得孩子套不住狼。想要达到你的目标就要不断的去学习进步,总有一天必能成为一位有的程序员!最后私信扣【学习】撩我领取学习资料!

web前端面试题合集

1.线程和进程是什么?举例说明

进程:cpu分配资源的最小单位(是能拥有资源和独立运行的最小单位)

线程:是cpu最小的调度单位(线程是建立在进程的基础上的一次程序运行单位,一个进程中可以有多个线程)

栗子:比如进程=火车,线程就是车厢

一个进程内有多个线程,执行过程是多条线程共同完成的,线程是进程的部分。

一个火车可以有多个车厢

每个进程都有独立的代码和数据空间,程序之间切换会产生较大的开销;线程可以看作轻量级的进程,同一类线程共享代码和数据空间,每个线程都有自己独立的运行栈和程序计数器,线程之间切换的开销小。

【多列火车比多个车厢更耗资源】

【一辆火车上的乘客很难换到另外一辆火车,比如站点换乘,但是同一辆火车上乘客很容易从A车厢换到B车厢】

同一进程的线程共享本进程的地址空间和资源,而进程之间的地址空间和资源是相互独立的

【一辆火车上不同车厢的人可以共用各节车厢的洗手间,但是不是火车上的乘客无法使用别的火车上的洗手间】

为什么js是单线程

JS是单线程的原因主要和JS的用途有关,JS主要实现浏览器与用户的交互,以及操作DOM。

如果JS被设计为多线程,如果一个线程要修改一个DOM元素,另一个线程要删除这个DOM元素,这时浏览器就不知道该怎么办,为了避免复杂的情况产生,所以JS是单线程的。

为了利用多核CPU的计算能力,HTML5提出Web Worker标准,允许JavaScript脚本创建多个线程,但是子线程完全受主线程控制,且不得操作DOM。所以,这个新标准并没有改变JavaScript单线程的本质。

2. js中的基础数据类型有哪几种? 了解包装对象吗?

答:六种,string, number, boolean, undefiend, null, symbol

基础数据类型临时创建的临时对象,称为包装对象。其中 number、boolean 和 string 有包装对象,代码运行的过程中会找到对应的包装对象,然后包装对象把属性和方法给了基本类型,然后包装对象被系统进行销毁。

3.对内存泄漏的了解

1. 理解

– 定义:程序中已在堆中分配的内存,因为某种原因未释放或者无法释放的问题

– 简单理解: 无用的内存还在占用,得不到释放和归还,比较严重的时候,无用的内存还会增加,从而导致整个系统卡顿,甚至崩溃。

2. 生命周期

1. 分配期

分配所需要的内存,在js中,是自动分配的

2. 使用期

使用分配的内存,就是读写变量或者对象的属性值

3. 释放期

不需要时将该内存释放,js会自动释放(除了闭包和一些bug以外)

内存泄漏就是出现在这个时期,内存没有被释放导致的

3. 可能出现内存泄漏的原因

1. 意外的全局变量

2. DOM元素清空时,还存在引用

3. 闭包

4. 遗忘的定时器

如何优化内存泄漏?

全局变量先声明在使用

避免过多使用闭包。

注意清除定时器和事件监听器。

4.js中数组合并的方法

js 数组合并

let arr1 = [\’温情\’, \’刘聪\’]

let arr2 = [\’杨和苏\’, \’邓紫棋\’]

let arr3 = [\’周延\’]

1. arr1.concat(arr2, ······)

es5 Array.concat() 合并两个数组, 返回新数组,不会改变原数组

arr = arr1.concat(arr2, arr3);

console.log(arr); // [\”温情\”, \”刘聪\”, \”杨和苏\”, \”邓紫棋\”, \”周延\”]

2. […arr1, …arr2,······]

es6 展开运算符(…)

arr = […arr1, …arr2, …arr3];

console.log(arr); // [\”温情\”, \”刘聪\”, \”杨和苏\”, \”邓紫棋\”, \”周延\”]

3. push(…arr)

push 结合 …[] 来实现, 会更改原数组

arr1.push(…arr2, …arr3)

console.log(arr1); // [\”温情\”, \”刘聪\”, \”杨和苏\”, \”邓紫棋\”, \”周延\”

适合两个数组,不适合多个数组的方法

1. for + push

for(let i in arr2) {

arr1.push(arr2[i])

}

console.log(arr1); // [\”温情\”, \”刘聪\”, \”杨和苏\”, \”邓紫棋\”]

2. arr1.push.apply(arr1, arr2)

arr1.push.apply(arr1, arr2)

console.log(arr1); // [\”温情\”, \”刘聪\”, \”杨和苏\”, \”邓紫棋\”]

5.合并对象的方法

Object.assign()

es6 Object.assign()方法用于对象的合并,将源对象(source)的所有可枚举属性,复制到目标对象(target)

Object.assign()方法的第一个参数是目标对象,后面的参数都是源对象。

let obj1 = {name: \’温情\’}

let obj2 = {age: \’22\’}

const newObj = Object.assign({}, obj1, obj2);

console.log(newObj); // {name: \”温情\”, age: \”22\”}

!注意! Object.assign()实行的是浅拷贝,也就是说如果源对象的属性是一个对象,那么目标对象得到的是这个对象的引用

let obj1 = {name: {chinese: \’杨和苏\’, english: \’keyNG\’}}

const newObj = Object.assign({}, obj1);

console.log(newObj); // name: {chinese: \”杨和苏\”, english: \”keyNG\”}

obj1.name.english = \’pig\’;

console.log(newObj); // name: {chinese: \”杨和苏\”, english: \”pig\”}

6.什么是作用域,什么是作用域链?

规定变量和函数的可使用范围称为作用域

查找变量或者函数时,需要从局部作用域到全局作用域依次查找,这些作用域的集合称作用域链。

7.JS如何实现异步编程(5种)?

1)回调函数(callback)

优点:解决了同步的问题(只要有一个任务耗时很长,后面的任务都必须排队等着,会拖延整个程序的执行。)

缺点:回调地狱,每个任务只能指定一个回调函数,不能 return.

2)事件监听。这种思路是说异步任务的执行不取决于代码的顺序,而取决于某个事件是否发生。比如一个我们注册一个按钮的点击事件或者注册一个自定义事件,然后通过点击或者trigger的方式触发这个事件。

3)Promise

4)Generator

5)生成器 async/await,是ES7提供的一种解决方案。

8.js中的堆内存与栈内存

在js引擎中对变量的存储主要有两种位置,堆内存和栈内存。

和java中对内存的处理类似,栈内存主要用于存储各种基本类型的变量,包括Boolean、Number、String、Undefined、Null,**以及对象变量的指针,这时候栈内存给人的感觉就像一个线性排列的空间,每个小单元大小基本相等。

而堆内存主要负责像对象Object这种变量类型的存储,如下图

栈内存中的变量一般都是已知大小或者有范围上限的,算作一种简单存储。而堆内存存储的对象类型数据对于大小这方面,一般都是未知的。个人认为,这也是为什么null作为一个object类型的变量却存储在栈内存中的原因。

因此当我们定义一个const对象的时候,我们说的常量其实是指针,就是const对象对应的堆内存指向是不变的,但是堆内存中的数据本身的大小或者属性是可变的。而对于const定义的基础变量而言,这个值就相当于const对象的指针,是不可变。

既然知道了const在内存中的存储,那么const、let定义的变量不能二次定义的流程也就比较容易猜出来了,每次使用const或者let去初始化一个变量的时候,会首先遍历当前的内存栈,看看有没有重名变量,有的话就返回错误。

说到这里,有一个十分很容易忽略的点,之前也是自己一直没有注意的就是,使用new关键字初始化的之后是不存储在栈内存中的。为什么呢?new大家都知道,根据构造函数生成新实例,这个时候生成的是对象,而不是基本类型。再看一个例子

我们可以看到new一个String,出来的是对象,而直接字面量赋值和工厂模式出来的都是字符串。但是根据我们上面的分析大小相对固定可预期的即便是对象也可以存储在栈内存的,比如null,为啥这个不是呢?再继续看

很明显,如果a,b是存储在栈内存中的话,两者应该是明显相等的,就像null === null是true一样,但结果两者并不相等,说明两者都是存储在堆内存中的,指针指向不一致。

9.如何去判断js数据类型?

首先我们可以用typeof去判断,typeof只能判断基本数据类型,对于引用数据类型,- -律返回object,在js中,数组是一种特殊的对象类型, 因此typeof-个数组,返回的是object.

还可以通过instanceof来判断,它不能检测基本数据类型,它是用来判断个实例是否属于某种类型, 使用它的方式可以用Ainstanceof B,如果A是B的实例,则返回true,否则返回flase。

然后还可以用constructor来判断,除了undefined和nul1之外,其它类型都可以通过constructor来判断,

但是如果声明了一个构造函数,并且把它的原型指向改变了,这种情况下,constructor也不能准确的判断。

通过0bject . prototype . toString,判断一个对象 只属于某种内置类型,但是不能准确的判断一个实例是否属于某种类型。

原因是因为实例对象可能会自定义toString方法,把这个方法给覆盖掉,我们可以通过函数. call( )方法,可以在任意值上调用这个方法,帮助我们判断这个值的类型。

10,怎么允许跨域(跨域解决办法)

A、JSONP

在页面上,js脚本,css样式文件,图片这三种资源是可以与页面本身不同源的。jsonp就利用了script标签进行跨域取得数据。

JSONP允许用户传递一个callback参数给服务器端,然后服务器端返回数据时会将这个callback参数作为函数名来包裹住JSON数据。这样客户端就可以随意定制自己的函数来自动处理返回的数据了。

JSONP只能解决get请求,不能解决post请求。

<script>

function callback(data){

console.log(data);

}

</script>

<script src=\”http://localhost:80/?callback=callback\”></script>

使用ajax实现跨域:

<script src=\”http://code.jquery.com/jquery-latest.js\”></script>

$.ajax({

url:\’http://localhost:80/?callback=callback\’,

method:\’get\’,

dataType:\’jsonp\’, //=> 执行jsonp请求

success:(res) => {

console.log(res);

}

})

function callback(data){

console.log(data);

}

B、 CORS跨域资源共享:

浏览器会自动进行CORS通信,实现CORS通信的关键是后端。服务端设置Access-Control-Allow-Origin就可以开启CORS。该属性表示哪些域名跨域访问资源。

主要设置以下几个属性:

Access-Control-Allow-Origin//允许跨域的域名

Access-Control-Allow-Headers//允许的header类型

Access-Control-Allow-Methods//跨域允许的请求方式

C、Nginx反向代理

通过nginx配置一个代理服务器将客户机请求转发给内部网络上的目标服务器;并将服务器上返回的结果返回给客户端。

D、webpack (在vue.config.js文件中)中 配置webpack-dev-server

devServer: {

proxy: {

\’/api\’: {

target: \”http://39.98.123.211\”,

changeOrigin: true, //是否跨域

},

},

},

11.怎么让对象的一个属性不可被改变

(1) Object.defineProperty()

可以使用Object.defineProperty()方法,让对象的某一个属性不可变,把对象某一属性的writable和configurable设置为false.

let obj = {a:1,b:2};

Object.defineProperty(obj,\’c\’,{

value:100000,

writable:false,//当该属性的 writable 键值为 true 时,属性的值才能被赋值操作修改

configurable:false//当为true时,该属性的描述符才能够被改变,同时该属性也能从对应的对象上被删除。

})

obj.c = 282031283

console.log(obj.c)//100000

2)object.preventExtensions()

让对象不能添加新属性,可以使用object.preventExtensions()方法。(但是可以修改属性值)

let obj = {a:1,b:2};

Object.preventExtensions(obj);

obj.c = 1000;

console.log(obj)

12.浏览器所用的内核

IE:Trident内核

Chrome:以前是webkit内核,现在是Blink内核

Firefox:Gecko(/ˈɡekoʊ/)内核

Safari:webkit内核

Opera:最初使用的是presto内核,后来加入谷歌大军,从webkit内核又变成了Blink内核

360,猎豹浏览器:IE+chrome双内核

13、判断一个函数是普通函数还是构造函数(补全funcA(){})

构造函数中this指向new创建的实例。所以可通过在函数内部判断this是否为当前函数的实例进而判断当前函数是否作为构造函数。

function A(){

if(this instanceof A){

console.log(\’我是构造函数\’)

}else{

console.log(\’我是普通函数\’)

}

}

A();

new A();

14.JavaScript 中的提升是什么?

提升意味着所有的声明都被移动到作用域的顶部。这发生在代码运行之前。

对于函数,这意味着你可以从作用域中的任何位置调用它们,甚至在它们被定义之前。

hello(); // Prints \”Hello world! \” even though the function is called \”before\” declaration

function hello(){

console.log(\”Hello world! \”);

}

对于变量,提升有点不同。它在作用域的顶部将 undefined 分配给它们。

例如,在定义变量之前调用它:

console.log(dog);//undefined

var dog = \”Spot\”;

结果是:

undefined

这可能令人惊讶,因为你可能预计它会导致错误。

用var声明一个函数或变量,无论你在哪里声明它,它总是被移动到作用域的顶部。

15、js有哪些内置对象? 

数据封装类对象:Object、Array、Boolean、Number 和 String

其他对象:Function、Arguments、Math、Date、RegExp、Error….

前端经典面试题(60道前端面试题包含JS、CSS、React、浏览器等)

防抖

触发高频事件后n秒内函数只会执行一次,如果n秒内高频事件再次被触发,则重新计算时间

  • 思路:

每次触发事件时都取消之前的延时调用方法

节流

高频事件触发,但在n秒内只会执行一次,所以节流会稀释函数的执行频率

  • 思路:

每次触发事件时都判断当前是否有等待执行的延时函数

误区:我们经常说get请求参数的大小存在限制,而post请求的参数大小是无限制的。

实际上HTTP 协议从未规定 GET/POST 的请求长度限制是多少。对get请求参数的限制是来源与浏览器或web服务器,浏览器或web服务器限制了url的长度。为了明确这个概念,我们必须再次强调下面几点:

  • HTTP 协议 未规定 GET 和POST的长度限制
  • GET的最大长度显示是因为 浏览器和 web服务器限制了 URI的长度
  • 不同的浏览器和WEB服务器,限制的最大长度不一样
  • 要支持IE,则最大长度为2083byte,若只支持Chrome,则最大长度 8182byte

补充补充一个get和post在缓存方面的区别:

  • get请求类似于查找的过程,用户获取数据,可以不用每次都与数据库连接,所以可以使用缓存。
  • post不同,post做的一般是修改和删除的工作,所以必须与数据库交互,所以不能使用缓存。因此get请求适合于请求缓存。

可从IIFE、AMD、CMD、CommonJS、UMD、webpack(require.ensure)、ES Module、<script type=\”module\”> 这几个角度考虑。

模块化主要是用来抽离公共代码,隔离作用域,避免变量冲突等。

IIFE:使用自执行函数来编写模块化,特点:在一个单独的函数作用域中执行代码,避免变量冲突

AMD:使用requireJS 来编写模块化,特点:依赖必须提前声明好

CMD:使用seaJS 来编写模块化,特点:支持动态引入依赖文件

CommonJS:nodejs 中自带的模块化。

UMD:兼容AMD,CommonJS 模块化语法。

webpack(require.ensure):webpack 2.x 版本中的代码分割。

ES Modules:ES6 引入的模块化,支持import 来引入另一个 js 。

  • 发出npm install命令
  • 查询node_modules目录之中是否已经存在指定模块
    • npm 向 registry 查询模块压缩包的网址
    • 下载压缩包,存放在根目录下的.npm目录里
    • 解压压缩包到当前项目的node_modules目录
    • 若存在,不再重新安装
    • 若不存在

输入 npm install 命令并敲下回车后,会经历如下几个阶段(以 npm 5.5.1 为例):

  1. 执行工程自身 preinstall当前 npm 工程如果定义了 preinstall 钩子此时会被执行。
  2. 确定首层依赖模块首先需要做的是确定工程中的首层依赖,也就是 dependencies 和 devDependencies 属性中直接指定的模块(假设此时没有添加 npm install 参数)。工程本身是整棵依赖树的根节点,每个首层依赖模块都是根节点下面的一棵子树,npm 会开启多进程从每个首层依赖模块开始逐步寻找更深层级的节点。
  3. 获取模块获取模块是一个递归的过程,分为以下几步:
  • 获取模块信息。在下载一个模块之前,首先要确定其版本,这是因为 package.json 中往往是 semantic version(semver,语义化版本)。此时如果版本描述文件(npm-shrinkwrap.json 或 package-lock.json)中有该模块信息直接拿即可,如果没有则从仓库获取。如 packaeg.json 中某个包的版本是 ^1.1.0,npm 就会去仓库中获取符合 1.x.x 形式的最新版本。
  • 获取模块实体。上一步会获取到模块的压缩包地址(resolved 字段),npm 会用此地址检查本地缓存,缓存中有就直接拿,如果没有则从仓库下载。
  • 查找该模块依赖,如果有依赖则回到第1步,如果没有则停止。
  • 模块扁平化(dedupe)上一步获取到的是一棵完整的依赖树,其中可能包含大量重复模块。比如 A 模块依赖于 loadsh,B 模块同样依赖于 lodash。在 npm3 以前会严格按照依赖树的结构进行安装,因此会造成模块冗余。从 npm3 开始默认加入了一个 dedupe 的过程。它会遍历所有节点,逐个将模块放在根节点下面,也就是 node-modules 的第一层。当发现有重复模块时,则将其丢弃。这里需要对重复模块进行一个定义,它指的是模块名相同semver 兼容。每个 semver 都对应一段版本允许范围,如果两个模块的版本允许范围存在交集,那么就可以得到一个兼容版本,而不必版本号完全一致,这可以使更多冗余模块在 dedupe 过程中被去掉。比如 node-modules 下 foo 模块依赖 lodash@^1.0.0,bar 模块依赖 lodash@^1.1.0,则 ^1.1.0 为兼容版本。而当 foo 依赖 lodash@^2.0.0,bar 依赖 lodash@^1.1.0,则依据 semver 的规则,二者不存在兼容版本。会将一个版本放在 node_modules 中,另一个仍保留在依赖树里。举个例子,假设一个依赖树原本是这样:node_modules — foo —- lodash@version1– bar —- lodash@version2假设 version1 和 version2 是兼容版本,则经过 dedupe 会成为下面的形式:node_modules — foo– bar– lodash(保留的版本为兼容版本)假设 version1 和 version2 为非兼容版本,则后面的版本保留在依赖树中:node_modules — foo — lodash@version1– bar —- lodash@version2
  • 安装模块这一步将会更新工程中的 node_modules,并执行模块中的生命周期函数(按照 preinstall、install、postinstall 的顺序)。
  • 执行工程自身生命周期当前 npm 工程如果定义了钩子此时会被执行(按照 install、postinstall、prepublish、prepare 的顺序)。最后一步是生成或更新版本描述文件,npm install 过程完成。
  • ES5的继承时通过prototype或构造函数机制来实现。ES5的继承实质上是先创建子类的实例对象,然后再将父类的方法添加到this上(Parent.apply(this))。

    ES6的继承机制完全不同,实质上是先创建父类的实例对象this(所以必须先调用父类的super()方法),然后再用子类的构造函数修改this

    具体的:ES6通过class关键字定义类,里面有构造方法,类之间通过extends关键字实现继承。子类必须在constructor方法中调用super方法,否则新建实例报错。因为子类没有自己的this对象,而是继承了父类的this对象,然后对其进行加工。如果不调用super方法,子类得不到this对象。

    ps:super关键字指代父类的实例,即父类的this对象。在子类构造函数中,调用super后,才可使用this关键字,否则报错。

    参考答案

    **因为js是单线程的,浏览器遇到setTimeout或者setInterval会先执行完当前的代码块,在此之前会把定时器推入浏览器的待执行事件队列里面,等到浏览器执行完当前代码之后会看一下事件队列里面有没有任务,有的话才执行定时器的代码。**所以即使把定时器的时间设置为0还是会先执行当前的一些代码。

    输出结果:

    输出:[1, NaN, NaN]

    • 首先让我们回顾一下,map函数的第一个参数callback:

    var new_array = arr.map(function callback(currentValue[, index[, array]]) { // Return element for new_array }[, thisArg])这个callback一共可以接收三个参数,其中第一个参数代表当前被处理的元素,而第二个参数代表该元素的索引。

    • 而parseInt则是用来解析字符串的,使字符串成为指定基数的整数。parseInt(string, radix)接收两个参数,第一个表示被处理的值(字符串),第二个表示为解析时的基数。
    • 了解这两个函数后,我们可以模拟一下运行情况
    1. parseInt(\’1\’, 0) //radix为0时,且string参数不以“0x”和“0”开头时,按照10为基数处理。这个时候返回1
    2. parseInt(\’2\’, 1) //基数为1(1进制)表示的数中,最大值小于2,所以无法解析,返回NaN
    3. parseInt(\’3\’, 2) //基数为2(2进制)表示的数中,最大值小于3,所以无法解析,返回NaN
    • map函数返回的是一个数组,所以最后结果为[1, NaN, NaN]

    Doctype声明于文档最前面,告诉浏览器以何种方式来渲染页面,这里有两种模式,严格模式和混杂模式。

    • 严格模式的排版和 JS 运作模式是 以该浏览器支持的最高标准运行。
    • 混杂模式,向后兼容,模拟老式浏览器,防止浏览器无法兼容页面。

    fetch发送post请求的时候,总是发送2次,第一次状态码是204,第二次才成功?

    原因很简单,因为你用fetch的post请求的时候,导致fetch 第一次发送了一个Options请求,询问服务器是否支持修改的请求头,如果服务器支持,则在第二次中发送真正的请求。

    • location.href– 返回或设置当前文档的URL
    • location.search — 返回URL中的查询字符串部分。例如 http://www.dreamdu.com/dreamd… 返回包括(?)后面的内容?id=5&name=dreamdu
    • location.hash — 返回URL#后面的内容,如果没有#,返回空 location.host — 返回URL中的域名部分,例如http://www.dreamdu.com
    • location.hostname — 返回URL中的主域名部分,例如http://dreamdu.com
    • location.pathname — 返回URL的域名后的部分。例如 http://www.dreamdu.com/xhtml/ 返回/xhtml/
    • location.port — 返回URL中的端口部分。例如 http://www.dreamdu.com:8080/xhtml/ 返回8080
    • location.protocol — 返回URL中的协议部分。例如 http://www.dreamdu.com:8080/xhtml/ 返回(//)前面的内容http:
    • location.assign — 设置当前文档的URL
    • location.replace() — 设置当前文档的URL,并且在history对象的地址列表中移除这个URL location.replace(url);
    • location.reload() — 重载当前页面

    history对象

    • history.go() — 前进或后退指定的页面数
    • history.go(num); history.back() — 后退一页
    • history.forward() — 前进一页

    Navigator对象

    • navigator.userAgent — 返回用户代理头的字符串表示(就是包括浏览器版本信息等的字符串)
    • navigator.cookieEnabled — 返回浏览器是否支持(启用)cookie

    共同点:都是保存在浏览器端,并且是同源的

    • Cookie:cookie数据始终在同源的http请求中携带(即使不需要),即cookie在浏览器和服务器间来回传递。而sessionStorage和localStorage不会自动把数据发给服务器,仅在本地保存。cookie数据还有路径(path)的概念,可以限制cookie只属于某个路径下,存储的大小很小只有4K左右。(key:可以在浏览器和服务器端来回传递,存储容量小,只有大约4K左右)
    • sessionStorage:仅在当前浏览器窗口关闭前有效,自然也就不可能持久保持,localStorage:始终有效,窗口或浏览器关闭也一直保存,因此用作持久数据;cookie只在设置的cookie过期时间之前一直有效,即使窗口或浏览器关闭。(key:本身就是一个回话过程,关闭浏览器后消失,session为一个回话,当页面不同即使是同一页面打开两次,也被视为同一次回话)
    • localStorage:localStorage 在所有同源窗口中都是共享的;cookie也是在所有同源窗口中都是共享的。(key:同源窗口都会共享,并且不会失效,不管窗口或者浏览器关闭与否都会始终生效)

    补充说明一下cookie的作用:

    • 保存用户登录状态。例如将用户id存储于一个cookie内,这样当用户下次访问该页面时就不需要重新登录了,现在很多论坛和社区都提供这样的功能。cookie还可以设置过期时间,当超过时间期限后,cookie就会自动消失。因此,系统往往可以提示用户保持登录状态的时间:常见选项有一个月、三个 月、一年等。
    • 跟踪用户行为。例如一个天气预报网站,能够根据用户选择的地区显示当地的天气情况。如果每次都需要选择所在地是烦琐的,当利用了 cookie后就会显得很人性化了,系统能够记住上一次访问的地区,当下次再打开该页面时,它就会自动显示上次用户所在地区的天气情况。因为一切都是在后 台完成,所以这样的页面就像为某个用户所定制的一样,使用起来非常方便
    • 定制页面。如果网站提供了换肤或更换布局的功能,那么可以使用cookie来记录用户的选项,例如:背景色、分辨率等。当用户下次访问时,仍然可以保存上一次访问的界面风格。

    XSS(跨站脚本攻击)是指攻击者在返回的HTML中嵌入javascript脚本,为了减轻这些攻击,需要在HTTP头部配上,set-cookie:

    • httponly-这个属性可以防止XSS,它会禁止javascript脚本来访问cookie。
    • secure – 这个属性告诉浏览器仅在请求为https的时候发送cookie。

    结果应该是这样的:Set-Cookie=…..

    其中一个主要的区别在于浏览器的event loop 和nodejs的event loop 在处理异步事件的顺序是不同的,nodejs中有micro event;其中Promise属于micro event 该异步事件的处理顺序就和浏览器不同.nodejs V11.0以上 这两者之间的顺序就相同了.

    https协议由 http + ssl 协议构成,具体的链接过程可参考SSL或TLS握手的概述

    中间人攻击过程如下:

    1. 服务器向客户端发送公钥。
    2. 攻击者截获公钥,保留在自己手上。
    3. 然后攻击者自己生成一个【伪造的】公钥,发给客户端。
    4. 客户端收到伪造的公钥后,生成加密hash值发给服务器。
    5. 攻击者获得加密hash值,用自己的私钥解密获得真秘钥。
    6. 同时生成假的加密hash值,发给服务器。
    7. 服务器用私钥解密获得假秘钥。
    8. 服务器用加秘钥加密传输信息

    防范方法:

    1. 服务端在发送浏览器的公钥中加入CA证书,浏览器可以验证CA证书的有效性

    (1). 减少HTTP请求数

    这条策略基本上所有前端人都知道,而且也是最重要最有效的。都说要减少HTTP请求,那请求多了到底会怎么样呢?首先,每个请求都是有成本的,既包 含时间成本也包含资源成本。一个完整的请求都需要经过DNS寻址、与服务器建立连接、发送数据、等待服务器响应、接收数据这样一个“漫长”而复杂的过程。时间成本就是用户需要看到或者“感受”到这个资源是必须要等待这个过程结束的,资源上由于每个请求都需要携带数据,因此每个请求都需要占用带宽。

    另外,由于浏览器进行并发请求的请求数是有上限的,因此请求数多了以后,浏览器需要分批进行请求,因此会增加用户的等待时间,会给 用户造成站点速度慢这样一个印象,即使可能用户能看到的第一屏的资源都已经请求完了,但是浏览器的进度条会一直存在。减少HTTP请求数的主要途径包括:

    (2). 从设计实现层面简化页面

    如果你的页面像百度首页一样简单,那么接下来的规则基本上都用不着了。保持页面简洁、减少资源的使用时最直接的。如果不是这样,你的页面需要华丽的皮肤,则继续阅读下面的内容。

    (3). 合理设置HTTP缓存

    缓存的力量是强大的,恰当的缓存设置可以大大的减少HTTP请求。以有啊首页为例,当浏览器没有缓存的时候访问一共会发出78个请求,共600多K 数据(如图1.1),而当第二次访问即浏览器已缓存之后访问则仅有10个请求,共20多K数据(如图1.2)。(这里需要说明的是,如果直接F5刷新页面 的话效果是不一样的,这种情况下请求数还是一样,不过被缓存资源的请求服务器是304响应,只有Header没有Body,可以节省带宽)

    怎样才算合理设置?原则很简单,能缓存越多越好,能缓存越久越好。例如,很少变化的图片资源可以直接通过HTTP Header中的Expires设置一个很长的过期头;变化不频繁而又可能会变的资源可以使用Last-Modifed来做请求验证。尽可能的让资源能够 在缓存中待得更久。

    (4). 资源合并与压缩

    如果可以的话,尽可能的将外部的脚本、样式进行合并,多个合为一个。另外,CSS、Javascript、Image都可以用相应的工具进行压缩,压缩后往往能省下不少空间。

    (5). CSS Sprites

    合并CSS图片,减少请求数的又一个好办法。

    (6). Inline Images

    使用data: URL scheme的方式将图片嵌入到页面或CSS中,如果不考虑资源管理上的问题的话,不失为一个好办法。如果是嵌入页面的话换来的是增大了页面的体积,而且无法利用浏览器缓存。使用在CSS中的图片则更为理想一些。

    (7). Lazy Load Images

    这条策略实际上并不一定能减少HTTP请求数,但是却能在某些条件下或者页面刚加载时减少HTTP请求数。对于图片而言,在页面刚加载的时候可以只 加载第一屏,当用户继续往后滚屏的时候才加载后续的图片。这样一来,假如用户只对第一屏的内容感兴趣时,那剩余的图片请求就都节省了。有啊首页曾经的做法 是在加载的时候把第一屏之后的图片地址缓存在Textarea标签中,待用户往下滚屏的时候才“惰性”加载。

    重绘(Repaint)和回流(Reflow)

    重绘和回流是渲染步骤中的一小节,但是这两个步骤对于性能影响很大。

    • 重绘是当节点需要更改外观而不会影响布局的,比如改变 color就叫称为重绘
    • 回流是布局或者几何属性需要改变就称为回流。

    回流必定会发生重绘,重绘不一定会引发回流。回流所需的成本比重绘高的多,改变深层次的节点很可能导致父节点的一系列回流。

    所以以下几个动作可能会导致性能问题:

    • 改变 window 大小
    • 改变字体
    • 添加或删除样式
    • 文字改变
    • 定位或者浮动
    • 盒模型

    很多人不知道的是,重绘和回流其实和 Event loop 有关。

    1. 当 Event loop 执行完 Microtasks 后,会判断 document 是否需要更新。因为浏览器是 60Hz 的刷新率,每 16ms 才会更新一次。
    2. 然后判断是否有 resize或者 scroll,有的话会去触发事件,所以 resizescroll事件也是至少 16ms 才会触发一次,并且自带节流功能。
    3. 判断是否触发了 media query
    4. 更新动画并且发送事件
    5. 判断是否有全屏操作事件
    6. 执行 requestAnimationFrame回调
    7. 执行 IntersectionObserver回调,该方法用于判断元素是否可见,可以用于懒加载上,但是兼容性不好
    8. 更新界面
    9. 以上就是一帧中可能会做的事情。如果在一帧中有空闲时间,就会去执行 requestIdleCallback回调。

    减少重绘和回流

    • 使用 translate 替代 top<div class=\”test\”></div><style>.test {position: absolute;top: 10px;width: 100px;height: 100px;background: red;}</style><script>setTimeout(() => {// 引起回流document.querySelector(\’.test\’).style.top = \’100px\’}, 1000)</script>
    • 使用 visibility替换 display: none,因为前者只会引起重绘,后者会引发回流(改变了布局)把 DOM 离线后修改,比如:先把 DOM 给 display:none(有一次 Reflow),然后你修改100次,然后再把它显示出来不要把 DOM 结点的属性值放在一个循环里当成循环里的变量for(let i = 0; i < 1000; i++) {// 获取 offsetTop 会导致回流,因为需要去获取正确的值console.log(document.querySelector(\’.test\’).style.offsetTop)}
    • 不要使用 table 布局,可能很小的一个小改动会造成整个 table 的重新布局
    • 动画实现的速度的选择,动画速度越快,回流次数越多,也可以选择使用 requestAnimationFrame
    • CSS 选择符从右往左匹配查找,避免 DOM 深度过深
    • 将频繁运行的动画变为图层,图层能够阻止该节点回流影响别的元素。比如对于 video标签,浏览器会自动将该节点变为图层。

    vue和react都是采用diff算法来对比新旧虚拟节点,从而更新节点。在vue的diff函数中(建议先了解一下diff算法过程)。在交叉对比中,当新节点跟旧节点头尾交叉对比没有结果时,会根据新节点的key去对比旧节点数组中的key,从而找到相应旧节点(这里对应的是一个key => index 的map映射)。如果没找到就认为是一个新增节点。而如果没有key,那么就会采用遍历查找的方式去找到对应的旧节点。一种一个map映射,另一种是遍历查找。相比而言。map映射的速度更快。vue部分源码如下:

    创建map函数

    遍历寻找

    在React中,如果是由React引发的事件处理(比如通过onClick引发的事件处理),调用setState不会同步更新this.state,除此之外的setState调用会同步执行this.state。所谓“除此之外”,指的是绕过React通过addEventListener直接添加的事件处理函数,还有通过setTimeout/setInterval产生的异步调用。

    **原因:**在React的setState函数实现中,会根据一个变量isBatchingUpdates判断是直接更新this.state还是放到队列中回头再说,而isBatchingUpdates默认是false,也就表示setState会同步更新this.state,但是,有一个函数batchedUpdates,这个函数会把isBatchingUpdates修改为true,而当React在调用事件处理函数之前就会调用这个batchedUpdates,造成的后果,就是由React控制的事件处理过程setState不会同步更新this.state

    虚拟dom相当于在js和真实dom中间加了一个缓存,利用dom diff算法避免了没有必要的dom操作,从而提高性能。

    具体实现步骤如下:

    用 JavaScript 对象结构表示 DOM 树的结构;然后用这个树构建一个真正的 DOM 树,插到文档当中

    当状态变更的时候,重新构造一棵新的对象树。然后用新的树和旧的树进行比较,记录两棵树差异

    把2所记录的差异应用到步骤1所构建的真正的DOM树上,视图就更新了。

    结构:display:none: 会让元素完全从渲染树中消失,渲染的时候不占据任何空间, 不能点击, visibility: hidden:不会让元素从渲染树消失,渲染元素继续占据空间,只是内容不可见,不能点击 opacity: 0: 不会让元素从渲染树消失,渲染元素继续占据空间,只是内容不可见,可以点击

    继承:display: none:是非继承属性,子孙节点消失由于元素从渲染树消失造成,通过修改子孙节点属性无法显示。visibility: hidden:是继承属性,子孙节点消失由于继承了hidden,通过设置visibility: visible;可以让子孙节点显式。

    性能:displaynone : 修改元素会造成文档回流,读屏器不会读取display: none元素内容,性能消耗较大 visibility:hidden: 修改元素只会造成本元素的重绘,性能消耗较少读屏器读取visibility: hidden元素内容 opacity: 0 :修改元素会造成重绘,性能消耗较少

    联系:它们都能让元素不可见

    常用的一般为三种.clearfix, clear:both,overflow:hidden;

    比较好是 .clearfix,伪元素万金油版本,后两者有局限性.

    clear:both:若是用在同一个容器内相邻元素上,那是贼好的,有时候在容器外就有些问题了, 比如相邻容器的包裹层元素塌陷

    overflow:hidden:这种若是用在同个容器内,可以形成 BFC避免浮动造成的元素塌陷

    概念:将多个小图片拼接到一个图片中。通过 background-position 和元素尺寸调节需要显示的背景图案。

    优点:

    1. 减少 HTTP 请求数,极大地提高页面加载速度
    2. 增加图片信息重复度,提高压缩比,减少图片大小
    3. 更换风格方便,只需在一张或几张图片上修改颜色或样式即可实现

    缺点:

    1. 图片合并麻烦
    2. 维护麻烦,修改一个图片可能需要重新布局整个图片,样式
    1. link是 HTML 方式, @import是 CSS 方式
    2. link最大限度支持并行下载,@import过多嵌套导致串行下载,出现FOUC
    3. link可以通过rel=\”alternate stylesheet\”指定候选样式
    4. 浏览器对link支持早于@import,可以使用@import对老浏览器隐藏样式
    5. @import必须在样式规则之前,可以在 css 文件中引用其他文件
    6. 总体来说:link 优于@import

    block元素特点:

    1.处于常规流中时,如果width没有设置,会自动填充满父容器 2.可以应用margin/padding 3.在没有设置高度的情况下会扩展高度以包含常规流中的子元素 4.处于常规流中时布局时在前后元素位置之间(独占一个水平空间) 5.忽略vertical-align

    inline元素特点

    1.水平方向上根据direction依次布局

    2.不会在元素前后进行换行

    3.受white-space控制

    4.margin/padding在竖直方向上无效,水平方向上有效

    5.width/height属性对非替换行内元素无效,宽度由元素内容决定

    6.非替换行内元素的行框高由line-height确定,替换行内元素的行框高由height,margin,padding,border决定 7.浮动或绝对定位时会转换为block8.vertical-align属性生效

    1. 容器元素闭合标签前添加额外元素并设置clear: both
    2. 父元素触发块级格式化上下文(见块级可视化上下文部分)
    3. 设置容器元素伪元素进行清理推荐的清理浮动方法

    GIF:

    1. 8 位像素,256 色
    2. 无损压缩
    3. 支持简单动画
    4. 支持 boolean 透明
    5. 适合简单动画

    JPEG

    1. 颜色限于 256
    2. 有损压缩
    3. 可控制压缩质量
    4. 不支持透明
    5. 适合照片

    PNG

    1. 有 PNG8 和 truecolor PNG
    2. PNG8 类似 GIF 颜色上限为 256,文件小,支持 alpha 透明度,无动画
    3. 适合图标、背景、按钮
    1. 如果display为 none,那么 position 和 float 都不起作用,这种情况下元素不产生框
    2. 否则,如果 position 值为 absolute 或者 fixed,框就是绝对定位的,float 的计算值为 none,display 根据下面的表格进行调整。
    3. 否则,如果 float 不是 none,框是浮动的,display 根据下表进行调整
    4. 否则,如果元素是根元素,display 根据下表进行调整
    5. 其他情况下 display 的值为指定值 总结起来:绝对定位、浮动、根元素都需要调整display
    • 如果需要居中的元素为常规流中 inline 元素,为父元素设置text-align: center;即可实现
    • 如果需要居中的元素为常规流中 block 元素,1)为元素设置宽度,2)设置左右 margin 为 auto。3)IE6 下需在父元素上设置text-align: center;,再给子元素恢复需要的值
    • <body><div class=\”content\”>aaaaaa aaaaaa a a a a a a a a</div></body><style>body {background: #DDD;text-align: center; /* 3 */}.content {width: 500px; /* 1 */text-align: left; /* 3 */margin: 0 auto; /* 2 */background: purple;}</style>
    • 如果需要居中的元素为浮动元素,1)为元素设置宽度,2)position: relative;,3)浮动方向偏移量(left 或者 right)设置为 50%,4)浮动方向上的 margin 设置为元素宽度一半乘以-1<body><div class=\”content\”>aaaaaa aaaaaa a a a a a a a a</div></body><style>body {background: #DDD;}.content {width: 500px; /* 1 */float: left;position: relative; /* 2 */left: 50%; /* 3 */margin-left: -250px; /* 4 */background-color: purple;}</style>
    • 如果需要居中的元素为绝对定位元素,1)为元素设置宽度,2)偏移量设置为 50%,3)偏移方向外边距设置为元素宽度一半乘以-1<body><div class=\”content\”>aaaaaa aaaaaa a a a a a a a a</div></body><style>body {background: #DDD;position: relative;}.content {width: 800px;position: absolute;left: 50%;margin-left: -400px;background-color: purple;}</style>
    • 如果需要居中的元素为绝对定位元素,1)为元素设置宽度,2)设置左右偏移量都为 0,3)设置左右外边距都为 auto<body><div class=\”content\”>aaaaaa aaaaaa a a a a a a a a</div></body><style>body {background: #DDD;position: relative;}.content {width: 800px;position: absolute;margin: 0 auto;left: 0;right: 0;background-color: purple;}</style>

    七种数据类型

    • Boolean
    • Null
    • Undefined
    • Number
    • String
    • Symbol (ECMAScript 6 新定义)
    • Object

    (ES6之前)其中5种为基本类型:string,number,boolean,null,undefined,

    ES6出来的Symbol也是原始数据类型 ,表示独一无二的值

    Object为引用类型(范围挺大),也包括数组、函数,

    输出结果是:

    工厂模式

    简单的工厂模式可以理解为解决多个相似的问题;

    单例模式

    只能被实例化(构造函数给实例添加属性与方法)一次

    沙箱模式

    将一些函数放到自执行函数里面,但要用闭包暴露接口,用变量接收暴露的接口,再调用里面的值,否则无法使用里面的值

    发布者订阅模式

    就例如如我们关注了某一个公众号,然后他对应的有新的消息就会给你推送,

    代码实现逻辑是用数组存贮订阅者, 发布者回调函数里面通知的方式是遍历订阅者数组,并将发布者内容传入订阅者数组

    1.字面量

    2.Object构造函数创建

    3.使用工厂模式创建对象

    4.使用构造函数创建对象

    HTML中与javascript交互是通过事件驱动来实现的,例如鼠标点击事件onclick、页面的滚动事件onscroll等等,可以向文档或者文档中的元素添加事件侦听器来预订事件。想要知道这些事件是在什么时候进行调用的,就需要了解一下“事件流”的概念。

    什么是事件流:事件流描述的是从页面中接收事件的顺序,DOM2级事件流包括下面几个阶段。

    • 事件捕获阶段
    • 处于目标阶段
    • 事件冒泡阶段

    addEventListeneraddEventListener是DOM2 级事件新增的指定事件处理程序的操作,这个方法接收3个参数:要处理的事件名、作为事件处理程序的函数和一个布尔值。最后这个布尔值参数如果是true,表示在捕获阶段调用事件处理程序;如果是false,表示在冒泡阶段调用事件处理程序。

    IE只支持事件冒泡

    获取一个对象的原型,在chrome中可以通过__proto__的形式,或者在ES6中可以通过Object.getPrototypeOf的形式。

    那么Function.proto是什么么?也就是说Function由什么对象继承而来,我们来做如下判别。

    我们发现Function的原型也是Function。

    我们用图可以来明确这个关系:

    • 原型(prototype): 一个简单的对象,用于实现对象的 属性继承。可以简单的理解成对象的爹。在 Firefox 和 Chrome 中,每个JavaScript对象中都包含一个__proto__(非标准)的属性指向它爹(该对象的原型),可obj.__proto__进行访问。
    • 构造函数: 可以通过new新建一个对象的函数。
    • 实例: 通过构造函数和new创建出来的对象,便是实例。实例通过__proto__指向原型,通过constructor指向构造函数

    这里来举个栗子,以Object为例,我们常用的Object便是一个构造函数,因此我们可以通过它构建实例。

    则此时, 实例为instance, 构造函数为Object,我们知道,构造函数拥有一个prototype的属性指向原型,因此原型为:

    这里我们可以来看出三者的关系:

    在 JS 中,继承通常指的便是 原型链继承,也就是通过指定原型,并可以通过原型链继承原型上的属性或者方法。

    • 最优化: 圣杯模式var inherit = (function(c,p){var F = function(){};return function(c,p){F.prototype = p.prototype;c.prototype = new F();c.uber = p.prototype;c.prototype.constructor = c;}})();
    • 使用 ES6 的语法糖 class / extends

    在函数式编程中,函数是一等公民。那么函数柯里化是怎样的呢?

    函数柯里化指的是将能够接收多个参数的函数转化为接收单一参数的函数,并且返回接收余下参数且返回结果的新函数的技术。

    函数柯里化的主要作用和特点就是参数复用、提前返回和延迟执行。

    在一个函数中,首先填充几个参数,然后再返回一个新的函数的技术,称为函数的柯里化。通常可用于在不侵入函数的前提下,为函数 预置通用参数,供多次重复调用。

    callapply 都是为了解决改变 this 的指向。作用都是相同的,只是传参的方式不同。

    除了第一个参数外,call 可以接收一个参数列表,apply 只接受一个参数数组。

    bind和其他两个方法作用也是一致的,只是该方法会返回一个函数。并且我们可以通过 bind实现柯里化。

    如何实现一个 bind 函数

    对于实现以下几个函数,可以从几个方面思考

    • 不传入第一个参数,那么默认为 window
    • 改变了 this 指向,让新的对象可以执行该函数。那么思路是否可以变成给新的对象添加一个函数,然后在执行完以后删除?

    如何实现一个call函数

    如何实现一个apply函数

    箭头函数其实是没有 this的,这个函数中的 this只取决于他外面的第一个不是箭头函数的函数的 this。在这个例子中,因为调用 a符合前面代码中的第一个情况,所以 thiswindow。并且 this一旦绑定了上下文,就不会被任何代码改变。

    • A: Lydiaundefined
    • B: LydiaReferenceError
    • C: ReferenceError21
    • D: undefinedReferenceError

    在函数中,我们首先使用var关键字声明了name变量。这意味着变量在创建阶段会被提升(JavaScript会在创建变量创建阶段为其分配内存空间),默认值为undefined,直到我们实际执行到使用该变量的行。我们还没有为name变量赋值,所以它仍然保持undefined的值。

    使用let关键字(和const)声明的变量也会存在变量提升,但与var不同,初始化没有被提升。在我们声明(初始化)它们之前,它们是不可访问的。这被称为“暂时死区”。当我们在声明变量之前尝试访问变量时,JavaScript会抛出一个ReferenceError

    关于let的是否存在变量提升,我们何以用下面的例子来验证:

    let变量如果不存在变量提升,console.log(name)就会输出ConardLi,结果却抛出了ReferenceError,那么这很好的说明了,let也存在变量提升,但是它存在一个“暂时死区”,在变量未初始化或赋值前不允许访问。

    变量的赋值可以分为三个阶段:

    • 创建变量,在内存中开辟空间
    • 初始化变量,将变量初始化为undefined
    • 真正赋值

    关于letvarfunction

    • let的「创建」过程被提升了,但是初始化没有提升。
    • var的「创建」和「初始化」都被提升了。
    • function的「创建」「初始化」和「赋值」都被提升了。

    依次输出:undefined -> 10 -> 20

    • A: orange
    • B: purple
    • C: green
    • D: TypeError

    答案: D

    colorChange方法是静态的。静态方法仅在创建它们的构造函数中存在,并且不能传递给任何子级。由于freddie是一个子级对象,函数不会传递,所以在freddie实例上不存在freddie方法:抛出TypeError

    因为==会进行隐式类型转换 所以我们重写toString方法就可以了

    1.使用第一次push,obj对象的push方法设置 obj[2]=1;obj.length+=12.使用第二次push,obj对象的push方法设置 obj[3]=2;obj.length+=13.使用console.log输出的时候,因为obj具有 length 属性和 splice 方法,故将其作为数组进行打印 4.打印时因为数组未设置下标为 0 1 处的值,故打印为empty,主动 obj[0] 获取为 undefined

    undefined {n:2}

    首先,a和b同时引用了{n:2}对象,接着执行到a.x = a = {n:2}语句,尽管赋值是从右到左的没错,但是.的优先级比=要高,所以这里首先执行a.x,相当于为a(或者b)所指向的{n:1}对象新增了一个属性x,即此时对象将变为{n:1;x:undefined}。之后按正常情况,从右到左进行赋值,此时执行a ={n:2}的时候,a的引用改变,指向了新对象{n:2},而b依然指向的是旧对象。之后执行a.x = {n:2}的时候,并不会重新解析一遍a,而是沿用最初解析a.x时候的a,也即旧对象,故此时旧对象的x的值为{n:2},旧对象为 {n:1;x:{n:2}},它被b引用着。后面输出a.x的时候,又要解析a了,此时的a是指向新对象的a,而这个新对象是没有x属性的,故访问时输出undefined;而访问b.x的时候,将输出旧对象的x的值,即{n:2}。

    Hmm.. You don\’t have an age I guess

    在比较相等性,原始类型通过它们的值进行比较,而对象通过它们的引用进行比较。JavaScript检查对象是否具有对内存中相同位置的引用。

    我们作为参数传递的对象和我们用于检查相等性的对象在内存中位于不同位置,所以它们的引用是不同的。

    这就是为什么{ age: 18 } === { age: 18 }{ age: 18 } == { age: 18 }返回 false的原因。

    true` `true` `false` `true

    所有对象键(不包括Symbols)都会被存储为字符串,即使你没有给定字符串类型的键。这就是为什么obj.hasOwnProperty(\’1\’)也返回true

    上面的说法不适用于Set。在我们的Set中没有“1”set.has(\’1\’)返回false。它有数字类型1set.has(1)返回true

    这题考察的是对象的键名的转换。

    • 对象的键名只能是字符串和 Symbol 类型。
    • 其他类型的键名会被转换成字符串类型。
    • 对象转字符串默认会调用 toString 方法。

    1` `undefined` `2

    catch块接收参数x。当我们传递参数时,这与变量的x不同。这个变量x是属于catch作用域的。

    之后,我们将这个块级作用域的变量设置为1,并设置变量y的值。现在,我们打印块级作用域的变量x,它等于1

    catch块之外,x仍然是undefined,而y2。当我们想在catch块之外的console.log(x)时,它返回undefined,而y返回2

    输出顺序是 4 2 1

    作者:静观流叶

    原文地址:https://mp.weixin.qq.com/s/PTSaytcf3xgOp6C9l3Pvjw

    本文作者及来源:Renderbus瑞云渲染农场https://www.renderbus.com

    点赞 0
    收藏 0

    文章为作者独立观点不代本网立场,未经允许不得转载。