• 面试总结(2019年12月20日)


    1.js实现promise

    1.promise和async/await的区别

    函数前面多了一个async关键字。await关键字只能用在async定义的函数内。async函数会引式返回一个promise,改promise的resolve值就是函数return的值。
    简洁:使用async和await明显节约了不少代码,不需要.then,不需要写匿名函数处理promise的resolve的值,不需要定义多余的data变量,还避免了嵌套代码。
    async/await让try/catch 可以同时处理同步和异步错误。try/catch不能处理JSON.parse的错误,因为他在promise中。此时需要.catch,这样的错误处理代码非常冗余。并且,在我们的实际生产代码会更加复杂

    1.什么是promise,解决了什么问题

    Promise 概括来说是对异步的执行结果的描述对象
    Promise最大的好处是在异步执行的流程中,把执行代码和处理结果的代码清晰地分离了。
    解决回调地狱(Callback Hell)问题
    
    由于Promise只能被决议一次,且决议之后无法改变,所以,即便是多次回调,也不会影响结果,决议之后的调用都会被忽略。

    1.async的返回值是什么

    1.async函数的返回值是Promise对象,可以用then方法指定下一步的操作。async函数可以看做多个异步操作,包装成一个Promise对象,await命令就是内部then命令的语法糖。
    
    2.async函数返回一个Promise对象,可以使用then方法添加回调函数。当函数执行的时候,一旦遇到await就会先返回,等到异步操作完成,再接着执行函数体后面的语句。

    2.vue data为什么是一个函数  

    组件是可复用的vue实例,一个组件被创建好之后,就可能被用在各个地方,而组件不管被复用了多少次,组件中的data数据都应该是相互隔离,互不影响的,基于这一理念,组件每复用一次,
    data数据就应该被复制一次,之后,当某一处复用的地方组件内data数据被改变时,其他复用地方组件的data数据不受影响

    总结:组件中的data写成一个函数,数据以函数返回值形式定义,这样每复用一次组件,就会返回一份新的data,类似于给每个组件实例创建一个私有的数据空间,让各个组件实例维护各自的数据。
    而单纯的写成对象形式,就使得所有组件实例共用了一份data,就会造成一个变了全都会变的结果。

    3.写一个ES5继承和ES6继承

    //组合继承
    function Supertype(name){
        this.name = name;
        this.colors = ["red","green","blue"];
    }
    ​
    Supertype.prototype.sayName = function(){
        console.log(this.name);
    };
    ​
    function Subtype(name,age){
        \继承属性
        Supertype.call(this,name);
        this.age  = age;
    }
    ​
    \继承方法
    Subtype.prototype = new Supertype();
    Subtype.prototype.constructor = Subtype;
    Subtype.prototype.sayAge = function(){
        console.log(this.age);
    };
    ​
    var instance1 = new Subtype('Annika',21);
    
    //构造函数继承
    缺点:方法都在构造函数中定义,函数无法复用
    
    在超类型中定义的方法,子类型不可见,结果所有类型都只能使用构造函数模式
    
    function Supertype(name){
        this.name = name;
    }
    ​
    function Subtype(){
        Supertype.call(this,'Annika');
        this.age  = 21;
    }
    ​
    var instance = new Subtype;
    console.log(instance.name);  \Annika
    console.log(instance.age);   \29
    View Code
    class Colorpoint extends Point {
        constructor(x,y,color){
            super(x,y); //调用父类的constructor(x,y)
            this.color = color
        }
        toString(){
            //调用父类的方法
            return this.color + ' ' + super.toString(); 
        }
    }
    View Code

    4.写一个数组去重的方法 

    利用indexOf去重
    function unique(arr) {
        if (!Array.isArray(arr)) {
            console.log('type error!')
            return
        }
        var array = [];
        for (var i = 0; i < arr.length; i++) {
            if (array .indexOf(arr[i]) === -1) {
                array .push(arr[i])
            }
        }
        return array;
    }
    var arr = [1,1,'true','true',true,true,15,15,false,false, undefined,undefined, null,null, NaN, NaN,'NaN', 0, 0, 'a', 'a',{},{}];
    console.log(unique(arr))
    
    利用ES6 Set去重(ES6中最常用)
    function unique (arr) {
      return Array.from(new Set(arr))
    }
    var arr = [1,1,'true','true'];
    console.log(unique(arr))
    
    利用对象的属性不能相同的特点进行去重(这种数组去重的方法有问题,不建议用,有待改进)
    function unique(arr) {
        if (!Array.isArray(arr)) {
            console.log('type error!')
            return
        }
        var arrry= [];
         var  obj = {};
        for (var i = 0; i < arr.length; i++) {
            if (!obj[arr[i]]) {
                arrry.push(arr[i])
                obj[arr[i]] = 1
            } else {
                obj[arr[i]]++
            }
        }
        return arrry;
    }
    View Code

    5.移动端点透事件

    使用 fastclick 插件
    这个也是在网上看到的,也可以解决点透问题,使用方法可以看 fastclick 的文档,在这里提供一下 Vue.js 的引入及使用
    
    import FastClick from 'fastclick'; // 引入插件
    FastClick.attach(document.body, options); // 使用 fastclick
    或者
    1. 直接用click,不考虑延迟,

    2. 下层避开click事件,如a链接改为span等标签,使用js跳转页面

    dom2二级事件 取消默认行为 addEventListener   e.preventDefault()

    利用touch事件模拟click,延迟一定的时间(300ms+)来处理事件

    6.移动端一像素边框问题怎么解决的 

    transform: scale(0.5)   border-image border-shower 都可以解决

    7.vue实现原理

    使用Object.defineProperty实现MVVM的表单数据双向绑定,当修改data属性之后,Vue立刻监听到,data属性被代理到vm上。

    下面举一个例子

    var obj = {}
    var name = 'lili'
    Object.defineProperty(obj, "name",{
     get: function () {
     console.log('get')
     return name
     },
     set: function (newValue) {
     console.log('set')
            name = newValue
     }
    });
    
    console.log(obj.name)
    obj.name = 'xiaoming'
    View Code

    注:set是用来监听属性值被修改,get是获取某个属性时的监听,那有必要加get吗,有!当创建了很多属性时,可以通过get知道这个属性是否被用到,当没有被用过时,就不必要要监听这个属性。vue是数据驱动视图,数据的修改会触发视图变化,当没用到的数据被修改时,我们就不用管他,因为视图上就没用到,不必浪费时间来更新视图。

    Vue使用了基于html的模版语法,模版的本质是字符串,但是它有逻辑,v-if,v-for等,最终还是要转化成html来显示,模版最终必须转化成js代码,因为转换为html渲染页面,必须js才能实现,因此,模版最终要转换成一个js函数(render函数),render函数执行之后,返回的是vnode,updateComponent中实现了vdom的patch,页面首次渲染执行updateComponent,data中每次修改属性,执行updateComponent

    <div id="app">
       <p>{{name}}</p>
    </div>
    View Code

    上面的代码被转换的render函数

    with(this) {
     return _c(
         'div',
         {
            attrs: {"id": "app"}
         },
         [
           _c('p',[_v(_s(name))])
         ]
      )
    }  
    View Code

    c是生成div结点,v是生成文本内容,_s其实是toString();

    可以在Vue源码中搜索code.render,在

    var code = generate(ast, options)

    下面打印出code.render就可以看到模版被转换后的render函数

    总结:Vue实现流程

    • 解析模版成render函数
    • 响应式开始监听
    • 首次渲染,显示页面且绑定依赖
    • data属性变化,触发rerender

    Vue实现了数据和视图的分离,解耦,以数据驱动视图,只关系数据的变化,DOM操作被封装。

    8.vue computed和watch的区别

    计算属性computed : 
    
    1. 支持缓存,只有依赖数据发生改变,才会重新进行计算
    2. 不支持异步,当computed内有异步操作时无效,无法监听数据的变化
    3.computed 属性值会默认走缓存,计算属性是基于它们的响应式依赖进行缓存的,也就是基于data中声明过或者父组件传递的props中的数据通过计算得到的值
    4. 如果一个属性是由其他属性计算而来的,这个属性依赖其他属性,是一个多对一或者一对一,一般用computed
    5.如果computed属性属性值是函数,那么默认会走get方法;函数的返回值就是属性的属性值;在computed中的,属性都有一个get和一个set方法,当数据变化时,调用set方法。
    
    侦听属性watch:
    
    1. 不支持缓存,数据变,直接会触发相应的操作;
    2.watch支持异步;
    3.监听的函数接收两个参数,第一个参数是最新的值;第二个参数是输入之前的值;
    4. 当一个属性发生变化时,需要执行对应的操作;一对多;
    5. 监听数据必须是data中声明过或者父组件传递过来的props中的数据,当数据变化时,触发其他操作,函数有两个参数,
      immediate:组件加载立即触发回调函数执行,
      deep: 深度监听,为了发现对象内部值的变化,复杂类型的数据时使用,例如数组中的对象内容的改变,注意监听数组的变动不需要这么做。注意:deep无法监听到数组的变动和对象的新增,参考vue数组变异,只有以响应式的方式触发才会被监听到。
    
    如果一个数据需要经过复杂计算就用 computed
    如果一个数据需要被监听并且对数据做一些操作就用 watch
    View Code

    9.vue 组件通信

    10.vue query和params 的区别

    11.vue watch深监听怎么搞

    12.vuex 比如有两个module 如果两个名字相同 怎么commit 

    vuex中的store分模块管理,需要在store的index.js中引入各个模块,为了解决不同模块命名冲突的问题,将不同模块的namespaced:true
    之后在不同页面中引入getter、actions、mutations时,需要加上所属的模块名

    13.你们vue项目用的是hash路径还是history的

    14.浏览器打开一个url 发生了什么

    15.会css3动画吗 都有什么

    16.flex的属性都有什么

    flex-direction: row|row-reverse|column|column-reverse|initial|inherit;
    flex-grow: number|initial|inherit;
    flex-wrap 属性规定flex容器是单行或者多行,同时横轴的方向决定了新行堆叠的方向。
    flex-wrap: nowrap|wrap|wrap-reverse|initial|inherit;
    flex-shrink: number|initial|inherit;

    17.左边固定 右边自适应怎么搞?

    18.平时怎么封装组件的?
    19.cookies和sessionstorage的区别

    20.闭包什么

    21.ES6的新特性有哪些

    22.let和var的区别

    let 配合for循环的独特应用
    let非常适合用于 for循环内部的块级作用域。JS中的for循环体比较特殊,每次执行都是一个全新的独立的块作用域,用let声明的变量传入到 for循环体的作用域后,不会发生改变

    let没有变量提升与暂时性死区

    let声明的变量,不存在变量提升。而且要求必须 等let声明语句执行完之后,变量才能使用,不然会报Uncaught ReferenceError错误

    let变量不能重复声明

    var 存在变量提升,而 let 不存在变量提升,所以用 let 定义的变量一定要在声明后再使用

    var:只有全局作用域和函数作用域概念,没有块级作用域的概念。

    let:只有块级作用域的概念 ,由 { } 包括起来,if语句和for语句里面的{ }也属于块级作用域。

  • 相关阅读:
    Python全栈开发:socket
    Python全栈开发:线程、进程和协程
    Python全栈开发:基本数据类型
    Python全栈开发:运算符
    使用pyplot和seaborn进行画图
    数据预处理之缺失值的处理
    数据预处理之标准化
    数据预处理之离散化
    集成学习中的 stacking 以及python实现
    使用sklearn进行交叉验证
  • 原文地址:https://www.cnblogs.com/yangsg/p/12071008.html
Copyright © 2020-2023  润新知