前端面经(三)

笔试题

1.数组扁平化/数组降维

目的:把多维数组(尤其是二维数组)转化为一维数组

方法一:使用遍历

function flat(arr) {
    // 验证 arr 中,还有没有深层数组 [1, 2, [3, 4]]
    const isDeep = arr.some(item => item instanceof Array)
    if (!isDeep) {
        return arr // 已经是 flatern [1, 2, 3, 4]
    }

    const res = Array.prototype.concat.apply([], arr)
    return flat(res) // 递归
}

const res = flat([1, 2, [3, 4, [10, 20, [100, 200]]], 5])
// instanceof 运算符用于检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上。
// some() 方法测试数组中是不是至少有1个元素通过了被提供的函数测试。它返回的是一个Boolean类型的值。
//  concat() 方法用于合并两个或多个数组。此方法不会更改现有数组,而是返回一个新数组。
// apply() 方法调用一个具有给定this值的函数。apply方法的第一个参数会作为被调用函数的this值,apply方法的第二个参数(一个数组,或类数组的对象)会作为被调用对象的arguments值,也就是说该数组的各个元素将会依次成为被调用函数的各个参数;
// Array.prototype.concat.apply([], [1, 2, 3, [4, 5, 6], 7, 8, [9, 10]]) 效果等同于 [].concat(1, 2, 3, [4, 5, 6], 7, 8, [9, 10])

方法二:使用 ES6 API flat()

var arr1 = [1, 2, [3, 4]];
arr1.flat();
// [1, 2, 3, 4]

var arr2 = [1, 2, [3, 4, [5, 6]]];
arr2.flat();
// [1, 2, 3, 4, [5, 6]]

var arr3 = [1, 2, [3, 4, [5, 6]]];
arr3.flat(2);
// [1, 2, 3, 4, 5, 6]

//使用 Infinity,可展开任意深度的嵌套数组
var arr4 = [1, 2, [3, 4, [5, 6, [7, 8, [9, 10]]]]];
arr4.flat(Infinity);
// [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

2.数组去重

方法1.传统方式,遍历元素挨个比较、去重

// 传统方式
function unique(arr) {
    const res = []
    arr.forEach(item => {
        if (res.indexOf(item) < 0) {
            res.push(item)
        }
    })
    return res
}

const res = unique([30, 10, 20, 30, 40, 10])
console.log(res)

方法2.使用Set (效率更高)

// 使用 Set (无序,不能重复)
function unique(arr) {
    const set = new Set(arr) // Set(4) {30, 10, 20, 40}
    return [...set] //  [30, 10, 20, 40]
}

const res = unique([30, 10, 20, 30, 40, 10])
console.log(res)

3.场景题:async/await的顺序问题

async function async1() {
    console.log('async1 start') // 2
    await async2()

    // await后面的都作为回调内容 —— 微任务
    console.log('async1 end') // 6
}

async function async2() {
    console.log('async2') // 3
}

console.log('script start') // 1

setTimeout(function () { // 宏任务 setTimeout
    console.log('setTimeout') // 8
}, 0)

async1()

// 初始化 Promise 时,传入的函数会立刻被执行
new Promise(function (resolve) {
    console.log('promise1') // 4
    resolve()
}).then(function () { // 微任务
    console.log('promise2') // 7
})

console.log('script end') // 5
// 同步代码执行完毕(event loop - call stack 被清空)
// 执行微任务
// 尝试触发 DOM 渲染
// 触发 Event Loop,执行宏任务

打印结果
在这里插入图片描述

面试题

1.描述vue双向数据绑定原理(包括底层代码如何实现)

object这个对象有个方法,叫做defineProperty,当数据发生访问或者修改,它都能够监测到,就是做到了一个数据劫持
一旦数据变化,他就会立即通知相关DOM更新页面,这个就用到了发布订阅者模式

<!-- Object.defineProperty -->
<!-- 数据劫持 -->
<!-- 发布订阅者模式 -->
<script>
  var book = {};
  var name = "";
  // 参1: 要给哪个对象设置属性
  // 参2: 属性名称是啥
  // 参3: 对象, 封装set和get方法
  Object.defineProperty(book, "name", {
    // 一旦修改了属性, 就会走到set方法中, value表示修改的内容
    // book.name = "xxx"
    set: function (value) {
      name = value;
      // 检测到数据变化的时候, 更新一下dom
      $("h1").text(value);
      $("input").val(value)
    },

    // 一旦读取属性, 就会走到get方法中
    // book.name
    get: function (value) {
      return name;
    }
  });

  //input事件: 只要文本框内容发生了变化, 就会执行回调函数
  $("input").on("input", function () {
    book.name = $(this).val(); //返回值, 决定了将来调用book.name返回的值
  });

  var num = 0;
  $("button").click(function () {
    book.name = num++;

    console.log(book.name);
  });
</script>

2.跨域解决方案

方案一:JSONP
1.原理
由于浏览器同源策略的限制,网页中无法通过 Ajax 请求非同源的接口数据。但是 <script> 标签不受浏览器同源策略的影响,可以通过 src 属性,请求非同源的 js 脚本。

因此,JSONP 的实现原理,就是通过 <script> 标签的 src 属性,请求跨域的数据接口,并通过函数调用的形式,接收跨域接口响应回来的数据。

2.缺点
由于 JSONP 是通过 <script> 标签的 src 属性,来实现跨域数据获取的,所以,JSONP 只支持 GET 数据请求,不支持 POST 请求。

注意:JSONP 和 Ajax 之间没有任何关系,不能把 JSONP 请求数据的方式叫做 Ajax,因为 JSONP 没有用到 XMLHttpRequest 这个对象。

方案二:跨域资源共享(CORS)

  • CORS是一个W3C标准,支持 GET 和 POST 请求。缺点是不兼容某些低版本的浏览器。

  • 它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。

  • 实现CORS通信的关键是服务器。只要服务器实现了CORS接口,就可以跨源通信。
    在这里插入图片描述在这里插入图片描述

3.介绍http协议

  • HTTP协议超文本传输协议 (HyperText Transfer Protocol) ,它规定了客户端与服务器之间进行网页内容传输时,所必须遵守的传输格式。
  • HTTP 协议采用了 请求/响应 的交互模型。
    在这里插入图片描述
  • 客户端发起的请求叫做 HTTP 请求,客户端发送到服务器的消息,叫做 HTTP 请求报文。
    在这里插入图片描述
  • 服务器响应给客户端的消息内容,叫作响应报文。

4.介绍promise

  • 概念
    Promise 是异步编程的一种解决方案。从语法上讲,promise是一个对象,用它可以获取异步操作的消息

  • 作用:
    用同步的方式写异步的代码,可以解决回调地狱问题。
    promise对象提供统一的接口,使得控制异步操作更加容易。

  • 三种状态
    pending (待定)状态,不会触发then和catch
    resolved(成功,又称 Fulfilled)状态,会触发后续的then回调函数
    rejected(失败)状态,会触发后续的catch回调函数

5.响应式布局有哪几种

  • 媒体查询(media-query),根据不同的屏幕宽度设置根元素font-size
  • flex 布局
  • 百分比布局

6.rem+媒体查询实现响应式布局的原理

使用媒体查询,根据不同的屏幕宽度设置根元素font-size

 @media (min-width: 320px) {
      html {
        /*font-size: 100/750 * 320px*/
        font-size: 42.67px;
      }
    }
    @media (min-width: 375px) {
      html {
        font-size: 50px;;
      }
    }
    @media (min-width: 414px) {
      html {
        font-size: 55.2px;;
      }
    }
    @media (min-width: 480px) {
      html {
        font-size: 64px;;
      }
    }
    @media (min-width: 640px) {
      html {
        font-size: 85.33px;
      }
    }
    @media (min-width: 750px) {
      html {
        font-size: 100px;;
      }
    }

7.flex弹性布局的特点

优点:容易上手,根据flex规则很容易达到某个布局效果。
缺点:浏览器兼容性比较差,只能兼容到ie9及以上。

8.css3动画效果如何实现

step1. 用keyframes 定义动画(类似定义类选择器)

@keyframes 动画名称 {
   0%{
        width:100px;
   }  
   100%{
        width:200px;
   }
}
  • 动画序列
    在这里插入图片描述

step2. 元素使用动画

div {
       width: 200px;
       height: 200px;
       background-color: aqua;
       margin: 100px auto;
       /* 调用动画 */
       animation-name: 动画名称;
       /* 持续时间 */
       animation-duration: 持续时间;
    }

  • 动画常用属性在这里插入图片描述

  • 动画简写属性
    在这里插入图片描述

9.inline元素加margin和padding值有效吗

10.场景题:隔行变色效果的实现

关键点:要用到css3新特性中的结构伪类选择器

  • E:nth-child(even) 匹配父元素中的偶数个子元素
  • E:nth-child(odd) 匹配父元素中的奇数个子元素
    <style>
        /* 1. 把所有的偶数 even 孩子选出来 */     
        ul li:nth-child(even) {
            background-color: #ccc;
        }
        
        /* 2. 把所有的奇数 odd 的孩子选出来 */      
        ul li:nth-child(odd) {
            background-color: #ddd;
        }
    </style>

11.场景题:一行上 有两个盒子,如何让左边的 固定宽度,右边盒子自适应

12.伪元素和伪类元素

结构伪类选择器
在这里插入图片描述
伪元素选择器
在这里插入图片描述

13.清除浮动的几种方式

清除浮动主要是为了解决,父元素因为子级元素浮动引起的内部高度为0的问题。
清除浮动之后,父级就会根据浮动的子盒子自动检测高度。父级有了高度,就不会影响下面的标准流了

方法1 — 额外标签法
也称为隔墙法,是 W3C 推荐的做法。
会在浮动元素末尾添加一个空的标签。例如<div style=“clear:both”>,或者其他标签(如<br />等)

方法2 — 父级添加 overflow 属性
可以给父级添加 overflow 属性,将其属性值设置为 hiddenauto scroll

方法3 — 父级添加after伪元素√

        .clearfix:after {
            content: '';
            display: table;
            clear: both;
        }

14.溢出文字省略号显示

1. 单行文本

/*1. 先强制一行内显示文本*/ 
white-space: nowrap; ( 默认 normal 自动换行) 
/*2. 超出的部分隐藏*/ 
overflow: hidden; 
/*3. 文字用省略号替代超出的部分*/ 
text-overflow: ellipsis;

注意:

  • 设置文本溢出显示省略号时必须有宽度 width;
  • 必须要设置display属性为line-block/block,设置为其他值不生效。

2. 多行文本

overflow: hidden;
text-overflow: ellipsis;
/* 弹性伸缩盒子模型显示 */
display: -webkit-box;
/* 限制在一个块元素显示的文本的行数 */
-webkit-line-clamp: 2;
/* 设置或检索伸缩盒对象的子元素的排列方式 */
-webkit-box-orient: vertical;

多行文本溢出显示省略号,有较大兼容性问题, 适合于webKit浏览器或移动端(移动端大部分是webkit内核)

15.vuex的作用

  • 概述
    Vuex是实现组件全局状态(数据)管理的一种机制,可以方便的实现组件之间的数据共享

  • 特性

    • State提供唯一的公共数据源,所有共享的数据都要统一放到Store中的State中存储
    • Mutation用于修改变更$store中的数据
    • 使用Action来执行异步操作
    • Getter用于对Store中的数据进行加工处理形成新的数据
      • Getter只会包装Store中保存的数据,并不会修改Store中保存的数据,当Store中的数据发生变化时,Getter生成的内容也会随之变化

16.vue组件如何通信

父传子
通过props传递

父组件: <child value = ‘传递的数据’ />

子组件: props[‘value’],接收数据,接受之后使用和data中定义数据使用方式一样

子传父
在父组件中给子组件绑定一个自定义的事件,子组件通过$emit()触发该事件并传值。

父组件: <child @receive = ‘receive’ />

子组件: this.$emit(‘receive’,‘传递的数据’)

兄弟组件传值

通过中央通信 let bus = new Vue()

A:methods :{ 函数{bus.$emit(‘自定义事件名’,数据)} 发送

B:created (){bus.$on(‘A发送过来的自定义事件名’,函数)} 进行数据接收

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值