前端面试笔记整理

111 阅读9分钟

前段面试笔记

HTML面试题篇

如何理解HTML语义化标签?

  • 是什么:语义化标签是一种写HTML标签的方法论/方式
  • 怎么做:实现方法是遇到标题就用h1到h6,遇到段落用p,遇到文章用article,主要内容用main,边栏用aside,导航用nav
  • 解决了什么问题:明确了HTML的书写规范
  • 优点是:1、适合搜索引擎搜索,2、适合人类阅读,利于团队维护

总结:是什么、怎么做、解决了什么问题,优点是、缺点是、怎么解决缺点。

HTML新增了那些标签?

  • 文章相关:header(标题)、main(主要的)、footer(页脚)、nav、section(部分)、article(文章)、figure(图形)、mark(标记)
  • 媒体相关:video(视频)、audio(音频)、svg、cannas
  • 表单相关:type=email type=tel

总结:MDN把所有标签都列在这里

Canvas和svg的区别是什么?

答题思路为:先说一,在说二,在说相同点,最后说不同点

  • Canvas主要是用笔刷绘制2D图形的
  • SVG主要使用标签来绘制不规则的矢量图
  • 相同点:都是主要用来画2D图形的
  • 不同点:Canvas画的是位图,SVG画的是矢量图
  • 不同点:SVG节点过多是渲染慢,Canvas性能更好一点,但是写起来更复杂。
  • 不同点:SVG支持分层和事件,Canvas不支持,但是可以用库实现

总结:位图、矢量图、渲染性能、石峰支持分层和事件

Css面试题篇

BFC 是什么?

  • 是什么:BFCs是块级格式化上下文
  • 怎么做:背通BFC触发条件,MDN的BFC触发条件文章,记录几个触发条件
    • 浮动元素(元素的float不是none)
    • 绝对定位元素(元素的position为absolute或fixed)
    • 行内块inline block元素
    • overflow值不为visible的块元素
    • 弹性元素(display为flex或inline-flex元素的直接子元素)
解决了什么问题?
  • 清除浮动
  • 防止margin合并
  • 某些古老的布局方式会用到(已过时)
优点:无
缺点:有副作用

怎样解决缺点:使用最新的 disp.ay:flow-root来触发BFC就没有副作用

如何实现垂直居中?

如果 .parent 的 height 不写,你只需要 padding: 10px 0; 就能将 .child 垂直居中;

如果 .parent 的 height 写死了,就很难把 .child 居中,以下是垂直居中的方法。

忠告:能不写 height 就千万别写 height。

七种方式实现垂直居中

得分点:flex 方案、grid 方案、transform 方案……

CSS选择器优先级如何确定?

比较详细的博客文章

简单的总结记住三句话

  1. 选择器越具体,其优先级越高
  2. 相同优先级,出现在后面的,覆盖前面的
  3. 属性后面加 !important 的优先级最高,但是要少用

如何清除浮动?

方法一,给父元素加上 .clearfix

.clearfix:after{
    content: '';
    display: block; /*或者 table*/
    clear: both;
}

方法二,给父元素加上 overflow:hidden。

两种盒模型(box-sizing)的区别?

第一种盒模型是 content-box,即 width 指定的是 content 区域宽度,而不是实际宽度,公式为

实际宽度 = width + padding + border

第二种盒模型是 border-box,即 width 指定的是左右边框外侧的距离,公式为

实际宽度 = width

相同点是都是用来指定宽度的,不同点是 border-box 更好用。

JS面试题篇

JS 的数据类型有哪些?

字符串、数字、布尔、undefined、null、大整数、符号、对象

string、number、boolean、undefined、null、bigint、symbol、object

提了就零分的答案有:数组、函数、日期。这些是类 class,不是类型 type

原型链是什么?

举例说明

假设我们有一个普通对象 x={} ,这个 x 会有一个隐藏属性,叫做 ????? ,这 个属性会指向 Object.prototype ,即

x.__?????__ === Object.prototype // 原型

此时,我们说 x 的原型 是 Object.prototype,或者说 Object.prototype 是 x 的原 型。 而这个 ????? 属性的唯一作用就是用来指向 x 的原型的。 如果没有 ????? 属性,x 就不知道自己的原型是谁了。

为什么我用问号来表示?因为这样你不容易晕。

接下来我来说说原型链,我还是举例说明吧。

假设我们有一个数组对象 a=[] ,这个 a 也会有一个隐藏属性,叫做 ????? , 这个属性会指向 Array.prototype ,即

a.__?????__ === Array.prototype

此时,我们说 a 的原型是 Array.prototype ,跟上面的 x 一样。但又有一点不一样, 那就是 Array.prototype 也有一个隐藏属性 ????? ,指向 Object.prototype , 即

// 用 x 表示 Array.prototype
x.__?????__ === Object.prototype

这样一来,a 就有两层原型:

  1. a 的原型是 Array.prototype
  2. a 的原型的原型是 Object.prototype

于是就通过隐藏属性 ????? 形成了一个链条:

a ===> Array.prototype ===> Object.prototype

这就是原型链.

怎么做

看起来只要改写 x 的隐藏属性 ????? 就可以改变 x 的原型(链)

x.__?????__ = 原型

但是这不是标准推荐的写法,为了设置 x.?????_ ,推荐的写法是

const x = Object.create(原型)
// 或
const x = new 构造函数() // 会导致 x.__?????__ === 构造函数.prototype

解决了什么问题:

在没有 Class 的情况下实现「继承」。以 a ===> Array.prototype ===> Object.prototype 为例,我们说:

  1. a 是 Array 的实例,a 拥有 Array.prototype 里的属性
  2. Array 继承了 Object(注意专业术语的使用)
  3. a 是 Object 的间接实例,a 拥有 Object.prototype 里的属性 这样一来,a 就既拥有 Array.prototype 里的属性,又拥有 Object.prototype 里的属性。

优点:简单、优雅。

缺点:跟 class 相比,不支持私有属性。

怎么解决缺点:使用 class 呗。但 class 是 ES6 引入的,不被旧 IE 浏览器支持。建议熟读这篇文章

这段代码中的 this 是多少?

把判断依据背下来才能全对

var length = 4;
function callback() {
console.log(this.length); // => 打印出什么?
}
const obj = {
length: 5,
method(callback) {
callback();
}
};
obj.method(callback, 1, 2);

建议熟读这篇文章

JS 的 new 做了什么?

  1. 创建临时对象/新对象
  2. 绑定原型
  3. 指定 this = 临时对象
  4. 执行构造函数
  5. 返回临时对象

建议熟读这篇文章

JS 的立即执行函数是什么?

是什么*:声明一个匿名函数,然后立即执行它。这种做法就是立即执行函数。 怎么做:

(function(){alert('我是匿名函数')} ()) // 用括号把整个表达式包起来
(function(){alert('我是匿名函数')}) () // 用括号把函数包起来
!function(){alert('我是匿名函数')}() // 求反,我们不在意值是多少,只想通过语法
+function(){alert('我是匿名函数')}()
-function(){alert('我是匿名函数')}()
~function(){alert('我是匿名函数')}()
void function(){alert('我是匿名函数')}()
new function(){alert('我是匿名函数')}()
var x = function(){return '我是匿名函数'}()

上面每一行代码都是一个立即执行函数。(举例法) 解决了什么问题:在 ES6 之前,只能通过它来「创建局部作用域」。 优点:兼容性好。

缺点:丑。为什么这么丑?看视频分析。 怎么解决缺点:使用 ES6 的 block + let 语法,即

{
    let a = '我是局部变量啦'
    console.log(a) // 能读取 a
}
console.log(a) // 找不到 a

JS 的闭包是什么?怎么用?

是什么:闭包是 JS 的一种语法特性。

闭包 = 函数 + 自由变量

对于一个函数来说,变量分为:全局变量、本地变量、自由变量 怎么做:

let count
function add (){ // 访问了外部变量的函数
count += 1
}

把上面代码放在「非全局环境」里,就是闭包。

注意,闭包不是 count,闭包也不是 add,闭包是 count + add 组成的整体。

怎么制造一个「非全局环境」呢?答案是立即执行函数:

const x = function (){
    var count
    function add (){ // 访问了外部变量的函数
    count += 1
}
}()

但是这个代码什么用也没有,所以我们需要 return add ,即:

const add2 = function (){
    var count
    return function add (){ // 访问了外部变量的函数
    count += 1
}
}()

此时 add2 其实就是 add,我们可以调用 add2

add2()
// 相当于
add()
// 相当于
count += 1

至此,我们就实现了一个完整的「闭包的应用」。

注意:闭包 ≠ 闭包的应用,但面试官问你「闭包」的时候,你一定要答「闭包 的应用」,这是规矩。

解决了什么问题:

  1. 避免污染全局环境。(因为用的是局部变量)
  2. 提供对局部变量的间接访问。(因为只能 count += 1 不能 count -= 1)
  3. 维持变量,使其不被垃圾回收。

优点:简单,好用。 缺点:闭包使用不当可能造成内存泄露。

注意,重点是「使用不当」,不是闭包。 「闭包造成内存泄露」这句话以讹传讹很多年了,曾经旧版本 IE 的 bug 导致的问 题,居然被传成这样了。

举例说明:

function test() {
var x = {name: 'x'};
var y = {name: 'y', content: "-----这里很长,有一万三千五百个字符那么长----" }
return function fn() {
return x;
};
}
const myFn = test() // myFn 就是 fn 了
const myX = myFn() // myX 就是 x 了
// 请问,y 会消失吗?

对于一个正常的浏览器来说,y 会在一段时间后自动消失(被垃圾回收器给回收 掉)。 但旧版本的 IE 并不是正常的浏览器,所以是 IE 的问题。 当然,你可以说

君子不立于危墙之下,我们应该尽量少用闭包,因为有些浏览器对闭包的支持不够好

但你不可以说「闭包造成内存泄露」。对吗?

怎么解决缺点:慎用,少用,不用。(我偏要用)

建议熟读这篇文章

JS 如何实现类?

方法一:使用原型

 function Dog(name){
this.name = name
this.legsNumber = 4
}
Dog.prototype.kind = '狗'
Dog.prototype.say = function(){
console.log(`汪汪汪~ 我是${this.name},我有${this.legsNumber}条腿。`)
}
Dog.prototype.run = function(){
console.log(`${this.legsNumber}条腿跑起来。`)
}
const d1 = new Dog('啸天') // Dog 函数就是一个类
d1.say()

请试着实现一个 Chicken 类,没 name 会 say 会 fly。 方法二:使用 class

class Dog {
kind = '狗' // 等价于在 constructor 里写 this.kind = '狗'
constructor(name) {
this.name = name
this.legsNumber = 4
// 思考:kind 放在哪,放在哪都无法实现上面的一样的效果
}
say(){
console.log(`汪汪汪~ 我是${this.name},我有${this.legsNumber}条腿。`)
}
run(){
console.log(`${this.legsNumber}条腿跑起来。`)
}
}
const d1 = new Dog('啸天')
d1.say(

请试着实现一个 Chicken 类,没 name 会 say 会 fly

JS 如何实现继承?

方法一:使用原型链

function Animal(legsNumber){
this.legsNumber = legsNumber
}
Animal.prototype.kind = '动物'
function Dog(name){
this.name = name
Animal.call(this, 4) // 关键代码1
}
Dog.prototype.__proto__ = Animal.prototype // 关键代码2,但这句代码被禁用了,怎
Dog.prototype.kind = '狗'
Dog.prototype.say = function(){
console.log(`汪汪汪~ 我是${this.name},我有${this.legsNumber}条腿。`)
}
const d1 = new Dog('啸天') // Dog 函数就是一个类
console.dir(d1)

如果面试官问被 ban 的代码如何替换,就说下面三句:

var f = function(){ }
f.prototype = Animal.prototype
Dog.prototype = new f()

方法二:使用 class

class Animal{
    constructor(legsNumber){
    this.legsNumber = legsNumber
}
run(){}
}
class Dog extends Animal{
constructor(name) {
    super(4)
    this.name = name
}
say(){
console.log(`汪汪汪~ 我是${this.name},我有${this.legsNumber}条腿。`)
}
}