常考的前端基础面试题(笔记)

常考的基础面试题

    • Html/css基础知识
      • 1.说一下选择器的权重和优先级
      • 2.flex布局
      • 3.说一下实现居中对齐的方式有哪些
        • 水平居中
        • 垂直居中
      • 4.说一下对Html语义化的理解
      • 5.CSS3 动画
      • 6.存储相关的:cookie 和 localStorage 有何区别?
    • Js相关
      • 7.说一下js都有哪些数据类型,如何判断数据的类型,值类型和引用类型有什么区别?
      • 8.如何对js中的数据类型进行判断
      • `typeof`
      • `instanceof`
      • 9.值类型和引用类型的区别
      • 10.原型和原型链
      • 原型的一一些点
      • 原型链
      • 11.作用域和闭包
      • 12.执行上下文
      • 13.`this`
        • **一道题:如何理解 JS 的作用域和作用域链**
      • 14.作用域
      • 15.作用域链
      • 16.闭包
      • 17.异步
        • 同步 vs 异步
        • 异步和单线程
      • 一道题:下面代码的执行过程和结果
      • 前端异步的场景
    • JavaScript面试题
      • 第一道题
      • 第二道题
      • 第三道题
      • 第四题
      • 第五题
      • 第六题
      • 第七题
      • 第八题
      • 第九题
      • 第十题 this指向
      • 第十一题 加载页面渲染过程
      • 第十二题 性能优化相关
      • 第十三题 算法题
      • 第十四题 Vue相关
        • 生命周期钩子函数
        • 组件通信
        • computed 和 watch 区别
        • keep-alive 组件有什么作用
        • v-show 与 v-if 区别
        • 组件中 data 什么时候可以使用对象
        • 响应式原理
      • 第十五题 聊到具体的项目
        • 如何进行应对
        • 没有做过大型项目怎么办
        • 项目细节和技术点的追问
      • 第十六题:软技能问题回答
        • 回想下你遇见过最难打交道的同事,你是如何跟他沟通的
        • 当你被分配一个几乎不可能完成的任务时,你会怎么做
        • 业余时间都做什么?除了写码之外还有什么爱好
    • 面试注意事项
      • 提问环节
      • 面试后的总结和思考

Html/css基础知识

1.说一下选择器的权重和优先级

CSS 选择器有很多,不同的选择器的权重和优先级不一样,对于一个元素,如果存在多个选择器,那么就需要根据权重来计算其优先级。

权重分为四级,分别是:

  1. 代表内联样式,如style="xxx",权值为 1000;
  2. 代表 ID 选择器,如#content,权值为 100;
  3. 代表类、伪类和属性选择器,如.content:hover[attribute],权值为 10;
  4. 代表元素选择器和伪元素选择器,如divp,权值为 1。

需要注意的是:通用选择器(*)、子选择器(>)和相邻同胞选择器(+)并不在这四个等级中,所以他们的权值都为 0。 权重值大的选择器其优先级也高,相同权重的优先级又遵循后定义覆盖前面定义的情况。

2.flex布局

布局的传统解决方案基于盒子模型,依赖 display 属性 + position 属性 + float 属性来实现布局。但是对于那些特殊布局非常不方便,比如,垂直居中就不太容易实现。在目前主流的移动端页面中,使用 flex 布局可以更好地完成需求,因此 flex 布局的知识是必须要掌握的。

基本使用

任何一个容器都可以使用 flex 布局,代码也很简单。

// 按比例分配容器空间
<style type="text/css">
    .container {
      
      display: flex;
    }
    .item {
      
        border: 1px solid #000;
        flex: 1;
    }
style>

<div class="container">
    <div class="item">aaadiv>
    <div class="item" style="flex: 2">bbbdiv>
    <div class="item">cccdiv>
    <div class="item">ddddiv>
div>

可以看到第三个

flex: 2,其他的
flex: 1,这样第二个
的宽度就是其他的
的两倍。

3.说一下实现居中对齐的方式有哪些

水平居中

inline 元素用text-align: center;即可,如下:

像img元素的水平居中也是可以使用的,text-align并不只是对文本元素起作用

.container {
     
   text-align: center;
}

block 元素可使用margin: auto;,PC端很多都是通过这种方式实现的


.item {
    width:400px;
    margin: auto; 
}

绝对定位元素可结合leftmargin实现,但是必须知道宽度。

结合margin需要提前知道宽度

.item {
     
    width: 300px;
    height: 100px;
    position: absolute;
    left: 50%;
    margin-left: -150px;
}

也可以使用transfrom,并且不需要知道宽度

.item {
     
    /* width: 300px; */
    height: 100px;
    position: absolute;
    left: 50%;
    margin-left: -50%;
    transform: translateX(-50%);
    background-color: red;
}

垂直居中

inline 元素可设置line-height的值等于height值,如单行文字垂直居中:

.container {
   height: 50px;
   line-height: 50px;
}

绝对定位元素,可结合leftmargin实现,但是必须知道尺寸。

  • 优点:兼容性好
  • 缺点:需要提前知道尺寸
.container {
    position: relative;
    height: 200px;
}
.item {
    width: 80px;
    height: 40px;
    position: absolute;
    left: 50%;
    top: 50%;
    margin-top: -20px;
    margin-left: -40px;
}

绝对定位可结合transform实现居中。

  • 优点:不需要提前知道尺寸
  • 缺点:兼容性不好 transfrom ,使用在浏览器中使用需要添加前缀进行处理
.container {
    position: relative;
    height: 200px;
}
.item {
    position: absolute;
    left: 50%;
    top: 50%;
    transform: translate(-50%, -50%);
    background: blue;
}

绝对定位结合margin: auto,不需要提前知道尺寸,兼容性好。这个也是比较推荐的一种方式

.container {
    position: relative;
    height: 300px;
}
.item {
    width: 100px;
    height: 50px;
    position: absolute;
    left: 0;
    top: 0;
    right: 0;
    bottom: 0;
    margin: auto;
}

其他的解决方案还有,不过没必要掌握太多,能说出上文的这几个解决方案即可。

比如还有像flex布局,几行代码就可以实现,也是现在在移动端使用非常多的

如果面试中再遇到这个问题就不用慌了。

4.说一下对Html语义化的理解

所谓“语义”就是为了更易读懂,这要分两部分:

  • 让人(写程序、读程序)更易读懂
  • 让机器(浏览器、搜索引擎)更易读懂

让人更易读懂

对于人来说,代码可读性、语义化就是一个非常广泛的概念了,例如定义 JS 变量的时候使用更易读懂的名称,定义 CSS class 的时候也一样,例如length list等,而不是使用a b这种谁都看不懂的名称。

不过平常考查的“语义化”并不会考查这么广义、这么泛的问题,而是考查 HTML 的语义化,是为了更好地让机器读懂 HTML。

让机器更易读懂

HTML 符合 XML 标准,但又和 XML 不一样 —— HTML 不允许像 XML 那样自定义标签名称,HTML 有自己规定的标签名称。

问题就在这里 —— HTML 为何要自己规定那么多标签名称呢,例如p div h1 ul等 —— 就是为了语义化。其实,如果你精通 CSS 的话,你完全可以全部用

标签来实现所有的网页效果,其他的p h1 ul等标签可以一个都不用。但是我们不推荐这么做,这样做就失去了 HTML 语义化的意义。

拿搜索引擎来说,爬虫下载到我们网页的 HTML 代码,它如何更好地去理解网页的内容呢?—— 就是根据 HTML 既定的标签。h1标签就代表是标题;p里面的就是段落详细内容,权重肯定没有标题高;ul里面就是列表;strong就是加粗的强调的内容 …… 如果我们不按照 HTML 语义化来写,全部都用

标签,那搜索引擎将很难理解我们网页的内容。

为了加强 HTML 语义化,HTML5 标准中又增加了header section article等标签。因此,书写 HTML 时,语义化是非常重要的,否则 W3C 也没必要辛辛苦苦制定出这些标准来。

5.CSS3 动画

CSS3 可以实现动画,代替原来的 Flash 和 JavaScript 方案。

如何使用,这里还是带着大家回顾下。

首先,使用@keyframes定义一个动画,名称为testAnimation,如下代码,通过百分比来设置不同的 CSS 样式,规定动画的变化。所有的动画变化都可以这么定义出来。

@keyframes testAnimation
{
    0%   {background: red; left:0; top:0;}
    25%  {background: yellow; left:200px; top:0;}
    50%  {background: blue; left:200px; top:200px;}
    75%  {background: green; left:0; top:200px;}
    100% {background: red; left:0; top:0;}
}

然后,针对一个 CSS 选择器来设置动画,例如针对div元素设置动画,如下:

div {
    width: 100px;
    height: 50px;
    position: absolute;

    animation-name: myfirst;
    animation-duration: 5s;
}

animation-name对应到动画名称,animation-duration是动画时长,还有其他属性:

  • animation-timing-function:规定动画的速度曲线。默认是ease
  • animation-delay:规定动画何时开始。默认是 0
  • animation-iteration-count:规定动画被播放的次数。默认是 1
  • animation-direction:规定动画是否在下一周期逆向地播放。默认是normal
  • animation-play-state :规定动画是否正在运行或暂停。默认是running
  • animation-fill-mode:规定动画执行之前和之后如何给动画的目标应用,默认是none,保留在最后一帧可以用forwards

一道题:CSS 的transition和animation有何区别?

首先transitionanimation都可以做动效,从语义上来理解,transition是过渡,由一个状态过渡到另一个状态,比如高度100px过渡到200px;而animation是动画,即更专业做动效的,animation有帧的概念,可以设置关键帧keyframe,一个动画可以由多个关键帧多个状态过渡组成,另外animation也包含上面提到的多个属性。

6.存储相关的:cookie 和 localStorage 有何区别?

cookie

cookie 本身不是用来做服务器端存储的,它是设计用来在服务器和客户端进行信息传递的,因此我们的每个 HTTP 请求都带着 cookie。但是 cookie 也具备浏览器端存储的能力(例如记住用户名和密码),因此就被开发者用上了。

使用起来也非常简单,document.cookie = ....即可。也有一些第三方库,封装了cookie的一写读取,写入删除的操作,比如js-cookie。我们在后台实战项目中使用的。

但是 cookie 有它致命的缺点:

  • 存储量太小,只有 4KB
  • 所有 HTTP 请求都带着,会影响获取资源的效率
  • API 简单,需要封装才能用

localStorage 和 sessionStorage

HTML5 标准就带来了sessionStoragelocalStorage,先拿localStorage来说,它是专门为了浏览器端缓存而设计的。其优点有:

  • 存储量增大到 5MB
  • 不会带到 HTTP 请求中
  • API 适用于数据存储 localStorage.setItem(key, value) localStorage.getItem(key)

sessionStorage的区别就在于它是根据 session 过去时间而实现,而localStorage会永久有效,应用场景不同。例如,一些需要及时失效的重要信息放在sessionStorage中,一些不重要但是不经常设置的信息,放在localStorage中。

这里在使用的时候有个注意点,针对localStorage.setItem,使用时尽量加入到try-catch中,某些浏览器是禁用这个 API 的,要注意。

Js相关

7.说一下js都有哪些数据类型,如何判断数据的类型,值类型和引用类型有什么区别?

ECMAScript 中定义了 6 种原始类型:

  • Boolean
  • String
  • Number
  • Null
  • Undefined
  • Symbol(ES6 新定义)

现在还新增了一个bigInt 类型,这个给大家讲ES6-10语法的时候,给大家讲过。

注意:原始类型是不包含 Object。像Js的数据类型可以分为两大类,值类型,和引用类型。

8.如何对js中的数据类型进行判断

typeof

typeof xxx得到的值有以下几种类型:undefined boolean number string object functionsymbol ,比较简单。这里需要注意的有三点:

  • typeof null结果是object ,实际这是typeof的一个bug,null是原始值,非引用类型
  • typeof [1, 2]结果是object,结果中没有array这一项,引用类型除了function其他的全部都是object
  • typeof Symbol()typeof获取symbol类型的值得到的是symbol,这是 ES6 新增的知识点

instanceof

用于实例和构造函数的对应。例如判断一个变量是否是数组,使用typeof无法判断,但可以使用[1, 2] instanceof Array来判断。因为,[1, 2]是数组,它的构造函数就是Array。同理:

但是instanceof也有问题
比如 
[] instanceof Array // true
[] instanceof Object // 也是true

最佳的判断方法是什么

// 使用toString方法
// 对于 Object 对象,直接调用 toString()  就能返回 [object Object] 。
// 而对于其他对象,则需要通过 call / apply 来调用才能返回正确的类型信息。借用object的toString方法来进行判断
Object.prototype.toString.call('') ;   // [object String]
Object.prototype.toString.call(1) ;    // [object Number]
Object.prototype.toString.call(true) ; // [object Boolean]
Object.prototype.toString.call(Symbol()); //[object Symbol]
Object.prototype.toString.call(undefined) ; // [object Undefined]
Object.prototype.toString.call(null) ; // [object Null]
Object.prototype.toString.call(new Function()) ; // [object Function]
Object.prototype.toString.call(new Date()) ; // [object Date]
Object.prototype.toString.call([]) ; // [object Array]
Object.prototype.toString.call(new RegExp()) ; // [object RegExp]
Object.prototype.toString.call(new Error()) ; // [object Error]
Object.prototype.toString.call(document) ; // [object HTMLDocument]
Object.prototype.toString.call(window) ; //[object global] window 是全局对象 global 的引用

9.值类型和引用类型的区别

除了原始类型,ES 还有引用类型,上文提到的typeof识别出来的类型中,只有objectfunction是引用类型,其他都是值类型。

根据 JavaScript 中的变量类型传递方式,又分为值类型引用类型,值类型变量包括 Boolean、String、Number、Undefined、Null,引用类型包括了 Object 类的所有,如 Date、Array、Function 等。在参数传递方式上,值类型是按值传递,引用类型是按共享传递。

引用类型经常会在代码中按照下面的写法使用,或者说容易不知不觉中造成错误

var obj = {
     
    a: 1,
    b: [1,2,3]
}
var a = obj.a
var b = obj.b
a = 2
b.push(4)
console.log(obj, a, b)

虽然obj本身是个引用类型的变量(对象),但是内部的ab一个是值类型一个是引用类型,a的赋值不会改变obj.a,但是b的操作却会反映到obj对象上。

所以也是需要注意一下


10.原型和原型链

JavaScript 是基于原型的语言,原型理解起来非常简单,但却特别重要,下面还是通过题目来理解下JavaScript 的原型概念。

一道题:如何理解 JavaScript 的原型

对于这个问题,可以从下面这几个要点来理解和回答,下面几条必须记住并且理解

  • 所有的引用类型(数组、对象、函数),都具有对象特性,即可自由扩展属性(null除外)
  • 所有的引用类型(数组、对象、函数),都有一个__proto__属性,属性值是一个普通的对象
  • 所有的函数,都有一个prototype属性,属性值也是一个普通的对象
  • 所有的引用类型(数组、对象、函数),__proto__属性值指向它的构造函数的prototype属性值

通过代码来看一下


// 要点一:自由扩展属性
var obj = {
     }; obj.a = 100;
var arr = []; arr.a = 100;
function fn () {
     }
fn.a = 100;

// 要点二:__proto__
console.log(obj.__proto__);
console.log(arr.__proto__);
console.log(fn.__proto__);

// 要点三:函数有 prototype
console.log(fn.prototype)

// 要点四:引用类型的 __proto__ 属性值指向它的构造函数的 prototype 属性值
console.log(obj.__proto__ === Object.prototype)

原型的一一些点

先写一个简单的代码示例。

// 构造函数
function Foo(name, age) {
     
    this.name = name
}
Foo.prototype.alertName = function () {
     
    alert(this.name)
}
// 创建示例
var f = new Foo('zhangsan')
f.printName = function () {
     
    console.log(this.name)
}
// 测试
f.printName()
f.alertName()

执行printName时很好理解,但是执行alertName时发生了什么?这里再记住一个重点 当试图得到一个对象的某个属性时,如果这个对象本身没有这个属性,那么会去它的__proto__(即它的构造函数的prototype)中寻找,因此f.alertName就会找到Foo.prototype.alertName

那么如何判断这个属性是不是对象本身的属性呢?使用hasOwnProperty,常用的地方是遍历一个对象的时候。

var item
for (item in f) {
     
    // 高级浏览器已经在 for in 中屏蔽了来自原型的属性,但是这里建议大家还是加上这个判断,保证程序的健壮性
    if (f.hasOwnProperty(item)) {
     
        console.log(item)
    }
}

题目:如何理解 JS 的原型链

原型链

还是接着上面的示例,如果执行f.toString()时,又发生了什么?

// 省略 N 行

// 测试
f.printName()
f.alertName()
f.toString()

因为f本身没有toString(),并且f.__proto__(即Foo.prototype)中也没有toString。这个问题还是得拿出刚才那句话——当试图得到一个对象的某个属性时,如果这个对象本身没有这个属性,那么会去它的__proto__(即它的构造函数的prototype)中寻找

如果在f.__proto__中没有找到toString,那么就继续去f.__proto__.__proto__中寻找,因为f.__proto__就是一个普通的对象而已嘛!

  • f.__proto__Foo.prototype,没有找到toString,继续往上找
  • f.__proto__.__proto__Foo.prototype.__proto__Foo.prototype就是一个普通的对象,因此Foo.prototype.__proto__就是Object.prototype,在这里可以找到toString
  • 因此f.toString最终对应到了Object.prototype.toString

这样一直往上找,你会发现是一个链式的结构,所以叫做“原型链”。如果一直找到最上层都没有找到,那么就宣告失败,返回undefined。最上层是什么 —— Object.prototype.__proto__ === null

关于原型,原型链的知识几乎是面试中必考的点,所以大家必须要掌握,根据这张经典的图好好理解下。


11.作用域和闭包

作用域和闭包是前端面试中,最可能考查的知识点。例如下面的题目:

一道题:现在有个 HTML 片段,要求编写代码,点击编号为几的链接就alert弹出其编号

<ul>
    <li>编号1,点击我请弹出1li>
    <li>2li>
    <li>3li>
    <li>4li>
    <li>5li>
ul>

一般不知道这个题目用闭包的话,会写出下面的代码:

var list = document.getElementsByTagName('li');
for (var i = 0; i < list.length; i++) {
     
    list[i].addEventListener('click', function(){
     
        alert(i + 1)
    }, true)
}

实际上执行才会发现始终弹出的是6,这时候就应该通过闭包来解决:

var list = document.getElementsByTagName('li');
for (var i = 0; i < list.length; i++) {
     
    list[i].addEventListener('click', function(i){
     
        return function(){
     
            alert(i + 1)
        }
    }(i), true)
}

现在使用ES6就更简单了

var list = document.getElementsByTagName('li');
for (let i = 0; i < list.length; i++) {
     
    list[i].addEventListener('click', function(){
     
        alert(i + 1)
    }, true)
}

要理解闭包还跌从执行上下文开始

12.执行上下文

先讲一个关于 变量提升 的知识点,面试中可能会遇见下面的问题,很多人都回答错误:

一道题:说出下面执行的结果

console.log(a)  // undefined
var a = 100

fn('zhangsan')  // 'zhangsan' 20
function fn(name) {
     
    age = 20
    console.log(name, age)
    var age
}

console.log(b); // 这里报错
// Uncaught ReferenceError: b is not defined
b = 100;

在一段 JS 脚本(即一个

你可能感兴趣的:(面试必备)