一二面(基础面)
1. 一面基础面
1.1 面试准备
1.1.1 个人简历
基本信息: 姓名 - 年龄 - 手机 - 邮箱 - 籍贯
工作经历: 时间 - 公司 - 岗位 - 职责 - 技术栈 - 业绩(哪些成就)
学历: 博士> 硕士> 本科> 大专
工作经历: 时间 - 公司 - 岗位 - 职责 - 技术栈 - 业绩
开源项目: GitHub 和说明
1.2.2 自我陈述
1.2.2.1 把我面试的沟通方向(别把自己带到坑里面)
答: 我平时喜欢研究一些网站, 并对一些技术的原理和好玩的点感兴趣, 我自己也喜欢思考, 也喜欢尝试探索有没有更好的方式和实现.(有所收留, 不要全部说出来, 稍微留一点悬念留作面试官来提问)
1.2.2.2 豁达, 自信的适度发挥
答: 适当自信, 向自己擅长的方向上面来引路; 要让面试官来欣赏我, 而不是来鄙视他.
1.2.2.3 自如谈兴趣
(豁达自信, 适当收住), 巧妙演示实例, 适时讨论疑问(不知道的问题请求指导一下, 如何去解决, 不要说不知道, 或者不了解)
1.2.2.4 节奏要适宜
切忌小聪明(尽量把问题的所有实现方法都写出来, 表现出来的是熟练)
1.2 面试实战
[!NOTE]
> 1. 方向要对, 过程要细(性能优化, 过程详细)
> 2. 胆子要大, 心态要和(算法题认真思考, 认真使劲想; 敢于承担责任, 不要轻易放弃)
2. CSS 相关
2.1 页面布局
2.1.1 如何实现垂直居中布局呢?
1. 已知宽高
- /*v1*/
- .container {
- position: absolute;
- left: 50%;
- top: 50%;
- marigin-left: -width / 2;
- marigin-top: -width / 2;
- }
- /*v2*/
- .container {
- position: absolute;
- top: calc(50% - 5em);
- left: calc(50% - 9em);
- }
2. 未知宽高
- /*v1*/
- .container {
- position: absolute;
- top: 50%;
- left: 50%;
- transform: translate(-50%, -50%);
- }
- /*v2:flex+ auto*/
- .wrapper {
- dislay: flex;
- }
- .content {
- margin: auto;
- }
- /*v3. 父元素居中 */
- .wrapper {
- display: flex;
- /* 盒子横轴的对齐方式 */
- justify-content: center;
- /* 盒子纵轴的对齐方式 */
- align-items: center;
- }
- /*v4.body 内部居中 */
- .content {
- /* 1vh = 1% * 视口高度 */
- margin: 50vh auto;
- transform: translateY(-50%);
- }
2.1.2 如何实现水平居中布局呢?
如果需要居中的元素为常规流中 inline / inline-block 元素, 为父元素设置 text-align: center;
父元素上设置 text-align: center; 居中元素上 margin 为 auto.
如果元素 positon: absolute; 那么
0)设置父元素 postion: relative
1)为元素设置宽度,
2)偏移量设置为 50%,
3)偏移方向外边距设置为元素宽度一半乘以 - 1
2.1.3 如何实现三栏布局呢?
left 和 right 写在 center 前面, 并且分别左右浮动;
左右区域分别 postion:absolute, 固定到左右两边; 中间的这个 div 因为是块级元素, 所以在水平方向上按照他的包容块自动撑开.
父元素 display: table; 并且宽度为 100%; 每一个子元素 display: table-cell; 左右两侧添加宽度, 中间不加宽度
包裹这个 3 个块的父元素 display: flex; 中间的元素 flex: 1;
网格布局
- /* 网格布局 */
- .wrapper {
- display: grid;
- width: 100%;
- grid-template-columns: 300px 1fr 300px;
- }
2.2 知道 CSS 动画的实现吗?
[!NOTE]
知道 transition 过渡动画和 animation 关键帧动画区别和具体实现.
1.CSS 动画实现轮播图
2.CSS 动画实现旋转的硬币
3.CSS 动画实现钟摆效果
2.3 CSS 盒子模型
2.3.1 说一下 CSS 的盒子模型? 标准模型和 IE 模型的区别? CSS 如何设置这两种模型?
标准盒子模型: width = content
IE 盒子模型: width = content + pading + border
- box-sizing : content-box
- box-sizing : border-box
2.4 CSS 样式获取
2.4.1 JS 如何设置获取盒子模型对应的宽度和高度?(面试重点)
dom.style.width/height : 只能取到内联样式的的属性信息(拿不到外部引入的 CSS 样式信息的)
dom.currentStyle.width/height : 会拿到浏览器渲染之后的属性信息(IE 浏览器)
Windows.getComputedStyle(dom).width/height : Chrome/Firefox 兼容, Firefox 可以通过 document.defaultView.getComputedStyle(dom)的方式来获取
dom.getBoundingClientRect().width/height : 可以获取距离 viewport 位置的宽度和高度
2.5 BFC
2.5.1 根据盒子模型解释边距额重叠问题? 边距重叠问题的解决方案?
父子元素
兄弟元素
其他 -------------------------- 计算方式: 以参数的最大值来进行计算
解决方案: 对父级元素创建 BFC
2.5.2 BFC 原理
[!NOTE]
BFC: 块级格式化上下文, IFC(内联格式化上下文)
在 BFC 的垂直边距上面会发生重叠
BFC 的区域不会与浮动元素的 BOX 重叠
BFC 在页面上是一个独立的渲染区域, 外部的元素不会影响到我, 同时也不会影响到外部的元素
计算 BFC 的高度的时候, 浮动元素也会参与运算
2.5.3 如何创建 BFC?
float 值不是 none
position 值不是 static 或者 relative
display 值为 table, table-cell, inline-box1.
overflow : auto/hidden
2.5.4 BFC 的使用场景?(重点理解)
解决边距的重叠问题
- <section id="margin">
- <style>
- #margin {
- background-color: #4eff35;
- overflow: hidden;
- }
- #margin>p {
- /* 上 左右 下 */
- margin: 5px auto 25px;
- background-color: #ff255f;
- }
- </style>
- <p>1</p>
- <!-- 把一个元素放在一个容器里面, 为这个容器创建 BFC 即可解决边距重叠问题 -->
- <div style="overflow: hidden">
- <p>2</p>
- </div>
- <p>3</p>
- </section>
BFC 不与 float 部分重叠的解决
- <section id="layout">
- <style>
- #layout {
- background-color: #48adff;
- }
- #layout .left {
- float: left;
- height: 300px;
- width: 200px;
- background-color: #ff4344;
- }
- #layout .right {
- height: 400px;
- background-color: #ff255f;
- /* 给右边的这个盒子容器创建一个 BFC, 这个容器里面的内容就会沿着垂直方向延伸 */
- overflow: auto;
- /*overflow: auto;*/
- /*display: table;*/
- /*float: left;*/
- /*position: fixed;*/
- }
- </style>
- <div class="left">
- LEFT
- </div>
- <div class="right">
- RIGHT
- <p>111</p>
- <p>111</p>
- <p>111</p>
- <p>111</p>
- <p>111</p>
- <p>111</p>
- <p>111</p>
- <p>111</p>
- <p>111</p>
- <p>111</p>
- <p>111</p>
- <p>111</p>
- <p>111</p>
- <p>111</p>
- <p>111</p>
- </div>
- </section>
BFC 子元素即使是 float 元素也要参与运算
- <section id="float">
- <style>
- /* 一个盒子内部的内容如果是浮动的话, 那么这个盒子的内容实际上是不参与父容器高度计算的 */
- #float {
- background-color: red;
- /*overflow: hidden;*/
- float: left;
- }
- #float .float {
- float: left;
- font-size: 30px;
- }
- </style>
- <div class="float">
我是浮动的元素
- </div>
- </section>
3. 事件相关
3.1 DOM 事件
3.1.1 DOM 事件的级别有哪些?
[!NOTE]
DOM 级别一共可以分为四个级别: DOM0 级, DOM1 级, DOM2 级和 DOM3 级. 而 DOM 事件分为 3 个级别: DOM0 级事件处理, DOM2 级事件处理和 DOM3 级事件处理.
DOM0 : element.onclick = function(e) {}
DOM1 : 该标准中未涉及到事件绑定的相关东西
DOM2 : element.addEventListener('click', function(e){}, false), 一个 DOM 元素可以添加多个事件
DOM3 : element.addEventListener('keyup', function(e){}, false), 在 DOM2 标准基础上面增加了新的事件类型: 鼠标事件, 键盘事件, 焦点事件
3.1.2 DOM 事件模型有哪些?
事件捕获: 从外向内, Windows -> document -> body -> button
事件冒泡: 从内向外, button -> body -> document -> Windows
3.1.3 DOM 事件流?
浏览器为当前的页面与用户进行交互的过程中, 点击鼠标后事件如何传入和响应的呢?
捕获阶段: 从外部容器开始向内
目标阶段: 事件通过捕获到达目标阶段
冒泡阶段: 从目标元素再上传到 Windows 对象
3.1.4 什么事件可以代理? 什么事件不可以代理呢?
什么样的事件可以用事件委托, 什么样的事件不可以用呢?
[!NOTE]
通常支持事件冒泡 (Event Bubbling) 的事件类型为鼠标事件和键盘事件, 例如: mouseover, mouseout, click, keydown, keypress.
接口事件 (指的是那些不一定与用户操作有关的事件) 则通常不支持事件冒泡(Event Bubbling), 例如: load, change, submit, focus, blur.
很明显: focus 和 blur 都属于不支持冒泡的接口事件. 既然都不支持冒泡, 那又如何实现事件代理呢?
3.1.5 IE 和 DOM 事件流的区别?
IE 采用冒泡型事件 Netscape 使用捕获型事件 DOM 使用先捕获后冒泡型事件
冒泡型事件模型: button -> div -> body (IE 浏览器本身只支持 Bubbling 不支持 Capturing)
捕获型事件模型: body -> div-> button (Netscape 事件流, 网景浏览器公司)
DOM 事件模型: body -> div -> button -> button -> div -> body (先捕获后冒泡, 除了 IE 以外的其他浏览器都支持标准的 DOM 事件处理模型)
[!NOTE]
规范和浏览器实现的差别?
DOM2 级事件规范的捕获阶段, 事件从文档节点 document 开始传播, 现代浏览器大多数都是从 Windows 对象开始传播事件的;
DOM2 级事件规范捕获阶段不涉及事件目标, 现代浏览器大多数都在这个阶段包含事件目标.
3.1.6 事件对象 event 的属性方法的差别?
- IE DOM
- cancelBubble = true stopPropagation() // 停止冒泡
- returnValue = false preventDefault() // 阻止元素默认事件
- srcEelement target // 事件目标
3.1.7 描述 DOM 事件捕获的具体流程?
Windows -> document -> HTML 标签 -> body -> ... -> 目标元素
[!NOTE]
关键点: 注意根节点是 Windows 这个对象的
- <!DOCTYPE HTML>
- <HTML lang="en">
- <head>
- <meta charset="UTF-8">
- <title>
- Title
- </title>
- </head>
- <body>
- <div id="container">
- <style>
- #container { width: 200px; height: 200px; background-color: #ff255f; }
- </style>
- </div>
- <script>
- // 事件捕获机制
- Windows.addEventListener('click',
- function() {
- console.log('window capture');
- },
- true) document.addEventListener('click',
- function() {
- console.log('document capture');
- },
- true) document.documentElement.addEventListener('click',
- function() {
- console.log('HTML capture');
- },
- true) document.body.addEventListener('click',
- function() {
- console.log('body capture');
- },
- true) document.getElementById('container').addEventListener('click',
- function() {
- console.log('container capture');
- },
- true)
- // 事件冒泡机制
- Windows.addEventListener('click',
- function() {
- console.log('window capture');
- }) document.addEventListener('click',
- function() {
- console.log('document capture');
- }) document.documentElement.addEventListener('click',
- function() {
- console.log('HTML capture');
- }) document.body.addEventListener('click',
- function() {
- console.log('body capture');
- }) document.getElementById('container').addEventListener('click',
- function() {
- console.log('container capture');
- })
- // 输出结果
- Windows capture-->document capture-->HTML capture-->body capture-->container capture-->container capture-->body capture-->HTML capture-->document capture-->Windows capture
- </script>
- </body>
- </HTML>
3.1.8 如何拿到 HTML 这个标签节点元素呢?(加分项)
var HTML = document.documentElement;
3.1.9 描述 Event 对象的常见应用?
e.preventDefault() : 阻止默认事件(如阻止 a 标签的默认跳转行为)
e.stopPropagation() : 阻止事件冒泡的行为
*** e.stopImmediatePropagation() : 事件响应的优先级的应用场景, 如果一个元素绑定了多个事件, 但是又不想让其他的事件执行的时候使用该方法[也会阻止冒泡]
e.currentTarget : 当前所绑定的事件对象
- document.documentElement.onclick = function(e) {
- console.log(e.currentTarget, e.target); // <HTML><body>...</body></HTML>()给绑定事件的那个元素, 当前被点击的那个元素
- }
- [!NOTE]
e.target : 当前被点击的元素, 父元素使用事件代理的方式来实现, 可以直接使用该属性获取被点击的那个元素
3.2 如何自定义事件?(重点))
3.2.1 如何给一个按钮绑定一个自己定义的事件呢?
- // v1. 使用 Event 对象来自定义事件
- // 开始创建一个自己定义的事件对象
- var eve = new Event('customEvent');
- // 使用 dom2 事件处理的方式来给这个元素绑定一个事件
- var dom = document.documentElement;
- dom.addEventListener('customEvent', function(e) {
- console.log('customEvent called!');
- });
- // 下面的这句话可以在适合的场景中来触发一个自己定义的事件对象
- setTimeout(function(){
- // 在 1s 之后触发这个事件
- dom.dispatchEvent(eve);
- }, 1000)
- // v2. 使用 CustomEvent 来实现自定义事件
- var dom = document.documentElement;
- // 使用 CustomEvent 的方式可以在事件触发的时候传递一个参数, 然后通过 e.detail 的方式来获取这个参数信息
- var myClick = new CustomEvent('myClick', {detail : {name : 'zhangsan', age : 24}});
- dom.addEventListener('myClick', function(e){
- console.log(e.detail, e.target)
- })
- dom.dispatchEvent(myClick);
4. HTTP 协议
4.1 HTTP 协议的主要特点?
简单快速
灵活
无连接
无状态
4.2 HTTP 报文的组成部分?
请求报文
请求行: 请求方法 资源地址 HTTP 版本
请求头: key : value
空行 :
请求体 : name=zhangsan&age=18
响应报文 : HTTP 版本 状态码
状态行
响应头
空行
响应体
4.3 HTTP 方法?
GET : 获取资源
POST : 传输资源
PUT : 更新资源
DELETE : 删除资源
HEAD : 获取报文首部
OPTIONS : 允许客户端查看服务器的性能.
4.4 POST 和 GET 的区别?
GET 请求在浏览器回退的时候是无害的, 而 POST 会再次提交请求
GET 请求产生的 URL 地址可以被收藏, 而 POST 不可以
GET 请求会被浏览器主动缓存, 而 POST 不会, 除非主动设置
GET 请求只能进行 URL 编码, 而 POST 支持多种编码方式
GET 请求参数会被完整第保留在浏览器的历史记录里面, 而 POST 参数不会被保留
GET 请求爱 URL 中传送的参数的长度是有限的(2KB), 而 POST 没有限制
对参数的数据类型, GET 值接受 ASCII 字符, 而 POST 没有限制
POST 比 GET 更安全, GET 参数直接暴露在 URL 上, 所以不能用来传递敏感信息
9. GET 参数通过 URL 传递, POST 参数直接放在了 Request body 中
4.5 HTTP 状态码?
4.5.1 状态码的第一位
1xx : 指示信息 - 表示请求已接收, 继续处理(重点)
2xx : 成功 - 表示请求已被成功接收
3xx : 重定向 - 要完成请求必须进行更进一步的操作
4xx : 客户端错误 - 请求有语法错误或请求无法实现
5xx : 服务器错误 - 服务器未能实现合法的请求
4.5.2 状态码详解
200 OK : 客户端请求成功
206 Partial Content : 客户端发送了一个带有 Range 头的 GET 请求(Video 标签或者 audio 标签在请求数据的时候)
301 Moved Permanently : 请求的页面已经转移到了新的 URL
302 Found : 所请求的页面已经临时转移到了新的 URL
304 Not Modified : 客户端有缓冲的文档并发出了一个条件下的请求, 原来缓冲的文档还可以继续使用
400 Bad Request : 客户端请求有语法错误, 不被服务器所理解
401 Unauthorized : 请求未经授权, 这个状态码必须和 WWW-Authenticate 报头域一起使用
403 Forbidden: 对被请求页面的访问被禁止
404 Not Found : 请求资源不存在
500 Internal Server Error : 服务器发生不可预期的错误, 原来缓冲的文档还可以继续使用
503 Service Unavailable : 请求未完成, 服务器临时过载或宕机, 一段时间后可能恢复正常
4.6 什么是持久连接?
[!NOTE]
HTTP 协议采用'请求 - 应答'模式, HTTP1.1 版本才支持的, 使用 Keep-alive 字段可以建立一个长连接, 从而不需要每次请求都去建立一个新的连接.
4.7 什么是管线化?
4.7.1 基本概念
在使用持久连接 (Keep-alive) 的情况下, 某个连接上的消息的传递类似于: 请求 1 --> 响应 1 --> 请求 2 --> 响应 2 --> 请求 3 --> 响应 3
管线化的过程: 请求 1 --> 请求 2 --> 请求 3 --> 响应 1 --> 响应 2 --> 响应 3
4.7.2 管线化的特点(特点)
管线化机制通过持久连接完成, 仅在 HTTP1.1 版本之后支持
只有 GET 和 HEAD 请求可以进行管线化, POST 有所限制的
初次创建连接的时候不应该启动管线机制, 因为对方 (服务器) 不一定支持 HTTP1.1 版本的协议
管线化不会影响到响应到来的顺序, HTTP 响应返回的顺序并未改变
HTTP1.1 要求服务器支持管线化, 但并不要求服务器也对响应进行管线化处理, 只是要求对于管线化的请求不失败即可
由于上面提到的服务器端问题, 开启管线化很可能并不会带来大幅度的性能提升, 而且很多服务器和代理程序对管线化的支持并不好, 因此现代的浏览器如 Chrome 和 Firefox 默认并没有开启管线化支持
5. 原型链
5.1 创建对象的几种方法?
- // 1. 使用字面量的方式来创建
- var o1 = {name : 'zhangsan'};
- var o11 = new Object({name : 'zhangsan'});
- // 2. 使用普通构造函数的方式来创建
- var M = function(){
- this.name = 'zhangsan';
- }
- var o2 = new M();
- // 3. Object.create 方法
- var p = {name : 'zhangsan'};
- var o3 = Object.create(p);
5.2 原型, 构造函数, 实例, 原型链?
构造函数: 使用 new 运算符来声明一个实例(任何函数都是可以通过构造函数来使用的)
原型链: 通过原型链可以找到上一级别的原型对象
原型对象: 多个实例公用的数据和属性或者方法
5.3 instanceof 的原理?
[!NOTE]
instanceof 检测一个对象 A 是不是另一个对象 B 的实例的原理是: 查看对象 B 的 prototype 指向的对象是否在对象 A 的 [[prototype]] 链上. 如果在, 则返回 true, 如果不在则返回 false. 不过有一个特殊的情况, 当对象 B 的 prototype 为 null 将会报错(类似于空指针异常).
- // 2. 使用普通构造函数的方式来创建
- var M = function(){
- this.name = 'zhangsan';
- }
- var o2 = new M();
- undefined
- o2.__proto__ == M.prototype
- true
- o2.__proto__ == M.prototype
- true
- o2.__proto__.constructor === Object
- false
- o2.__proto__.constructor === M
- true
5.4 new 运算符的原理?
一个新对象被创建. 它继承于 foo.prototype
构造函数 foo 被执行. 执行的时候, 相应的传参会被传入, 同时上下文 (this) 会被指定为这个新实例, new foo 等同于 new foo(), 只能用在不传递任何参数的情况
如果构造函数返回了一个 "对象", 那么这个对象会取代整个 new 出来的结果. 如果构造函数没有返回对象, 那么 new 出来的结果为步骤 1 创建的对象
- // new 一个对象的过程
- var _new = function (fn) {
- // 1. 创建一个对象, 这个对象要继承 fn 这个构造函数的原型对象
- var o = Object.create(fn.prototype);
- // 2. 执行构造函数
- var k = fn.call(o, arguments);
- // 3. 看下执行的这个函数的运行效果是不是函数
- if (typeof k === 'object'){
- return k;
- }
- else
- {
- return o;
- }
- }
6. 面向对象
6.1 类与继承: 如何实现继承, 继承的几种实现方式
- <!DOCTYPE HTML>
- <HTML lang="en">
- <head>
- <meta charset="UTF-8">
- <title>
- Title
- </title>
- </head>
- <body>
- <script>
- // 类的声明
- function Animal1() {
- this.name = 'name';
- }
- // ES6 中的 class 的声明
- class Animal2 {
- constructor() {
- this.name = 'name';
- }
- }
- console.log(new Animal1(), new Animal2());
- ///////////////////////////////////////////////////////////////////////////////////////////
- // 如何实现类的继承呢???----------- 本质: 原型链
- // v1. 借助构造函数实现继承
- function Parent1() {
- this.name = 'parent1'
- }
- Parent1.prototype.sayHello = function() {
- console.log('hello');
- }
- function Child1() {
- // 执行父亲的构造函数:
- // 1. 实现原理: 将父级函数的 this 指向了这个子类的实例上面去了
- // 2. 缺点: 父亲的原型链上面的方法或者属性不能被继承; 只能实现部分继承
- Parent1.call(this);
- this.type = 'child1';
- }
- // 没有参数的时候, 可以直接 new + 函数名称
- console.log(res = new Child1);
- // v2. 借助原型链实现继承
- function Parent2() {
- this.name = 'parent2';
- this.data = [1, 2, 3];
- }
- Parent2.prototype.sayHello = function() {
- console.log('hello');
- }
- function Child2() {
- this.type = 'child2';
- }
- // prototype 就是为了让这个对象的实例可以访问到原型链上的内容
- Child2.prototype = new Parent2();
- // new Child2().__proto__ === Child2.prototype // true
- // new Child2().__proto__.name // parent2
- // 原型链继承的缺点:
- // 1. 原理: 通过修改原型链来实现对象的继承关系
- // 2. 缺点: 修改第一个对象上面的属性, 会直接修改第二个对象属性数据(引用类型)
- var c1 = new Child2();
- var c2 = new Child2();
- c1.data.push(100, 200, 300);
- // v3. 组合继承
- function Parent3() {
- this.name = 'parent3';
- this.data = [1, 2, 3];
- }
- function Child3() {
- // 1. 借用构造函数继承
- Parent3.call(this);
- this.type = 'child3';
- }
- // 2. 原型链继承
- // child3 的原型对象是 Parent3 的一个实例对象, 但是这个实例对象中是没有 constructor 这个属性的, 因此寻找属性的时候回沿着这个实例对象的原型链继续向上寻找 new Parent3().prototype 这个原型对象的,
- // 最终在 Parent3.prototype 这个原型对象中找到了这个属性, new 一个对象找的实际上是{Parent3.prototype.constructor : Parent3}
- Child3.prototype = new Parent3();
- var c1 = new Child3();
- var c2 = new Child3();
- c1.data.push(100, 200, 300);
- // 组合继承的特点:
- // 1. 原理: 结合借用构造函数继承和原型链继承的优点, 摒弃二者的缺点
- // 2. 缺点: 父类构造函数在创建实例的时候总共执行了两次(new Parent3(), new Child3())
- // v4. 组合继承的优化 1
- function Parent4() {
- this.name = 'parent4';
- this.data = [1, 2, 3];
- }
- function Child4() {
- // 1. 借用构造函数继承
- Parent4.call(this);
- this.type = 'child4';
- }
- // 让子类的构造函数的原型对象和父类构造函数的原型对象执向同一个对象(都是同一个对象)
- Child4.prototype = Parent4.prototype;
- // 测试
- var c1 = new Child4();
- var c2 = new Child4();
- console.log(c1 instanceof Child4, c1 instanceof Parent4);
- console.log(c1.constructor) // Parent4? 如何实现: c1.constructor(c1.__proto__.constructor) === Child4 呢?
- // 缺点:
- // 1. 无法通过原型对象的 constructor 属性来获取对象的属性对应的构造函数了(子类和父类公用的是一个 contructor)
- // 2. obj instanceof Child4 === true; obj instanceof Parent4 === true
- // 3. obj.__proto__.constructor === Child4; obj.__proto__.constructor === Parent4 ???
- // v5. 组合继承的优化 2[完美写法]
- function Parent5() {
- this.name = 'parent5';
- this.data = [1, 2, 3, 4, 5];
- }
- function Child5() {
- Parent5.call(this);
- this.type = 'child5';
- }
- // 通过创建中间对象的方式来把两个对象区分开
- // var obj = new Object(); obj.__proto__ = Constructor.prototype;
- // 1. Object.create 创建的对象 obj, 这个 obj 的原型对象就是参数
- // 2. Child5 的原型对象是 Child5.prototype
- // 3. Child5.prototype = obj,obj 这个对象相当于就是一个中间的桥梁关系
- Child5.prototype = Object.create(Parent5.prototype);
- // 当前的方式还是会按照原型链一级一级向上寻找的, 给 Child5 的原型对象上面绑定一个自己定义的 constructor 属性
- Child5.prototype.constructor = Child5;
- // var s1 = new Child5()
- // 上面的代码等价于
- var obj = Object.create(Parent5.prototype); // obj.prototype = Parent5.prototype
- Child5.prototype = obj;
- Child5.prototype.constructor = Child5;
- // 1. 对象之间就是通过__proto__ 属性向上寻找的
- // 2. 寻找规则: child5 ---> Child5.prototype ---> obj(Object.create(Parent5.prototype)) ---> Parent5.prototype
- // 技巧: 不要让面试官问太多题目: 拖拉时间[挤牙膏] , 把一个问题尽量吃透
- // 消化这一块内容
- </script>
- </body>
- </HTML>
[!WARNING]
面试技巧
不要让面试官问太多题目: 拖拉时间[挤牙膏] , 把一个问题尽量吃透
知识深度
7. 通信
7.1 什么是同源策略个限制?
[!NOTE]
同源策略限制是从一个源加载的文档或脚本如何与来自另一个源的资源进行交互. 这是一个用于隔离潜在恶意文件的关键的安全机制.(一个源的文档或脚本是没有权利直接操作另外一个源的文档或脚本的)
Cookie, LocalStorage 和 IndexDB 无法读取
DOM 无法获得;(document.body 是无法获取的)
Ajax 请求不能发送
7.2 前后端如何进行通信呢?
Ajax(有同源策略限制);Fetch API 则是 XMLHttpRequest 的最新替代技术, 它是 W3C 的正式标准
WebSocket: 支持跨域请求数据, 没有同源策略的限制
CORS: 新的协议通信标准; CORS 则将导致跨域访问的请求分为三种: Simple Request,Preflighted Request 以及 Requests with Credential;cors 相对于 JSONP 而言的好处就是支持所有的请求方式, 不止是 get 请求, 还支持 post,put 请求等等, 而它的缺点就很明显, 无法兼容所有的浏览器, 对于要兼容到老式浏览器而言, 还是使用 JSONP 好点
7.3 如何创建 Ajax 呢?
XMLHttpRequest 对象的工作流程
浏览器的兼容性处理[重点]
事件的触发条件
事件的触发顺序
- function Ajax(params){
- // 1. 创建对象, 考虑兼容性[重点]
- var xhr = XMLHTTPRequest ? new XMLHTTPRequest() : new Windows.ActiveXObject('Microsoft.XMLHTTP'); //*** 兼容性问题必须考虑
- // 2. 打开连接
- var type = params.type || 'GET',
- url = params.url || '',
- data = params.data || {},
- success = params.success,
- error = params.error,
- dataArr = [];
- for (var k in data) {
- dataArr.push(k + '=' + data[k]);
- }
- // 带上 Cookie
- xhr.withCredentials = true;
- if (type.toUpperCase() === 'GET') {
- // get
- url += '?' + dataArr.join('&');
- // 问号结尾的话, 直接替换为空字符串
- xhr.open(type, url.replace(/\?$/g, ''), true);
- // GET 请求的话, 是不需要再 send 方法中带上参数的
- xhr.send();
- }
- else {
- // POST
- xhr.open(type, url, true);
- xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
- // POST 请求需要把数据放在 send 方法里面, data = name=zhangsna&age=18&sex=male
- xhr.send(dataArr.join('&'));
- }
- // 开始监听变化
- xhr.onreadystatechange = function(){
- // 这里需要考虑强缓存和协商缓存的话直接处理, 206 是媒体资源的创建方式
- if (xhr.readyState === 4 && xhr.status === 200 || xhr.status === 304) {
- var res;
- if (success instanceof Function) {
- res = xhr.responseText;
- if (typeof res === 'string') {
- res = JSON.parse(res);
- // 开始执行成功的回调函数
- success.call(xhr, res);
- }
- } else {
- if (error instanceof Function) {
- // 失败的话直接返回这个 responseText 中的内容信息
- error.call(xhr, res);
- }
- }
- }
- }
- }
7.4 跨域通信的几种方式?
- 7.4.1 JSONP
- function JSONP(url, onsuccess, onerror, charset){
- // 1. 全局注册一个 callback
- var callbackName = 'callback' + Math.random() * 100;
- Windows[callbackName] = function(){
- if (onsuccess && typeof onsuccess === 'Function') {
- onsuccess(arguments[0]);
- }
- }
- // 2. 动态创建一个 script 标签
- var script = document.createElement('script');
- script.setAttribute('type', 'text/javascript');
- charset && script.setAttribute('charset', charset);
- script.setAttribute('src', url);
- script.async = true;
- // 3. 开始监听处理的过程
- script.onload = script.onreadystatechange = function(){
- if (!script.readyState || /loaded|complete/.test(script.readyState)) {
- // 4. 成功之后移除这个事件
- script.onload = script.onreadystatechange = null;
- // 删除这个 script 的 DOM 对象(head.removeChild(script), 这个 DOM 节点的父节点相当于是 head 标签这个父节点)
- script.parentNode && script.parentNode.removeChild(script);
- // 删除函数或变量
- Windows[callbackName] = null;
- }
- }
- script.onerror = function(){
- if (onerror && typeof onerror === 'Function') {
- onerror();
- }
- }
- // 5. 开始发送这个请求(把这个标签放在页面中的 head 标签中即可)
- document.getElementsByTagName('head')[0].appendChild(script);
- }
- 7.4.2 Hash
hash 改变后页面不会刷新的
[!NOTE]
使用场景: 当前的页面 A 通过 iframe 或者 frame 嵌入了跨域的页面
- // 1. A 页面中的代码如下
- var B = document.getElementsByTagName('iframe');
- B.src = B.src + '#' + JSON.stringfy(data);
- // 2. B 中的伪代码如下
- Windows.onhashchange = function(){
- var data = Windows.location.hash; // 接受数据
- data = JSON.parse(data);
- }
- 7.4.3 postMessage(HTML5 中新增)
- [!NOTE]
使用场景: 可以实现窗口 A(A.com)向窗口 B(B.com)发送信息
- // 1. 窗口 B 中的代码如下
- var BWindow = Windows;
- BWindow.postMessage(JSON.stringfy(data), 'http://www.A.com');
- // 2. 窗口 A 中代码
- var AWindow = Windows;
- AWindow.addEventListener('message', function(e){
- console.log(e.origin); // http://www.B.com
- console.log(e.source); // BWindow
- e.source.postMessage('已成功收到消息');
- console.log(JSON.parse(e.data)); // data
- }, false)
- // 父窗口给子窗口发信息, 需要用 iframe 的 contentWindow 属性作为调用主体
- // 子窗口给父窗口发的信息需要使用 Windows.top, 多层 iframe 使用 Windows.frameElement
- 7.4.4 . WebSocket
- [!NOTE]
不受同源策略影响, 可以直接使用
- var ws = new Windows.WebSocket('ws://echo.websocket.org');
- // 打开连接
- ws.onopen = function(e){
- console.log('Connection open ......');
- ws.send('Hello WebSocket!');
- }
- // 接受消息
- ws.onmessage = function(e){
- console.log('Received Message :', e.data);
- }
- // 关闭连接
- ws.onclose = function(e){
- console.log('Connection closed');
- }
- 7.4.5 CORS
支持跨域通信版本的 Ajax, 是一种新的标准(Origin 头)[Ajax 的一个变种, 适用于任何]
- http://www.ruanyifeng.com/blog/2016/04/cors.html
- fetch('/get/name', {
- method : 'get'
- }).then(function(response){
- console.log(response);
- }).catch(function(err){
- // 出错了; 等价于 then 的第二个参数
- });
- // 原因: 浏览器默认会拦截 Ajax 请求, 会根据头中的 origin 消息进行判断处理消息; Origin 字段用来说明, 本次请求来自哪个源(协议 + 域名 + 端口). 服务器根据这个值, 决定是否同意这次请求. JSONP 只支持 GET 请求, CORS 支持所有类型的 HTTP 请求. JSONP 的优势在于支持老式浏览器, 以及可以向不支持 CORS 的网站请求数据.
7.4.5.1 CORS 请求的基本流程
对于简单请求, 浏览器直接发出 CORS 请求. 具体来说, 就是在头信息之中, 增加一个 Origin 字段.
Origin 字段用来说明, 本次请求来自哪个源(协议 + 域名 + 端口). 服务器根据这个值, 决定是否同意这次请求.
如果 Origin 指定的源, 不在许可范围内, 服务器会返回一个正常的 HTTP 回应. 浏览器发现, 这个回应的头信息没有包含 Access-Control-Allow-Origin 字段(详见下文), 就知道出错了, 从而抛出一个错误, 被 XMLHttpRequest 的 onerror 回调函数捕获.
如果 Origin 指定的域名在许可范围内, 服务器返回的响应, 会多出几个头信息字段.
- Access-Control-Allow-Origin: http://api.bob.com // 必需的字段
- Access-Control-Allow-Credentials: true // 可选字段: 是否允许发送 cookie
- Access-Control-Expose-Headers: FooBar
- Content-Type: text/HTML; charset=utf-8
简单请求的 CORS 请求, 会在正式通信之前, 增加一次 HTTP 查询请求, 称为 "预检" 请求(preflight).OPTIONS 表示当前的这个请求是用来询问的; 服务器收到 "预检" 请求以后, 检查了 Origin,Access-Control-Request-Method 和 Access-Control-Request-Headers 字段以后, 确认允许跨源请求, 就可以做出回应.
7.4.5.2 JSONP 和 CORS 的区别?
JSONP 只支持 GET 请求, CORS 支持所有类型的 HTTP 请求
JSONP 的优势在于支持老式浏览器, 以及可以向不支持 CORS 的网站请求数据.
8. 安全
8.1 CSRF
8.1.1 基本概念和缩写
CSRF: 跨站请求伪造, Cross site request forgery
8.1.2 CSRF 攻击原理
8.1.3 可以成功攻击的条件?
目标网站存在 CSRF 漏洞的请求接口(一般为 get 请求)
目标用户之前已经成功登录过这个网站(留下了 Cookie)
8.1.4 如何防御呢?
Token 验证: 访问服务器接口的时候, 会自动带上这个 token
Referer 验证: 验证网站的页面来源(只有我当前网站下的页面才可以请求, 对于来自其他网站的请求一律拦截)
隐藏令牌: 隐藏信息会放在 header 中(类似于 Token)
8.2 XSS
8.2.1 基本概念和缩写
XSS: cross-site scripting, 跨站脚本攻击
8.2.2 XSS 防御
攻击原理: 注入 JS 脚本
防御措施: 让 JS 代码无法解析执行
8.3 CSRF 和 XSS 的区别呢?
CSRF: 网站本身存在漏洞的接口, 依赖这些登录过目标网站的用户来实现信息的窃取;
XSS: 向页面中注入 JS 执行, JS 函数体内执行目标任务;
[!NOTE]
一定要说出中文名称, 实现原理, 防范措施都说出来
不要拖泥带水, 言简意赅
9. 算法
[!NOTE]
算法攻略: 多刷题才是硬道理!!!
二三面(知识深度面)
10. 渲染机制
10.1 什么是 DOCTYPE 及作用?
DTD(Document Type Definition): 文档类型定义, 是一系列的语法规则, 用来定义 xml 或者(X)HTML 的文件类型. 浏览器会使用它来判断文档的类型, 决定使用哪一种协议来解析, 以及切换浏览器模式;
DOCTYPE: 是用来声明文档类型和 DTD 规范的, 一个主要的用途是文件的合法性验证; 如果文件代码不合法, 那么浏览器解析的时候就会出现一些出错
总结: Doctype 就是通知浏览器当前的文档是属于那种类型的, 包含哪些 DTD.
- <!--HTML5 的写法 -->
- <DOCTYPE HTML>
- <!-- HTML 4.01 Strict
- 1. 这个 DTD 包含所有的 HTML 元素和属性
- 2. 但是不包含展示性的和弃用的元素(比如 font)
- -->
- <DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
- <!-- HTML 4.0.1 Transitional
- 1. 这个 DTD 包含所有的 HTML 元素和属性
- 2. 也包含展示性的和弃用性的元素(比如 font)
- -->
- <DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
- [!NOTE]
在 W3C 标准出来之前, 不同的浏览器对页面渲染有不同的标准, 产生了一定的差异. 这种渲染方式叫做混杂模式. 在 W3C 标准出来之后, 浏览器对页面的渲染有了统一的标准, 这种渲染方式叫做标准模式.<!DOCTYPE > 不存在或者形式不正确会导致 HTML 或 XHTML 文档以混杂模式呈现, 就是把如何渲染 HTML 页面的权利交给了浏览器, 有多少种浏览器就有多少种展示方式. 因此要提高浏览器兼容性就必须重视<!DOCTYPE>
10.2 严格模式和混杂模式
[!NOTE]
严格模式和混杂模式都是浏览器的呈现模式, 浏览器究竟使用混杂模式还是严格模式呈现页面与网页中的 DTD(文件类型定义)有关, DTD 里面包含了文档的规则. 比如: loose.dtd
严格模式: 又称标准模式, 是指浏览器按照 W3C 标准来解析代码, 呈现页面
混杂模式: 又称为怪异模式或者兼容模式, 是指浏览器按照自己的方式来解析代码, 使用一种比较宽松的向后兼容的方式来显示页面.
10.3 浏览器的渲染过程?
10.3.1 开始进行 DOM 解析, 渲染 DOM Tree
10.3.2 开始进行 CSS 解析, 渲染 CSSOM Tree
10.3.3 DOM 树和 CSS 树的结合, 最后会转换为 Render Tree
10.3.4 Layout 的过程, 计算每一个 DOM 元素的位置, 宽度, 高度等信息, 最终渲染并显示页面到浏览器
10.4 何时会触发 Reflow?
[!NOTE]
定义: DOM 结构中每个元素都有自己的盒子模型, 这些都是需要根据各种样式来计算并根据计算结果将元素放在它该出现的位置, 这个过程就是 reflow;
当你增加, 删除, 修改 DOM 节点的时候, 会导致 Reflow 或 Repaint
当你移动 DOM 的位置, 或者设置动画的时候
当你修改 CSS 样式的时候
当你 Resize 窗口的时候(移动端没有这个问题, 与浏览器有关), 或者在滚动窗口的时候
当你修改网页的默认的字体的时候
10.5 何时回触发 Repaint?
[!NOTE]
定义: 当各种盒子的位置, 大小以及其他属性, 例如颜色, 字体大小都确定下来以后, 浏览器于是便按照元素各自的特性绘制了一遍, 于是页面的内容出现了, 这个过程就是 repaint
DOM 改动
CSS 改动
10.6 如何最大程度上的减少浏览器的重绘 Repaint 过程 (频率) 呢?
10.6.1 避免在 document 上直接进行频繁的 DOM 操作, 如果确实需要可以采用 off-document 的方式进行
先将元素从 document 中删除, 完成修改之后然后再把元素放回原来的位置
将元素的 display 设置为 none, 然后完成修改之后再把元素的 display 属性修改为原来的值
如果需要创建多个 DOM 节点, 可以使用 DocumentFragment 创建完毕之后一次性地加入 document 中去
- var frag = document.createDocumentFragment();
- frag.appendChild(dom); /* 每次创建的节点先放入 DocumentFragment 中 */
10.6.2 集中修改样式
尽可能少的修改元素 style 上的属性
尽量通过修改 className 来修改样式(一次性修改)
通过 cssText 属性来设置样式值
document.getElementById("d1").style.cssText = "color:red; font-size:13px;";
10.6.3 缓存 Layout 的属性值
[!NOTE]
对于 Layout 属性中非引用类型的值(数字型), 如果需要多次访问则可以在一次访问时先存储到局部变量中, 之后都使用局部变量, 这样可以避免每次读取属性时造成浏览器的渲染.
- var width = el.offsetWidth;
- var scrollLeft = el.scrollLeft;
10.6.4 设置元素的 position 为 absolute 或 fixed
[!NOTE]
在元素的 position 为 static 和 relative 时, 元素处于 DOM 树结构当中, 当对元素的某个操作需要重新渲染时, 浏览器会渲染整个页面. 将元素的 position 设置为 absolute 和 fixed 可以使元素从 DOM 树结构中脱离出来独立的存在, 而浏览器在需要渲染时只需要渲染该元素以及位于该元素下方的元素, 从而在某种程度上缩短浏览器渲染时间.
11. 布局 Layout?
Layout 属性包括:
offsetLeft,offsetTop,offsetHeight,offsetWidth: 相对于父对象的边距信息, 且返回值为数字; left 获取或设置相对于具有定位属性 (position 定义为 relative) 的父对象的边距信息, 返回值为字符串 10px
scrollTop/Left/Width/Height: 滚动条在各个方向上拉动的距离, 返回值为数字
clientTop/Left/Width/Height: 浏览器的可视区域的大小
getComputedStyle(),currentStyle(in IE): 浏览器渲染 DOM 元素之后的宽度和高度等样式信息
12. JS 运行机制
12.1 如何理解 JS 的单线程?
看代码, 写结果?
- // 同步任务
- console.log(1);
- // 异步任务要挂起
- setTimeout(function(){
- console.log(2)
- }, 0);
- console.log(3)
- // out : 1 3 2
- console.log('A');
- setTimeout(function(){
- console.log('B')
- }, 0);
- while (true) {
- }
- // out : A
12.2 什么是任务队列?
- for (var i = 0; i <4; i++) {
- // setTimeout , setInterval 只有在时间到了的时候, 才会把这个事件放在异步队列中去
- setTimeout(function(){
- console.log(i);
- }, 1000);
- }
- // out : 4 4 4 4
12.3 什么是 Event Loop?
[!NOTE]
JS 是单线程的, 浏览器引擎会先来执行同步任务, 遇到异步任务之后, 会把当前的这个异步任务放在 time 模块中, 等到主线程中的所有的同步任务全部执行完毕之后; 然后当前的这个异步任务只有时间到了之后, 才会把这个任务 (回调函数) 放在一个异步队列中; 当当前的任务栈中的任务全部执行完毕了之后, 会先去执行微任务队列中的任务 (Promise), 然后等到微任务队列中的所有任务全部执行完毕之后, 再去执行 process.nextTick() 这个函数, 等到这个函数执行完毕之后, 本次的事件轮训结束;
开启新的执行栈, 从宏任务队列中依次取出异步任务, 开始执行; 每个宏任务执行都会重新开启一个新的任务执行栈
12.3.1 3 个关键点
执行栈执行的是同步任务;
什么时候去异步队列中取这个任务;
什么时候向这个任务队列中放入新的异步任务
12.3.2 异步任务的分类
setTimeout, setInterval;
DOM 事件(点击按钮的时候也会先去执行同步任务);
Promise
13. 知识点总结
理解 JS 的单线程的概念
理解任务队列
理解 Event Loop
理解哪些语句会翻入到异步任务队列
理解与放入到异步任务队列的时机
13.1 页面性能
13.1.1 提升页面性能的方法有哪些?
资源压缩合并, 减少 HTTP 请求;
非核心代码的异步加载 ---> 异步加载的方式有哪些? ---> 异步加载的区别?
利用浏览器的缓存 ---> 缓存的分类 ---> 缓存的原理
使用 CDN 加速
预解析 DNS:DNS Prefetch 是一种 DNS 预解析技术, 当你浏览网页时, 浏览器会在加载网页时对网页中的域名进行解析缓存, 这样在你单击当前网页中的连接时就无需进行 DNS 的解析, 减少用户等待时间, 提高用户体验.(提前解析域名, 而不是点击链接的时候才去进行 DNS 域名解析, 可以节省 DNS 解析需要耗费的 20-120 毫秒时间)
- <!-- https 协议的网站, 默认是关闭了 DNS 的预解析的, 可以使用下面的语句开启 -->
- <meta http-equiv="x-dns-prefetch-control" content="on">
- <!-- 开始配置需要进行 DNS 预解析的域名 -->
- <link rel="dns-prefetch" href="//www.zhix.net"> <!-- 支持 http 和 HTTPS-->
- <link rel="dns-prefetch" href="http://bdimg.share.baidu.com" /> <!-- 支持 http 的协议 -->
- <link rel="dns-prefetch" href="http://nsclick.baidu.com" />
- <link rel="dns-prefetch" href="http://hm.baidu.com" />
- <link rel="dns-prefetch" href="http://eiv.baidu.com" />
14. 异步加载的方式
14.1 动态脚本的加载
- var script = document.createElement('script');
- document.getElementsByTagName('head')[0].appendChild(script);
- // 没有 defer 或 async, 浏览器会立即加载并执行指定的脚本,"立即" 指的是在渲染该 script 标签之下的文档元素之前, 也就是说不等待后续载入的文档元素, 读到就加载并执行.
- <script src="script.js"></script>
- 14.2 defer
- <!-- 有 defer, 加载后续文档元素的过程将和 script.js 的加载并行进行(异步), 但是 script.js 的执行要在所有元素解析完成之后, DOMContentLoaded 事件触发之前完成. -->
- <script defer src="myscript.js"></script>
- 14.3 async
- <!-- 有 async, 加载和渲染后续文档元素的过程将和 script.js 的加载与执行并行进行(异步). -->
- <script async src="script.js"></script>
14.4 异步加载的区别?
[!NOTE]
defer 是在 HTML 解析完成之后 (DOMContentLoaded 事件执行之后) 才会执行, 如果是多个, 会按照加载的顺序依次执行(按照顺序执行)
async 是在加载完之后立即执行, 如果是多个, 执行顺序和加载顺序无关(与顺序无关)
15. 说一下浏览器的缓存机制吧?
15.1 缓存的分类
[!NOTE]
缓存目的就是为了提升页面的性能
15.1.1 强缓存
直接从本地读取, 不发送请求
- Response Headers
- cache-control: max-age=315360000(相对时间, 优先级比 expires 高)
- expires: Sat, 10 Mar 2029 04:01:39 GMT(绝对时间)
15.1.2 协商缓存
问一下服务器, 这个文件有没有过期, 然后再使用这个文件
- Response Headers
- last-modified: Tue, 12 Mar 2019 06:22:34 GMT(绝对时间)
- etag: "52-583dfb6f4de80"
向服务器请求资源的时候, 带上 if-Modified-Since 或者 if-None-Match 这个请求头, 去询问服务器:
- Request Headers
- if-Modified-Since: Tue, 12 Mar 2019 06:22:34 GMT
- if-None-Match: "52-583dfb6f4de80"
16. 错误监控 / 如何保证前端产品的上线质量?
16.1 前端错误的分类?
即时运行错误: 代码错误
资源加载错误: 图片 / CSS/JS 文件加载失败
16.2 错误的捕获方式?
16.2.1 即时运行错误的捕获方式
- // 方法一: 使用 try catch 捕获
- try {
- // ...
- } catch (e) {
- // error
- } finally {
- // handle error
- }
- // 方法二: 使用 Windows.onerror 捕获错误
- // 无法捕获到资源加载错误
- Windows.onerror = function(msg, url, line, col, error){
- // ...
- }
- Windows.addEventListener('error', function(msg, url, line, col, error){
- // ...
- })
16.2.2 资源加载错误(不会向上冒泡)
- // 方法一: 直接在 script, img 这些 DOM 标签上面直接加上 onerror 事件
- Object.onerror = function(e){
- // ...
- }
- // 方法二: Windows.performace.getEntries(间接获取资源加载错误的数量)
- var loadedResources = Windows.performance.getEntries(); // 1. 获取浏览器中已经加载的所有资源(包括各个阶段的详细加载时间)
- var loaderImgs = loadedResources.filter(item => {
- return /\.jpg|PNG|gif|svg/.test(item.name)
- });
- var imgs = document.getElementsByTagName('img'); // 2. 获取页面中所有的 img 集合
- var len = imgs.length - loaderImgs.length; // 3. 加载失败的图片数量
- console.log('图片加载失败数量:', len, '条');
- // 方法三: 使用事件捕获的方式来实现 Error 事件捕获
- // 使用事件捕获的方式来实现资源加载错误的事件的捕获: Windows ---> document --> HTML ---> body ---> div ---...
- Windows.addEventListener('error', function (msg) {
- console.log(msg);
- }, true);
16.2.3 补充的方法
- // 使用事件捕获的方式来实现
- Windows.addEventListener('error', function (msg) {
- console.log('资源加载异常成功捕获:', msg);
- }, true);
- // 使用事件冒泡的方式是只能捕获到运行的时候的一些异常
- Windows.addEventListener('error', function (e) {
- console.log('运行异常成功捕获 1:', e.message, e.filename, e.lineno, e.colno, e.error);
- }, false);
- // 这种方式是可以按照参数的方式来接受相关的参数信息
- Windows.onerror = function (msg, url, line, col, error) {
- console.log('运行异常成功捕获 2:', msg, url, line, col, error);
- }
16.2.4 问题的延伸: 跨域的 JS 运行错误可以捕获吗, 错误提示是什么? 应该怎么处理呢?
16.2.4.1 错误信息
- errorinfo :
- Script0 error
- 0 row
- 0 col
16.2.4.2 处理方法
第一步: 在 script 标签上增加 crossorigin 属性
- <!-- script 表情添加 crossorigin 属性 -->
- <!-- 除了 script, 所有能引入跨域资源的标签包括 link 和 img 之类, 都有一样的属性 -->
- <script crossorigin src="http://www.lmj.com/demo/crossoriginAttribute/error.js"></script>
第二步: 设置 JS 资源响应头'Access-Control-Allow-Origin: *', 服务器端需要开启
- // 服务器可以直接设置一个响应头信息
- res.setResponseHeader('Access-Control-Allow-Origin', 'www.lmj.com');
16.3 上报错误的基本原理?
采用 Ajax 通信的方式来上报
利用 Image 对象进行上报(cnzz)[重点理解掌握]
- // 下面的两种方式都是可以实现错误信息的上报功能的
- (new Image).src = 'http://www.baidu.com?name=zhangsna&age=18&sex=male'
- (new Image()).src = 'https://www.baidu.com?name=zhangsan'
17. 如何使用 JS 获取客户端的硬件信息呢?
- // IE 浏览器提供的获取电脑硬件的 API
- var locator = new ActiveXObject ("WbemScripting.SWbemLocator");
- var service = locator.ConnectServer(".");
- var properties = service.ExecQuery("SELECT * FROM Win32_Processor");
18. 使用 Windows.performace 来实现用户体验的数据记录呢?
[!NOTE]
可以参考性能优化章节 - performance 性能监控一文内容.
三四面(业务项目面)
[!NOTE]
知识面要广
理解要深刻
内心要诚实: 没了解过, 问面试官有哪些资料可以学习
态度要谦虚
回答要灵活: 把握一个度, 不要和面试官争执对错
要学会赞美: 被问住了可以回答, 适当赞美(没面试官理解的那么深, 虚心请教)
19. 介绍一下你做过的项目?
19.1 项目介绍模板(业务能力体现)
我做过什么业务?
负责的业务有什么业绩?
使用了什么技术方案?
突破了什么技术难点?
遇到了什么问题?
最大的收获是什么?
19.2 团队协作能力
19.3 事务推动能力
19.4 带人能力
终面(HR 面)
20. 技术终面或 HR 面试要点
[!NOTE]
主要考察点: 乐观积极, 主动沟通, 逻辑顺畅, 上进有责任心, 有主张, 做事果断, 职业竞争力, 职业规划
20.1 职业竞争力
业务能力: 可以做到行业第一
思考能力: 对同一件事可以从不同角度去思考, 找到最优解
学习能力: 不断学习新的业务, 沉淀, 总结
无上限的付出: 对于无法解决的问题可以熬夜, 加班
20.2 职业规划
目标是什么: 在业务上成为专家, 在技术上成为行业大牛
近阶段的目标: 不断的学习积累各方面地经验, 以学习为主
长期目标: 做几件有价值的事情, 如开源作品, 技术框架等
方式方法: 先完成业务上的主要问题, 做到极致, 然后逐步向目标靠拢
来源: https://www.cnblogs.com/fecommunity/p/11908984.html