前言
主要记录下面试遇到的题目,方便有空复习下。久不用就会忘,面试又要考../(ㄒ o ㄒ)/~~
HTML
浏览器的渲染过程
浏览器渲染的过程主要包括以下五步:
- 浏览器将获取的 HTML 文档解析成 DOM 树。
- 处理 CSS 标记,构成层叠样式表模型 CSSOM(CSS Object Model)。
- 将 DOM 和 CSSOM 合并为渲染树(rendering tree),代表一系列将被渲染的对象。
- 渲染树的每个元素包含的内容都是计算过的,它被称之为布局 layout。浏览器使用一种流式处理的方法,只需要一次绘制操作就可以布局所有的元素。
- 将渲染树的各个节点绘制到屏幕上,这一步被称为绘制 painting。
需要注意的是,以上五个步骤并不一定一次性顺序完成,比如 DOM 或 CSSOM 被修改时,亦或是哪个过程会重复执行,这样才能计算出哪些像素需要在屏幕上进行重新渲染。而在实际情况中,JavaScript 和 CSS 的某些操作往往会多次修改 DOM 或者 CSSOM
*扩展阅读/答案摘抄于《浏览器渲染原理与过程》
CSS
css 选择器主要分为五大类
- ID 选择器(#id)
- 类选择器(.class)
- 属性选择器([attr])
- 元素选择器(p)
- 伪类选择器(:hover)
- 派生选择器
- 后代选择器(body li)
- 子元素选择器(h1 > h2)
- 相邻兄弟选择器(h1 + h2)
- 后续兄弟选择器(h1 ~ h2)
- 通配选择器(*)
优先级
选择器的优先级由四个部分相加,可以认为是个十百千的四位数
- 千位(行内样式 style)
- 百位(ID 选择器)
- 十位(类选择器,属性选择器,伪类选择器)
- 个位(元素、伪元素)
计算结果越大优先级越高,在进行计算时不允许进位,例如:20 个类选择器只是 20 个十位,不能视为两个百位。
继承
子元素继承父元素
css 中 link 和@import 的区别
- 从属关系区别。
@import
是css
提供的语法规则,只有导入样式的作用;link
是HTMl
提供的标签,不仅可以加载css
文件,还可以定义RSS
,rel
等连接属性。例如常见的设置网站icon
图标。link 的官方解释的是:引入外部文档,引入什么文档由rel
属性说明。 - 加载顺序区别。
link
标签引入的 css 被同时加载;@import
引入的 css 将在页面加载完毕后被加载。 - 兼容性区别。
@import
是 CSS2.1 才有的语法,所以只可在 IE5+才能识别;link
作为 HTML 元素,不存在兼容问题 - DOM 可操作性区别。可通过 js 操作 DOM 来插入 link 标签,改变样式;而
@import
无法这样动态去插入样式
- 从属关系区别。
Javascript
302: 重定向,当响应码为 302 时,表示服务器要求浏览器重新再发一个请求,服务器会发送一个响应头 Location,它指定了新请求的 URL 地址
304: 是缓存机制中,服务器判断出内容没变化,未修改,继续试用本地缓存时的一个状态码
*扩展阅读《HTTP 状态码详解》
考作用域和变量提升
var a = 1 function fn() { alert(a) var a = 2 } fn() alert(a)
var a = 1 function fn(a) { alert(a) var a = 2 } fn() alert(a)
ES6 常用的心特性
- 不一样的变量声明:const 和 let
- 模板字符串
- 箭头函数
- 函数的参数默认值
- Spread / Rest 操作符
- 对象和数组解构
- for…of 和 for…in
- 数组 find 和 findInex
- ES6 中的类
依赖注入的理解
简单来说是解耦,详细看这篇通俗易懂的文章
https://zhuanlan.zhihu.com/p/33492169es6 class 类 与普通构造函数的区别
- 类的内部所有所有定义的方法都是不可枚举的,而在 es5 中的 prototype 的党发是可以枚举的
(Object.keys(Class.prototype) === [])
- 类的构造函数不使用
new
实例是没法调用的,会报错;而 es5 中的构造函数可以直接调用,也可以new
,因为本来就只是一个方法的形式 - Class 不存在变量提升(hoist),es5 存在。(因为 Class 类的继承要保证子类的声明定义必须在父类之后,所以在类声明前使用,不会把类的声明提升到顶部,而会报错)
- es5 的继承,实质是先创建子类的示例对象
this
,然后再将父类的方法添加到this
上面(Parent.apply(this)
);而 Class 类的继承机制完全不同,实质是先创造父类的实例对象this
,所以必须先调用super()
方法,然后子类再之类自己的构造函数修改this
*_4 的解释_:
// es5 function Animal (name) { this.name = name } function Cat (name) { Animal.apply(this) say() { return this.name } }
- 类的内部所有所有定义的方法都是不可枚举的,而在 es5 中的 prototype 的党发是可以枚举的
// es6
Class Animal {
constructor (name) {
this.name = name
}
}
Class Cat extends Animal {
constructor (name) {
super(name)
}
say () {
return this.name
}
}
\*_摘抄自《[es6 class 类 与普通构造函数的区别](https://blog.csdn.net/glorydx/article/details/103251475)》_
- ## instanceof 和 typeof 的区别
先说说官方理解
typeof 操作符返回一个字符串,表示未经计算的操作数的类型。
instanceof 运算符用于检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上。
1. 首先可以看出判断的原理不一样。typeof 的原理是根据数据的二进制存储前三位判断的;而 instanceof 是根据原型对象去判断的,
2. typeof 判断原理导致它的结果是不够精准的,对象、数组、null 类型判断都会返回`object`,其他类型判断精准;instanceof 的原理导致只能判断一个实例的对象(2 instanceiof Number === false; new Nember(2) instanceof Number === true;因为数字 2 是没有原型连的,对象 new Number(2)才有),但可以使用 instanceof 判断是否数组,是精准的,同样 instanceif 也不能精准判断 null 类型,因为 null 并不是对象。
扩展阅读:其他判断类型的方法
1. `constructor`
```javascript
(2).constructor === Number
(true).constructor === Boolean
('str').constructor === String
([]).constructor === Array
(functiong () {}).constructor === Function
({}).constructor === Object
// (null).constructor === Object //TypeError: Cannot read property 'constructor' of null
// (undefined).constructor === Object // TypeError: Cannot read property 'constructor' of undefined
可以看出就算是constructor
也是不能判断null
和undefined
类型的。
constructor
和instaceof
都有个缺点,更改了对象的原型后,就不可靠了
function Fn() {}
Fn.prototype = new Array()
var f = new Fn()
f.constructor === Fn // false
f.constructor === Array //true
f instanceof Function // false
f instanceof Array // true
Object.prototype.toString.call()
Object.prototype.toString.call()
是唯一个能精准判断所有类型的方法const a = Object.prototype.toString a.call(2) // [object Number] a.call(true) // [object Bollean] a.call('str') // [object String] a.call([]) // [object Array] a.call(function () {}) // [object Function] a.call({}) // [object Object] a.call(underfined) // [object Undefined] a.call(null) // [object Null] a.call(new Date()) // [object Date] a.call(Math) // [object Math]
*参考资料《JS 中数据类型的判断( typeof,instanceof,constructor,Object.prototype.toString.call() )》
斐波那契数列的迭代算法和递归算法
斐波那契数列: 0、1、1、2、3、5、8、13、21、34、……
迭代算法
function fibonacci(number) {
// number 数组下标
const fibonacciArry = []
for (let i = 0; i <= number; i++) {
if (i === 0) fibonacciArry.push(0)
else if (i === 1) fibonacciArry.push(1)
else {
fibonacciArry.push(fibonacciArry[i - 1] + fibonacciArry[i - 2])
}
}
return fibonacciArry
}
迭代算法
function fibonacciValue(number) {
// number 数组下标
if (number <= 0) return 0
else if (number === 1) return 1
else {
return fibonacciValue(number - 2) + fibonacciValue(number - 1)
}
}