学习前端知识点归纳

159 阅读3分钟

一、scss和less的区别

区别之处:

  1. 编译环境不一样 Less是基于JavaScript,是在客户端处理的。Sass是基于Ruby的,是在服务器端处理的。
  2. 变量符不一样,Less是@,而Scss是$。
  3. 输出设置,Less没有输出设置,Sass提供4种输出选项:nested, compact, compressed 和 expanded。
  4. Sass支持条件语句,可以使用if{}else{},for{}循环等等。而Less不支持。
  5. 引用外部CSS文件 css@import引用的外部文件如果不想编译时多生成同名的.css文件,命名必须以_开头, 文件名如果以下划线_开头的话,Sass会认为该文件是一个引用文件,不会将其编译为同名css文件.
  6. Sass和Less的工具库不同 Sass有工具库Compass, Less有UI组件库Bootstrap.

二、Vue中样式穿透

场景:如果你的引入了第三方库,例如element-ui,如果你想修改第三方库的样式,直接通过dom查找,修改样式(如颜色,边距等)是没有效果的

  • css可以使用>>>/deep/::v-deep
  • lessnode-sass可以使用/deep/::v-deep
  • dart-sass可以使用::v-deep

三、for in 和 for of 的区别

for in遍历的是数组的索引(即键名),而for of遍历的是数组元素值

for in可以得到对象的key或数组、字符串的下标

for of不能直接遍历对象, 可以先通过 Object.keys 得到对象的键再获取值

四、 echarts的使用

  • 第一步:下载echars包。
  • 第二步:准备一个具备大小(宽高)的 DOM,也就是容器
  • 第三步:然后可以通过echarts.init()方法初始化一个echarts实例,init里面放入的是一个dom对象
  • 第四步:调用生成dom对象,设置配置项空的option 即可
  • 第五步:调用方法,生成效果图
1:准备容器
<div id="main" style="width: 600px;height:400px;"></div>
2:初始化echart实例
var myChart = echarts.init(document.getElementById('main'));
3:指定图表的配置项和数据 (根据文档提供示例找到option)
var option = {
    xAxis: {
        type: 'category',
        data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
    },
    yAxis: {
        type: 'value'
    },
    series: [{
        data: [820, 932, 901, 934, 1290, 1330, 1320],
        type: 'line'
    }]
};
4:调用方法,生成效果图
myChart.setOption(option);

五、 防抖和节流

防抖:多次触发只执行最后一次

  
    <script>
 // timer 必须定义为全局变量,因为如果是局部变量,后一次无法访问到前一次的变量值;
        let timer = null;
 // 获取元素,绑定事件
        document.querySelector('button').onclick = function () {
 // 防抖的核心代码,后一次触发的时候,如果前一次的延时器还没有执行,那么就不要执行了;
            clearTimeout(timer);
  // 防抖就是多次触发某个逻辑,只执行最后一次; 
            timer = setTimeout(function () {
    // 将来的代码,就写道这里;
                console.log('ajax请求已发出...');
            }, 1000);
        }
    </script>

节流:多次触发只执行第一次

 <script>
  // 开关,控制器,开闭原则;
        let flag = false;
  // 获取元素,绑定事件
        document.querySelector('button').onclick = function () {
  // 节流的核心代码是,不能频繁触发定时器;
  // 在定时器里面的代码,执行完毕之前,都不能触发;
            if (flag) {
                return;
            }
  // 经过if判断,如果flag的值是false,就把他改为true
            flag = true;
  // 节流的逻辑是,多次触发某个事件,以第一次为主,执行完毕之后才能触发第二次;
           setTimeout(function () {
                console.log("模拟ajax发送...");
  // 代码执行完毕之后,再把flag改为false
                flag = false;
            }, 2000);
        }
    </script>

六、 介绍下 Set、Map、WeakSet 和 WeakMap 的区别

Set他的键和值是一样的,同时他有一个特性,就是存储不重复的元素,所以可以应用他用来值类型的数组去重或者求数组的交集

 let arr=[1,2,3,3,3,3]
        let arr1=[2,3,4]
        let arr2=[7,8,9,10]

        // 求交集
        let setList=new Set([...arr1,...arr2])
        let setList1=new Set(arr)
        Array.from(setlist)
        console.log(setList,"求交集");
        console.log(setList1,"去重");

七、 Async/Await 是如何通过同步的⽅式来实现异步?

AsyncAwait实质上是Generator的语法糖, 采⽤单向链表的处理⽅式, 利⽤async相当于function *,await相当 于yeild. 函数加上async后, 就会返回⼀个Promise对象, 并将return的结果执⾏Promise.resolve(). await会等待后⾯的异步Promise执⾏完成后拿到resolve结果后再向下执⾏.

八、 3个判断数组的⽅式

1:Object.prototype.toString.call()

因为⼀切皆对象, 所以理论上来说所有类型的数据都可以通过toString⽅法来得到 [object type] 的结果, 但是除了Object类型的对象外, 其他类型的数据直接调⽤toString会转化为内容的字符串, 所以 需要通过Object.prototype.toString.call的⽅式来调⽤, 缺点是toString⽅法可能会被᯿写, 影响判断结 果.

Object.prototype.toString.call('An')// "[object String]"
Object.prototype.toString.call(1) // "[object Number]"
Object.prototype.toString.call(Symbol(1)) // "[object Symbol]"
Object.prototype.toString.call(null) // "[object Null]"
Object.prototype.toString.call(undefined) // "[object Undefined]"
Object.prototype.toString.call(function(){}) // "[object Function]"
Object.prototype.toString.call({name: 'An'}) // "[object Object]"

2 instanceOf

instanceof判断⼀个对象是否是数组, 是通过判断这个对象的原型链上是否能找到对应的Array的原 型, 然后返回true和false, 但是instanceof只能判断对象类型, 原始类型必须通过new来创建才可以检测, ⽐如new String, ⽽且所有的对象类型instanceof Object的时候都会返回true, ⽽更改对象原型链指向 Array的话也会影响判断.

let a = '1';
a instanceof String; // false
a = new String('1');
a instanceof String; // true
 
a = [];
a instanceof Array; // true
a instanceof Object; // true
 
a = new Number(1);
a.__proto__ = Array.prototype;
a instanceof Array; // true

3 Array.isArray()

isArray是ES5推出解决判断是否为数组的⽅法, 所以可能会有兼容问题

九、 Vue的双向数据绑定, Model如何改变View, View⼜是 如何改变Model的

1:MVVM的双向绑定, 采⽤的是数据劫持集合发布订阅模式的⽅式

2:⾸先需要⼀个解析器Compile来扫描和解析每个结点的指令, 根据指令模板替换数据,以及绑定相应的更新函数

3:通过设置⼀个Observer利⽤Object.defineProperty(Proxy)来劫持各个属性的setter和getter, 如有数据变动可通知订阅者

4: Wacther作为Observer和Compile的桥梁, 可以订阅并收到每个数据变动的通知, 执⾏指令绑定的相应动作,从⽽更新视图

十、 Vue中, ⼦组件为何不可以修改⽗组件传递的Prop, 如果修改了,Vue是如何监控到属性修改并给出警告的

因为Vue是单向数据流的, ⽗组件的数据不可以被⼦组件修改

if (process.env.NODE_ENV !== 'production') {
 var hyphenatedKey = hyphenate(key);
 if (isReservedAttribute(hyphenatedKey) || config.isReservedAttr(hyphenatedKey)) {
 warn( ("\"" + hyphenatedKey + "\" is a reserved attribute and cannot be used as 
component prop."), Vm );
 }
 defineReactive$$1(props, key, value, function () {
 if (!isRoot && !isUpdatingChildComponent) {
 warn( "Avoid mutating a prop directly since the value will be " + "overwritten 
whenever the parent component re-renders. " + "Instead, use a data or computed property 
based on the prop's " + "value. Prop being mutated: \"" + key + "\"", Vm );
 }
 });

在initProps的时候, 会去判断是否在开发环境, 如果是开发环境, 会在触发set的时候判断时候是否此key处 于updatingChildren中被修改, 如果不是, 说明此修改来⾃⼦组件, 触发warning 需要注意的是, 丛⼦组件修改的prop属于基础类型的时候才会触发提示, ⽽且这样是⽆法修改⽗组件数据 源的, 但是当修改object属性时不会触发提示, 并且会修改⽗组件数据源的数据

十一、 Vue 的响应式原理中 Object.defineProperty 有什么缺陷?

Vue在3.0中采⽤的Proxy, 抛弃了object.defineProperty

  • DP⽆法监控到数组下标的变化, 导致通过数组下标添加元素, 不能实时响应
  • DP只能劫持对象的属性, 从⽽需要对每个对象, 每个属性进⾏遍历, 如果属性值是对象, 还需要深度遍
  • 历, Proxy能劫持整个对象, 并返回⼀个新对象
  • Proxy不仅可以代理对象, 还可以代理数组, 还可以代理动态增加的属性

十二、分析⽐较opacity: 0; visibility: hidden; display: none;优劣和使⽤场景

  • display-none 不占空间, 不能点击;显示出原来这⾥不存在的结构,导致⻚⾯回流
  • visibility-hidden 占据空间,不能点击;显示不会导致⻚⾯回流
  • opacity-0 占据空间, 可以点击; 只是颜⾊完全透明, 可以跟transition搭配实现⼀些特效

十三 介绍下webpack热更新原理, 是如何做到在不刷新浏览器的前提下更新⻚⾯的

  1. 当修改了⼀个或者多个⽂件
  2. ⽂件系统接受更改并通知webpack
  3. webpack᯿新编译构建⼀个或者多个模块, 并通知HMR服务器进⾏更新
  4. HMR Server使⽤webSocket通知HMR runtime需要更新, HMR runtime通过HTTP请求更新jsonp
  5. HMR runtime替换更新中的模块, 如果确定这些模块⽆法更新, 则触发整个⻚⾯的刷新

十四、 为什么普通for循环的性能要⾼于forEach的性能, 请解释原因

for循环没有任何额外的函数调⽤栈和上下⽂查找, forEach不是普通for循环的语法题, 还有诸多参数传递/函数调⽤/上下⽂查找等需要在执⾏的时候考虑进来.

十五、介绍下BFC/IFC/GFC/FFC

  • BFC 是块级格式上下⽂, ⻚⾯中的⼀个隔离的渲染区域.
  • IFC 是内联格式上下⽂, ⾼度由其⾏内元素最⾼的实例⾼度计算⽽来
  • GFC 是⽹格格式上下⽂, display-grid, 可以定义⾏和列实现⽹格布局
  • FFC 是⾃适应格式上下⽂, flex or inline-flex, 弹性布局

十六、 介绍下Promise.all的使⽤/原理实现及错误处理

Promise.all⽅法接受⼀个数组作为参数, p1,p2,p3都是Promise实例, 如果不是, 就会先调⽤Promise.resolve 将参数转为Promise实例

十七、 mutation 里面可以放异步吗?

非严格模式确实是可以放异步,代码也可以正常执行!严格模式下不能这样操作(写异步),会有警告。 不建议放异步代码,目的是为了形成数据快照(拿到当时的那个数据状态)便于溯源,同时在vuex数据更新也会出现延迟现象,为了配合 DevTools 调试。

十八、vuex中的数据在页面刷新后数据消失

用sessionstorage 或者 localstorage 存储数据

存储: sessionStorage.setItem( '名', JSON.stringify(值) )
使用: sessionStorage.getItem('名') ---得到的值为字符串类型,用JSON.parse()去引号;