前端基础
HTML 基础
DOCTYPE 的作用是什么?
html5 标准网页声明,告知浏览器的解析器用什么文档标准解析文档,不同的渲染模式会影响到 css 甚至 js 的脚本解析。必须声明在第一行。
文档解析类型:
- 标准模式:W3C 标准
- 怪异模式: 浏览器自己标准
CSS 基础
CSS 选择器的优先级是怎么样的?
内联 > id 选择器 > 类选择器 > 标签选择器, 权重从左到右依次减小。
link 和@import 区别?
- link 是 xhtml 元素,@import 是 css 提供的(需要 IE5 以上)
- 页面加载时,link 会同时被加载;@import 引用的 css 等到页面加载完再加载
- link 的样式权重高于@import
如何理解 z-index?
css 中的 z-index 属性控制重叠元素的垂直叠加顺序,默认元素的 z-index 为 0,修改 z-index 来控制元素的图层位置,而且 z-index 仅在定位元素(position 不等于 static)中生效。
如何理解层叠上下文?
是什么?
层叠上下文是 HTML 元素的三维概念,这些 HTML 元素在一条假想的相对于面向用户的 z 轴上叠放排列,HTML 元素依据其自身优先级顺序占用层叠上下文的空间。
作用是什么?
该元素的所有后代元素相对于该祖先元素都有其自己的叠放顺序。
如何产生?
触发一下条件则会产生层叠上下文:
- 根元素(HTML)
- z-index 值不为 “auto”的
- opacity 属性值小于 1 的元素(参考 the specification for opacity),
- transform 属性值不为 “none”的元素
- mix-blend-mode 属性值不为 “normal”的元素,
- filter 值不为“none”的元素,
- perspective 值不为“none”的元素,
- isolation 属性被设置为 “isolate”的元素,
- position: fixed
- 在 will-change 中指定了任意 CSS 属性,即便你没有直接指定这些属性的值
- webkit-overflow-scrolling 属性被设置 “touch”的元素
你对盒模型的理解?
是什么?
当一个文档进行布局的时候,浏览器的渲染引擎会根据标准盒模型将所有元素渲染为一个矩形盒子。CSS 决定盒子的大小、位置、颜色、背景、边框····
盒模型由 content、padding、border、margin 组成。
box-sizeing: content-box border-box
谈谈对 BFC 的理解?
是什么?
BFC 是块级格式上下文,页面中一个独立的渲染区域,让处于内部的元素与外部的元素互相隔离。
如何形成?
- 根元素
- position 不为 static
- float 不为 none
- overflow 不为 visible
- display: inline-block table-cell table-caption
作用是什么?
- 防止 margin 重叠
- 消除浮动的副作用
- 防止文字环绕
- 防止高度坍塌
伪类和伪元素的区别是什么?
是什么?
伪类(pseudo-class) 是一个以冒号(:)作为前缀,被添加到一个选择器末尾的关键字,当你希望样式在特定状态下才被呈现到指定的元素时,你可以往元素的选择器后面加上对应的伪类。
伪元素用于创建一些不在文档树中的元素,并为其添加样式。比如说,我们可以通过::before 来在一个元素前增加一些文本,并为这些文本添加样式。虽然用户可以看到这些文本,但是这些文本实际上不在文档树中。
区别
伪类是通过在元素选择器上加入伪类改变元素状态,而伪元素通过对元素的操作进行对元素的改变。
js 基础
js 的作用域链理解吗?
js 是词法作用域(静态作用域),声明的作用域在编译阶段就已经确定。
js 在执行时会创建执行上下文,执行上下文中的词法环境会包含外层词法环境的引用,通过引用可以获取外层词法环境的变量,这些引用层层串联最终指向全局环境,因此形成作用域连。s
ES6 模块与 CommonJS 模块的差异
两个重大差异:
- CommonJS 模块输出的是一个值的拷贝,ES6 模块输出的是值的引用
- CommonJS 模块是运行时加载,ES6 模块是编译时输出接口
为什么会有 BigInt 的提案?
Number.MAX_SAFE_INTEGER
,表示最大安全数字
0.1 + 0.2 为什么不等于 0.3?
JS 的 Number 类型是双精度浮点数,遵循 IEEE 754 标准。
以 0.1 转换 IEEE 754 标准为例,会有 3 个阶段:
- 0.1 转换为二进制表示
- 二进制用科学计数法表示
- 科学计数法表示的二进制转换为 IEEE 754 标准表示
问题出在第三步,以 IEEE 754 标准转换后的 0.1 换成十进制,变成 0.100000000000000005551115123126
谈谈你对原型链的理解?
先谈原型对象
绝大部分函数(少数内建函数除外)都会有一个 prototype 属性,这个属性指向函数的原型对象,当调用构造函数创建实例时,该实例的内部将包含一个内部__proto__
属性,指向构造函数的原型对象。所有被创建的实例都会共享原型对象,这些实例可以访问原型对象的属性。
原型链
原因是每个对象都有__proto__
属性,此属性指向该对象的构造函数的原型。
对象可以通过__proto__
与上游的构造函数的原型对象连接起来,而上游的原型对象也有一个__proto__
,这样形成了原型链。
谈谈你对原型链的理解?
this 的指向不是在编写时确定的,而是在执行时确定的,同时,this 的指向遵循一定的规则。
- 默认规则,指向全局对象
- 隐式调用,函数被调用的位置存在上下文对象时,指向这个上下文对象
- 显示调用(apply, call, bind),指向指定的对象
- new 调用,优先级最高,用 new 调用一个构造函数,会创建一个新对象,this 会自动绑定到这个新对象
补充
箭头函数与传统函数的差异:
- 没有
this
、super
、new.target
绑定 它们的值由外围最近一层非箭头函数决定。- 不能通过
new
调用 箭头函数没有[[Construct]]
方法,所以不能被用作构造函数- 没有原型
- 不支持
arguments
对象- 不支持重复的命名参数
async/await 是什么?
async 函数,就是 Generator 函数的语法糖,它建立在 Promise 上,并且与所有现有的 Promise 的 API 兼容。
- Async——声明一个异步函数
- 自动将常规函数转换为 Promise,返回值也是一个 Promise 对象
- 只有 asyn 函数内部的异步操作执行完,才会执行 then 方法指定的回调函数
- 异步函数内部可以使用 await
- Await——暂停异步的功能执行
- 放置在 Promise 调用之前,await 强制代码等待,直到 Promise 完成并返回结果
- 只能与 Promise 一起使用,不适用回调
- 只能在 async 函数内调用
浏览器与新技术
浏览器是如何渲染 UI 的?
- 浏览器获取 HTML 文件,然后对文件进行解析,形成 DOMTree
- 与此同时,进行 CSS 解析,形成 Style Rules
- 接着将 DOMTree 和 Style Rules 合成为 Render Tree
- 然后进入布局(layout)阶段,也就是为每个节点分配一个应出现在屏幕上的确切坐标
- 随后调用 GPU 进行绘制(Paint),遍历 Render Tree 的节点,并将元素呈现出来
DOM Tree 是如何建立的?
- 转码:浏览器将接收到的二进制数据按照指定编码格式转化为 HTML 字符串
- 生成 TOKEN:浏览器会将 HTML 字符串解析成 Tokens
- 构建 Nodes:对 Node 添加特定的属性,通过指针确定 Node 的父、子、兄弟关系和所属 treeScope
- 生成 Dom Tree: 通过 node 包含的指针确定的关系构建出 DOM Tree
前端基础笔试
javascript 笔试部分
实现防抖函数(debounce)
防抖函数原理:在事件被触发 n 秒后再执行回调,如果在这 n 秒内又被触发,则重新计时
1 | //计时器版本 |
实现节流函数(throttle)
节流函数原理:规定在一个单位时间内,只能触发一次函数。如果这个单位时间内触发多次函数,只有一次生效。
1 | //简单版本 |
实现深拷贝
一行代码的深拷贝
1 | const copyJSON = obj => JSON.parse(JSON.stringify(obj)); |
存在的问题:
- 不能拷贝正则、函数等特殊对象
- 循环引用的问题
- 会抛弃对象的 constructor,所有的构造函数会指向 Object
面试版
1 | // 对象类型判断函数 |
实现一个 Event Bus
1 | class EventEmeitter { |
实现instanceOf
1 | // 模拟 instanceof |
模拟 new
1 | function objectFactory() { |
实现一个 call
call 做了什么:
- 将函数设为对象的属性
- 执行并删除这个函数
- 指定 this 到函数并传入给定参数执行函数
- 如果不传入参数,默认指向 window
1 | Function.prototype.myCalll = function(context) { |
实现一个 bind
1 | Function.prototype.bind = function(context) { |
实现 Promise
1 | function Promise(executor) { |