blog icon indicating copy to clipboard operation
blog copied to clipboard

前端工程师面试题合集

Open kaindy7633 opened this issue 3 years ago • 0 comments

Table of Contents generated with DocToc

  • 前端工程师面试题合集
    • HTML
      • 如何理解HTML语义化
      • 块状元素 & 内联元素
    • CSS
      • 什么是盒模型,请根据盒模型计算下面 div1offsetWidth
      • 下面代码中 AAA 元素与 BBB 元素之间的距离是多少?
      • margin 属性设置负值会有什么影响?
      • BFC的理解和应用
      • float布局
      • 手写 clearfix
      • 使用 flex 画三点骰子
      • relative 和 absolute 定位
      • 居中对齐的实现方式
      • line-height 继承的问题
      • rem是什么? 如何利用它来做响应式
    • JavaScript
      • 值类型和引用类型
      • typeof 能判断哪些类型
      • 类型转换
      • 何时使用 ===, 何时使用 ==
      • 值类型和引用类型的区别
      • 手写深拷贝

前端工程师面试题合集

HTML

如何理解HTML语义化

  • 让人更容易读懂(增加代码可读性)

  • 让搜索引擎更容易读懂(SEO)

块状元素 & 内联元素

  • 块状元素:display: block 或者 display: table,有 divh1h2tableulolp 等, 它们都会在浏览器中独占一行

  • 内敛元素: display: inline 或者 display: inline-block,有 spanimginputbutton等,它们不会独占一行,根据其宽度依次排列,直到换行

CSS

什么是盒模型,请根据盒模型计算下面 div1offsetWidth

<!-- 如下代码,请问 div1 的 offsetWidth 是多大? -->
<style>
  #div1 {
    width: 100px;
    padding: 10px;
    border: 1px solid #ccc;
    margin: 10px;
  }
</style>

<div id="div1"></div>

CSS 盒子模型(Box Model) 所有 HTML 元素可以看作盒子,在 CSS 中,"box model"这一术语是用来设计和布局时使用。 CSS 盒模型本质上是一个盒子,封装周围的 HTML 元素,它包括:边距,边框,填充,和实际内容。

offsetWidth = (内容宽度 + 内边距 + 边框), 无外边距,因此答案是 122px

如果为此元素增加 box-sizing 属性,并设置其值为: border-box,则其宽度为 100px

#div1 {
    width: 100px;
    padding: 10px;
    border: 1px solid #ccc;
    margin: 10px;
    box-sizing: boder-box;
  }

下面代码中 AAA 元素与 BBB 元素之间的距离是多少?

<!-- 如下代码,AAA 和 BBB 之间的距离是多少 -->
<style>
  p {
    font-size: 16px;
    line-height: 1;
    margin-top: 10px;
    margin-bottom: 15px;
  }
</style>

<p>AAA</p>
<p></p>
<p></p>
<p></p>
<p>BBB</p>
  • 相邻元素的 margin-topmargin-bottom 会发生重叠

  • 空白内容的 <p></p> 也会发生重叠

所以答案是 15px

margin 属性设置负值会有什么影响?

  • margin-topmargin-left 负值,元素向上、向左移动

  • margin-right 负值,右侧元素左移,自身不受影响

  • margin-bottom 负值,下方元素上移,自身不受影响

BFC的理解和应用

BFC 全称为 Block Format Context ,块级格式化上下文,它是一块独立渲染的区域,内部元素的渲染不会影响边界以外的元素

形成 BFC 的常见条件如下:

  • float 不是 none

  • positionabsolutefixed

  • overflow 不是 visible

  • displayflexinline-block

BFC 常见的用于清除浮动,下面是一个例子

<style>
  .container {
    background-color: #f1f1f1;
  }
  .left {
    float: left;
  }
</style>

<div clas="container">
  <img src="http://img.xxx.com/logo.png" class="left" />
  <p>这里是一段文字...</p>
</div>

上面代码展示的效果是图片脱离的文档流,p 标签占满一行,很难看,这时我们只需要设置 BFC,这里我们增加一个 css 属性 overflow, 并在容器中增加即可解决

<style>
  .container {
    background-color: #f1f1f1;
  }
  .left {
    float: left;
  }
  .bfc {
    overflow: hidden;  /* 启用 BFC */
  }
</style>

<div clas="container bfc">
  <img src="http://img.xxx.com/logo.png" class="left" />
  <p class="bfc">这里是一段文字...</p>
</div>

float布局

圣杯布局和双飞翼布局的目的:

  • 三栏布局,中间一栏最先加载和渲染(内容最重要)

  • 两侧内容固定,中间内容随着宽度自适应

  • 一般用于PC网页

圣杯布局和双飞翼布局的技术总结:

  • 使用 float 布局

  • 两侧使用 margin 负值,以便和中间内容横向重叠

  • 防止中间内容被两侧覆盖,一个用 padding ,一个用 margin

圣杯布局演示代码如下:

<style>
  body {
    min-width: 550px;
  }
  #header {
    text-align: center;
    background-color: #f1f1f1;
  }
  #center {
    background-color: #ccc;
    width: 100%;
  }
  #left {
    position: relative;  /* 浮动基于自身 */
    background-color: yellow;
    width: 200px;
    margin-left: -100%;  /* 使用负值设定左边区域距离边界100% */
    right: 200px;
  }
  #right {
    background-color: red;
    width: 150px;
    margin-right: -150px; /* 使用负值 */
  }
  #footer {
    text-align: center;
    background-color: #f1f1f1;
    clear: both;  /* 清除浮动 */
  }
  #container {
    /* 设定中间内容区域距离左右的padding */
    padding-left: 200px;
    padding-right: 150px;
  }
  #container .column {
    float: left;  /* 所有结构元素浮动 */
  }
</style>

<body>
  <div id="header">this is header</div>
  <div id="container">
    <div id="center" class="column">this is center</div>
    <div id="left" class="column">this is left</div>
    <div id="right" class="column">this is right</div>
  </div>
  <div id="footer">this is footer</div>
</body>

双飞翼布局代码如下:

<style type="text/css">
    body {
        min-width: 550px;
    }
    .col {
        float: left;
    }

    #main {
        width: 100%;
        height: 200px;
        background-color: #ccc;
    }
    #main-wrap {
        margin: 0 190px 0 190px;
    }

    #left {
        width: 190px;
        height: 200px;
        background-color: #0000FF;
        margin-left: -100%;
    }
    #right {
        width: 190px;
        height: 200px;
        background-color: #FF0000;
        margin-left: -190px;
    }
</style>

<body>
    <div id="main" class="col">
        <div id="main-wrap">
            this is main
        </div>
    </div>
    <div id="left" class="col">
        this is left
    </div>
    <div id="right" class="col">
        this is right
    </div>
</body>

手写 clearfix

/* 手写 clearfix */
.clearfix:after {
    content: '';
    display: table;
    clear: both;
}

使用 flex 画三点骰子

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>flex 画骰子</title>
    <style type="text/css">
        .box {
            width: 200px;
            height: 200px;
            border: 2px solid #ccc;
            border-radius: 10px;
            padding: 20px;

            display: flex; /* 设置为flex */
            justify-content: space-between; /* 两端对齐 */
        }
        .item {
            display: block;
            width: 40px;
            height: 40px;
            border-radius: 50%;
            background-color: #666;
        }
        .item:nth-child(2) {
            align-self: center; /* 中间的点上下左右居中 */
        }
        .item:nth-child(3) {
            align-self: flex-end; /* 右边的点纵向尾对齐 */
        }

    </style>
</head>
<body>
    <div class="box">
        <span class="item"></span>
        <span class="item"></span>
        <span class="item"></span>
    </div>
</body>
</html>

relative 和 absolute 定位

  • relative 依据自身定位

  • absolute 依据最近一层的定位元素定位,定位元素就是 abosluterelativefixedbody

居中对齐的实现方式

水平居中:

  • inline 元素: text-align: center

  • block 元素:margin: auto

  • absolute 元素: left: 50% + margin-left 负值

垂直居中:

  • inline 元素: 设置 line-height 的值等于 height 的值

  • absolute 元素: top: 50% + margin-top 负值,此方法必须要知道子元素的宽高

  • absolute 元素: transform(-50%, -50%)

  • absolute 元素: 设置 topleftbottomright 为0, 然后设置 margin: auto

line-height 继承的问题

如果一个元素的父元素设置了 line-height 属性,则其子元素都会继承这个属性,它有如下情况:

  • 写具体的数值,如: 30px,则直接继承该值

  • 写比例, 如: 2 / 1.5,则继承该比例

  • 写百分比,如: 200%,则继承计算出来的值(考点)

<style type="text/css">
    body {
        font-size: 20px;
        /* line-height: 50px;  下面的子元素p的line-height为50px */
        /* line-height: 1.5;  下面的子元素p的line-height为24px 16 * 1.5 */
        line-height: 200%; /* 下面的p标签的line-height为40px,直接在父元素上计算后继承到p标签 20px * 200% */
    }
    p {
        background-color: #ccc;
        font-size: 16px;
    }
</style>

rem是什么? 如何利用它来做响应式

rem 是一个长度单位

  • px,绝对长度单位,最常用

  • em,相对长度单位,相对于父元素,不常用

  • rem,相对长度单位,相对于根元素,常用于响应式

如果使用 rem 来做响应式?

我们可以利用 css3 属性 media-query, 根据不同的屏幕宽度设置根元素的 font-size 属性,然后再使用 rem 基于根元素的相对单位来定义元素尺寸

<style type="text/css">
    @media only screen and (max-width: 374px) {
        /* iphone5 或者更小的尺寸,以 iphone5 的宽度(320px)比例设置 font-size */
        html {
            font-size: 86px;
        }
    }
    @media only screen and (min-width: 375px) and (max-width: 413px) {
        /* iphone6/7/8 和 iphone x */
        html {
            font-size: 100px;
        }
    }
    @media only screen and (min-width: 414px) {
        /* iphone6p 或者更大的尺寸,以 iphone6p 的宽度(414px)比例设置 font-size */
        html {
            font-size: 110px;
        }
    }

    body {
        font-size: 0.16rem;
    }
    #div1 {
        width: 1rem;
        background-color: #ccc;
    }

</style>

JavaScript

类型

值类型和引用类型

  • 值类型: undefinedstringnumberbooleansymbol

  • 引用类型: objectarraynullfunction

typeof 能判断哪些类型

  • 能识别所有的值类型
let a;
const str = 'abc';
const n = 100;
const b = true;
const s = Symbol('s');

typeof a;  // undefined
typeof str;  // string
typeof n;  // number
typeof b;  // boolean
typeof s;  // symbol
  • 识别函数
typeof console.log   // function
typeof function() {}  // function
  • 判断是否是引用类型(无法进行下一步细分判断)
typeof null   // object
typeof ['a', 'b']  // object
typeof { x: 100 }  // object

类型转换

const a = 100 + 10  // 110
const b = 100 + '10'  // 10010
const c = true + 10   // true10

在使用 == 进行计算时也会发生类型转换

// 下面使用 == ,发生错误的情况
100 == '100'  // true
0 == ''       // true
0 == false    // true
false == ''   // true
null == undefined  // true

何时使用 ===, 何时使用 ==

除了 == null 之外,其他情况一律使用 ===, 例如:

const obj = { x: 100 }
if (obj.a == null) {
  // ...
}
// 相当于:
// if (obj.a === null || obj.a === undefined) {}

值类型和引用类型的区别

const obj1 = { x: 100, y: 200 }
const obj2 = obj1
let x1 = obj1.x  // 干扰部分..
obj2.x = 101
x1 = 102  // 干扰部分..
console.log(obj1)  // { x: 101, y: 200 }

手写深拷贝

/**
 * 深拷贝
 * @param {Object} obj 要拷贝的对象
 */
function deepClone(obj = {}) {
    if (typeof obj !== 'object' || obj == null) {
        // obj 是 null ,或者不是对象和数组,直接返回
        return obj
    }

    // 初始化返回结果
    let result
    if (obj instanceof Array) {
        result = []
    } else {
        result = {}
    }

    for (let key in obj) {
        // 保证 key 不是原型的属性
        if (obj.hasOwnProperty(key)) {
            // 递归调用!!!
            result[key] = deepClone(obj[key])
        }
    }

    // 返回结果
    return result
}

原型和原型链

ES6 之前的 ES3ES5 都是基于构造函数来实现继承的,而构造函数具有原型属性,目前 ES6 已普及,故这里使用 ES6class 语法糖来理解 JavaScript 中的原型和原型链

在面向对象编程模型中, class 是一个非常重要的概念,我们可以把它理解成某种事物的模板,在这个模板中我们可以定义属性和方法

  • constructor 构造函数,在实例化对象时执行

  • 属性

  • 方法

Javascript中的 class 并不是 JavaC++这些编译型语言中的 class,它只是一个语法糖,本质上,它还是一个函数,这样我们理解起来容易,下面是例子:

// 声明学生类
class Student {
  // 构造函数
  constructor(name, number) {
    this.name = name;
    this.number = number;
  }

  // 方法
  sayHi() {
    console.log(`姓名: ${this.name}, 学号: ${this.number}`)
  }
}

// 实例化
const xialuo = new Student('夏洛', 100);
console.log(xiaoluo.name);  // 夏洛
console.log(xiaoluo.number);  // 100
xiaoluo.sayHi()  // 姓名: 夏洛, 学号: 100 

ES6 通过 extends 关键字实现继承,子类中需要使用 super 方法来执行父类的构造方法,然后就可以扩展或重写方法

// 声明父类
class People {
  constructor(name) {
    this.name = name;
  }

  eat() {
    console.log(`${this.name} eat something`)
  }
}

// 子类 学生
class Student extends People {
  constructor(name, number) {
    super(name);
    this.number = number;
  }

  sayHi() {
    console.log(`姓名: ${this.name}, 学号: ${this.number}`);
  }
}

// 子类 老师
class Teacher extends People {
  constructor(name, major) {
    super(name);
    this.major = major;
  }

  teach() {
    console.log(`${this.name} 教授 ${this.major}`)
  }
}

// 实例化学生
const xialuo = new Student('夏洛', 100);
console.log(xiaoluo.name);  // 夏洛
console.log(xiaoluo.number);  // 100
xiaoluo.eat();  // 夏洛 eat something
xiaoluo.sayHi();  // 姓名: 夏洛, 学号: 100 

// 实例化老师
const wanglaoshi = new Teacher('王老师', '语文');
console.log(wanglaoshi.name);  // 王老师
console.log(wanglaoshi.number);  // 语文
wanglaoshi.eat();  // 王老师 eat something
wanglaoshi.teach();  // 王老师 教授 语文

通过 instanceof 关键字判断实例,实际上就是通过原型来判断

xialuo instanceof Student;  // true
xialuo instanceof People;   // true
xialuo instanceof Object;   // true 所有类都是 Object 的子类

[] instanceof Array;  // true
[] instanceof Object;  // true

{} instanceof Object;  // true

class 实际上就是函数,是一个语法糖

typeof People;  // 'function'
typeof Student; // 'function'

每一个构造函数(class)在创建时都会有一个显式原型,每一个实例都有一个隐式原型,而实例的隐式原型都指向创建它的类(class)的显式原型

xialuo.__proto__  // 隐式原型
Student.prototype  // 显式原型
xialuo.__proto__ === Student.prototype  // true

原型的关系如下:

  • 每个 class 都有显式原型 prototype

  • 每个实例都有隐式原型 __proto__

  • 实例的隐式原型 __proto__ 对应其 class 的显式原型 prototype

如何判断一个变量是数组

a instanceof Array (原型链原理)

作用域和闭包

kaindy7633 avatar Mar 11 '21 14:03 kaindy7633