前端基础面试题

一、HTML

1.0 如何理解 HTML 语义化?

第一段代码:

<div>标题</div>
 <div>
   <div>一段文字</div>
   <div>
     <div>列表1</div>
     <div>列表2</div>
   </div>
</div>

第二段代码:

<h1>标题</h1>
<div>
  <p>一段文字</p>
   <ul>
     <li>列表1</li>
     <li>列表2</li>
   </ul>
</div>

以上两段代码,第一段代码给人的感觉就全是div,不方便阅读。第二段代码相比第一段代码来说,能让人知道写的具体是什么内容,让人更加容易读懂,增加了代码的可阅读性。相对于机器来说,识别第一段代码机器只能识别到div,而对于第二段代码,机器就能清楚的识别出h1表示的是标题,重点突出,p表示文字,ul li 表示一个列表。这样可以使得搜索引擎更容易读懂,更加利于SEO的优化。

1.1 默认情况下,哪些标签是块级元素、哪些是内联元素、哪些是空标签?

块级元素独占一行,display:block/table的都是块级元素,有 div、h1~h6、table、ul、ol、li、p、section 等元素。
内联元素不会独占一行,display:inline/inline-block的都是内联元素,有 a、img、span、b、strong、input、select、button 等元素。
空标签的元素有 br、hr、img、input、meta、link

二、CSS - 布局

1.0 盒子模型的宽度如何计算?

如下代码,请问 box 的 offsetWidth 是多大?

<style>
    #box {
      width: 100px;
      border: 1px solid red;
      margin: 10px;
      padding: 10px;
    }
</style>
<div id="box">
    这是一个盒子
</div>

offsetWidth 的宽度 = 内容宽度 + 内边距 + 边框,没有外边距,因此这个 box 的 offsetWidth 宽度为 122
补充:如果让 offsetWidth 的宽度等于 100px,该如何做?
添加 box-sizing:border-box

1.1 margin 纵向重叠的问题(所谓纵向重叠就是很多个元素纵向排列,它们如果有 margin ,这个 margin 就会有重叠的问题

如下代码,请问 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-top 和 margin-bottom 会发生重叠
空白的 <p></p> 也会重叠
答案为15px

1.2 margin 负值的问题

margin-left 与 margin-top 负值,元素会向上、向左移动。
margin-right 负值,右侧元素左移,自身不受影响。 (例如:A元素B元素在一行,A元素设置 margin-right:-10px,此时B元素就会向左边移动10px,而A元素不会发生变化。)
margin-bottom 负值,下方元素上移,自身不受影响。(例如:A元素在上面,B元素在下面,A元素设置margin-bottom:-10px。此时B元素就会向上边移动10px,而A元素不会发生变化。)

1.3 BFC理解和应用,什么是 BFC?如何应用?

创建 BFC

  1. float 不是 none
  2. position 是 absolute 或 fixed
  3. overflow 不是 visible
  4. display 是 flex、inline-block等。

BFC(Block formatting context) 是块级格式化上下文 就是页面上一个独立的容器,在它内部的子元素不会影响到容器外的元素。
内部的元素会在垂直方向,一个接一个的放置。

BFC 清除浮动应用

<style>
    .par {
      width: 300px;
      border: 5px solid red;
      overflow: hidden;
    }

    .par .child {
      float: left;
      border: 5px solid green;
      width: 100px;
      height: 100px;
   }
  </style>
<div class="par">
   <div class="child"></div>
   <div class="child"></div>
 </div>

添加overflow: hidden

image.png

添加overflow: hidden

image.png

1.4 float 布局的问题,以及claerfix

如何实现圣杯布局和双飞翼布局?
圣杯布局和双飞翼布局的技术总结:

  • 使用 float 布局。
  • 两边使用 margin 负值,以便和中间内容横向重叠。
  • 防止中间内容被两侧覆盖,一个用 padding 一个用 margin。

圣杯布局:使用 padding-left 和 padding-right 为左右两边留出位置。

<style>
    * {
      margin: 0;
      padding: 0;
    }
    header,
    footer {
      width: 100%;
      background-color: red;
    }
    .container {
      padding-left: 200px;
      padding-right: 150px;
    }
    .container .left {
      position: relative;
      width: 200px;
      background-color: green;
      margin-left: -100%;
      right: 200px;
    }
    .container .right {
      width: 150px;
      background-color: pink;
      margin-right: -150px;
    }
    .container .center {
      width: 100%;
      background-color: blue;

    }
    .container .column {
      float: left;
    }
    footer {
      clear: both;
    }
</style>
</head>
<body>
  <header>头部</header>
  <div class="container">
    <div class="center column">中间</div>
    <div class="left column">左边</div>
    <div class="right column">右边</div>
  </div>
  <footer>尾部</footer>
</body>
image.png

优点:不需要添加多余的 DOM 节点
缺点:浏览器缩小至左边或右边的固定宽度后,圣杯布局会发生错乱。

双飞翼布局:使用 margin-left 和 margin-right 为左右两边留出位置。

<style>
    * {
      margin: 0;
      padding: 0;
    }
    .box {
      background-color: red;
      width: 100%;
      height: 200px;
    }
    .box .main {
      margin-left: 200px;
      margin-right: 100px;
    }
    .left {
      width: 200px;
      height: 200px;
      background-color: green;
      margin-left: -100%;
    }
    .right {
      width: 100px;
      height: 200px;
      background-color: pink;
      margin-left: -100px;
    }
    .column {
      float: left;
    }
</style>
<body>
  <div class="box column">
    <div class="main">
      中间
    </div>
  </div>
  <div class="left column">左边</div>
  <div class="right column">右边</div>
</body>
image.png

优点:不会像圣杯布局那样发生布局错乱
缺点:多添加了一个 DOM 节点

手写 claerfix 清除浮动

<style>
.clearfix::after{
    content:'';
    display:table;
    clear:both;
}
</style>
1.5 使用 flex 布局画一个骰子

image.png

代码如下:

<style>
    .box {
      width: 150px;
      height: 150px;
      border: 2px solid #ccc;
      border-radius: 10px;
      padding: 10px;
      display: flex;
      justify-content: space-between;
    }
    .box .circle {
      display: block;
      width: 50px;
      height: 50px;
      border-radius: 50%;
      background-color: red;
    }
    .box .circle:nth-child(2) {
      align-self: center;
    }
    .box .circle:nth-child(3) {
      align-self: flex-end;
    }
</style>
<div class="box">
    <span class="circle"></span>
    <span class="circle"></span>
    <span class="circle"></span>
</div>
1.6 relative 和 absolute 分别依据什么定位?

relative 相对定位,是根据自身定位
absolute 绝对定位,是根据最近一层的元素定位

1.7 居中对齐有哪些实现方式?

水平居中:

  • inline 元素:text-align:center
  • block 元素:margin:auto
  • absolute 元素:left:50% + margin-left:宽度一半的负值

垂直居中:

  • inline 元素:line-height 行高的值等于 height 高度的值
  • absolute 元素:top:50% + margin-top:高度一半的负值
  • absolute 元素:transform:translate(-50%,-50%)
  • absolute 元素:top,right,bottom,left都等于 0 ,然后设置 margin:auto
1.8 line-height 的继承问题

如下代码,p 标签的行高会是多少?

<style>
    body {
      font-size: 20px;
      line-height: 200%;
    }
    p {
      font-size: 16px;
      background-color: red;
    }
</style>
<body>
  <p>AAA</p>
</body>

当 line-height 的值是百分比的时候,就会由当前百分比 * font-size 得到后的值继承给 p 标签,所以此时的 p 标签的行高为 40
当 line-height 的值为 1、2 或者 20px、30px,p 标签会直接继承下来,1、2 的值为继承下来 * 当前标签的 font-size。例如:body 现在的行高为 line-height:2,p 标签此时的行高则为 font-size 的 16 * 2 得到行高 32

1.9 rem 是什么?

rem 是一个长度单位,相对于 html 根元素,常用于响应式布局,html 根元素的 font-size 为 100px ,则 1rem 等于 100px。

2.0 如何实现响应式?

如下代码,实现三种尺寸的响应式大小

<style>
    @media screen and (max-width:374px) {
      html {
        font-size: 86px;
      }
    }
    @media screen and (min-width:375px) and (max-width:413px) {
      html {
        font-size: 100px;
      }
    }
    @media screen and (min-width:414px) {
      html {
        font-size: 110px;
      }
    }
    .box {
      font-size: 0.16rem;
      width: 1rem;
      background-color: #ccc;
    }
</style>
<body>
  <div class="box">
    这是一个盒子
  </div>
</body>

当屏幕宽度小于 374px 时,盒子宽度为 86px,字体为 13.76px
当屏幕宽度大于 375px 并且小于 413px 时,盒子宽度为 100px,字体为 16px
当屏幕宽度大于 414px 时,盒子宽度为 110px ,字体为 17.6px

三、JavaScript

1.0 typeof 可以判断哪些类型?

可以识别所有值类型,例如:字符串(string),布尔值(boolean),undefined,数字(number),symbol
可以识别函数类型:函数(function)。
可以识别引用类型(不可细分),例如:null、对象、数组使用 typeof 判断出来的类型都是 Object。

1.1 何时使用 === 何时使用 ==

当判断一个值是否等于 null 时,使用 == 进行判断:

const obj = { x: 100};
if(obj.x == null){}

相当于:

if (obj.x === null || obj.x === undefined) { }

除了判断 null 时,建议判断其他类型时一律使用 ===

1.2 值类型和引用类型的区别是什么?
  • 值类型:字符串string,数值number,布尔booleannullundefined

    1. 占用空间固定,保存在中。
    2. 保存与复制是值的本身。
    3. 使用 typeof 检测数据类型。
    4. 基本类型数据是值类型。
  • 引用类型:数组Array,对象Object,函数Function

    1. 占用空间不固定,保存在中。
    2. 保存与复制是指向对象的一个指针。
    3. 使用 instanceof 检测数据类型。
    4. 使用 new 方法构造出来的对象是引用类型。
1.3 手写深拷贝
<script>
    const obj = {
      name: '张三',
      age: 18,
      sex: '男',
      address: {
        city: '北京'
      }
    }
    const newObj = deepClone(obj)
    newObj.address.city = '成都'
    console.log(obj.address.city); // 北京
    console.log(newObj.address.city); // 成都

    function deepClone(obj = {}) {
      // 判断 obj 不是数组和对象  或者 obj 是 null
      if (typeof obj !== 'object' || obj == null) {
        return obj
      }
      let result;
      // 判断 obj 是不是数组
      if (Array.isArray(obj)) {
        result = []
      } else {
        result = {}
      }

      // 循环
      for (let key in obj) {
        // 保证 key 不是原型的属性
        if (obj.hasOwnProperty(key)) {
          // 递归调用
          result[key] = deepClone(obj[key])
        }
      }
      return result
    }
</script>
1.4 使用 class 实现继承

代码如下:

<script>
    // 父类 人
    class Person {
      constructor(name) {
        this.name = name;
      }
      eat() {
        console.log(`${this.name}正在吃饭!`);
      }
    }

    // 子类 学生 继承 父类 人
    class Student extends Person {
      constructor(name, num) {
        super(name)
        // 学号
        this.num = num;
      }
      sayHi() {
        console.log(`${this.name}向你打了个招呼`)
      }
    }

    // 子类 老师 继承 父类 人
    class Teacher extends Person {
      constructor(name, major) {
        super(name);
        // 专业
        this.major = major;
      }
      teach() {
        console.log(`${this.name}正在教学生们${this.major}`);
      }
    }

    const student = new Student('张三', '000001');
    const teacher = new Teacher('王老师', '语文课');

    console.log(student.name);
    console.log(student.num);
    student.sayHi();
    student.eat()

    console.log(teacher.name);
    console.log(teacher.major);
    teacher.teach()
    teacher.eat()

    console.log(student.__proto__ === Student.prototype);  // true
    console.log(Person.prototype === Student.prototype.__proto__);  // true

    /*
    张三
    000001
    张三向你打了个招呼
    张三正在吃饭!
    
    王老师
    语文课
    王老师正在教学生们语文课
    王老师正在吃饭!
    */
</script>
1.5 如何理解 JS 原型

显示原型:prototype,隐式原型:__proto__
原型关系:

  • 每个 class 都有显示原型 prototype
  • 每个实例都有隐式原型 __proto__
  • 实例的 __proto__ 指向对应 classprototype

基于原型的执行规则:

  • 获取属性或者执行方法时,先在自身属性和方法中寻找,如果找不到则自动去 __proto__ 隐式原型中查找。
1.6 如何准确判断一个变量是不是数组?
  • a instanceof Array
    • 缺点:只能判断对象是否存在于目标对象的原型链上。
  • 通过 E6 数组方法 Array.isArray(值) 判断一个变量值是否是数组,成功返回 true 否则返回 false
  • 通过原型链 Object.prototype.toString.call(值) ,输出 "[object Array]" 代表是数组。
1.7 闭包是什么?
    // 函数作为返回值
    function fnc() {
      var a = 100;
      return function () {
        console.log(a);
      }
    }
    let fn = fnc();
    var a = 200;
    fn() // 100

    // 函数作为参数
    function print(fn) {
      let a = 200;
      fn()
    }
    let a = 100;
    function fnc() {
      console.log(a);
    }
    print(fnc)  // 100

闭包就是获取其他函数内部变量的函数。
闭包就是定义一个在函数内部的函数。
闭包就是将函数内部和函数外部连接起来的一座桥梁。

闭包:自由变量的查找,是从定义函数的地方,向上级作用域查找。 不是在执行函数的地方查找!!!

1.8 手写 bind 函数
<script>
    Function.prototype.bindTest = function () {
      // 将类数组转换成数组
      const args = [...arguments];
      // 获取 this 数组的第一项
      const t = args.shift();
      // 当前 this
      const self = this;
      // 返回一个函数
      return function () {
        return self.apply(t, args);
      }
    }

    function fn1(a, b, c) {
      console.log('this', this);
      console.log(a, b, c);
      return 'this is fn1'
    }
    const fn2 = fn1.bindTest({ x: 100 }, 100, 200, 300);
    const res = fn2()
    console.log(res);
    /*
    this { x: 100 }
    100 200 300
    this is fn1
    */
</script>
1.9 异步和同步的区别
  • 基于 JS 是单线程语言
  • 异步不会阻塞代码执行
  • 同步会阻塞代码执行

前端异步的应用场景:网络请求&定时任务。
Promise 解决 callback 嵌套

2.0 编写一个通用的事件监听函数
<script>
    // 通用事件绑定
    function bindEvent(el, type, selector, fn) {
      // 判断 三个参数  还是四个参数
      if (fn == null) { // 三个参数
        fn = selector;
        selector = null
      }
      el.addEventListener(type, e => {
        const target = e.target;
        // 存在说明是代理绑定
        if (selector) {
          // 使用 matches 来判断是否触发元素
          if (target.matches(selector)) {
            fn.call(target, e);
          }
        } else {
          // 普通绑定
          fn.call(target, e)
        }
      })
    }

    const ul = document.querySelector('ul');
    const li = document.querySelectorAll('li');
    bindEvent(li[0], 'click', function (e) {
      console.log(this.innerHTML);
    })
    bindEvent(ul, 'click', 'li', function (e) {
      console.log(this.innerHTML);
    })
  </script>
2.1 手写防抖

防抖是什么?防抖就是用户在触发事件后,在指定时间内只会执行一次,如果触发事件后,在指定时间内再次触发,则会重新计算函数延迟执行时间。

防抖代码如下:

<body>
    <input type="text" id="input">
</body>
<script>
    const input = document.getElementById('input');
    // 监听事件
    input.addEventListener('keyup', debounce(function () {
      console.log(this.value);
    }, 1000))
    // 防抖
    function debounce(fn, delay = 500) {
      let timer;
      return function () {
        if (timer) {
          clearTimeout(timer)
        }
        timer = setTimeout(() => {
          fn.apply(this, arguments);
          timer = null
        }, delay)
      }
    }
</script>
2.2 手写节流

节流是什么?节流就是用户触发事件后,在指定时间内只执行一次,如果触发事件后,在指定时间内再次触发,则不会影响上次触发,直到触发事件执行结束。多次点击在指定时间内只会执行一次。

节流代码如下:

<body>
    <button id="btn">按钮</button>
</body>
<script>
    const btn = document.getElementById('btn');
    // 监听点击事件
    btn.addEventListener('click', throttle(function () {
      console.log(666);
    }, 1000))
    // 节流定时器
    function throttle(fn, delay = 500) {
      let timer;
      return function () {
        if (timer) return false;
        timer = setTimeout(() => {
          fn.apply(this, arguments);
          timer = null;
        }, delay)
      }
    }
    // 节流时间戳
    function throttle(fn, delay = 500) {
      // 触发时间
      let pre = Date.now();
      return function () {
        // 当前时间
        let now = Date.now();
        if (now - pre >= delay) {
          fn.apply(this, arguments)
          pre = Date.now();
        }
      }
    }
</script>
2.3 DomContentLoaded 和 load 的区别
  • load
    load 用于检测一个完全加载的页面,页面的 html、css、js 等资源全部加载完毕后才会触发 load 事件。
  • DomContentLoaded
    当初始的 html 加载和解析完毕后,就会触发 DomContentLoaded 事件,无需等待其他资源完成加载。

四、Vue.js

1.0 v-showv-if 有什么区别?

v-show 会在 DOM 里生成全部元素节点,使用 display:block/none 控制显示隐藏,用于频繁的加载。
v-if 用于不频繁加载的时候,因为它每次都是在 DOM 中创建一个新的元素出来。

1.1 v-for 中为什么要使用 key

因为 v-for 正在更新已染的列表时,它默认‘就地复用’策略,如果列表中的顺序发生改变或者被删除某项时,vue 不是移动 DOM元素来匹配数据项的改变,而是会简单的复用现有的元素,并且确定它在特定的索引下显示已经被渲染过的每个元素。为了给 vue 一个提示,便于让它跟踪每个元素,从而更好的重排现有元素,就需要为每一项添加一个 key 作为唯一值。key 的作用主要是为了高效的更新虚拟DOM。

1.2 vue 组件的生命周期(父子组件)
1.3 vue 组件如何进行通讯?
1.4 computed 和 watch
  • computed 有缓存,data 不变则不会重新计算
  • watch 如何深度监听?
  • watch 监听引用类型,拿不到 oldVal
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • 1、<img> 的title 和alt 有什么区别 alt属性和title属性相同点: 它们都会出现浮层,显示自己...
    糖醋鱼_阅读 4,514评论 0 2
  • title: 基础面试题date: 2019-10-12 20:23:00updated: 2019-10-12 ...
    铅笔芯的Ta阅读 5,017评论 0 0
  • HTML押题1.(必考)你是如何理解HTML语义化的 第一种举例:段落用P,边栏用aside,主要内容用main标...
    24_Magic阅读 2,087评论 0 1
  • 1、css实现图片自适应宽高 主要使用padding-bottom,该属性是基于父元素宽度百分比的; 2、什么是B...
    行走的巨象阅读 8,677评论 7 74
  • 表情是什么,我认为表情就是表现出来的情绪。表情可以传达很多信息。高兴了当然就笑了,难过就哭了。两者是相互影响密不可...
    Persistenc_6aea阅读 128,431评论 2 7

友情链接更多精彩内容