自己遇到的面试问题整理

  1. ES6的类

  2. vue的生命周期

    VUE生命周期是指VUE实例对象从创建之初到销毁的过程,总共分为八个阶段:创建前/后、载入前/后、更新前/后、销毁前/后。
    beforeCreate:在实例刚在内存中被创建,还没有初始化data和methods等属性
    created:实例已经在内存中初始化完成,此时data和methods已经初始化完成,但还没有开始编译模板。
    beforeMount:已经完成了模板的编译,但还没有挂载在页面中。
    mounted:已经将模板挂载到了页面指定的容器中。
    beforeUpdate:页面状态更新之前执行,此时vue实例属性中的状态值是新的,但是页面是展示的数据还是旧的,还没有开始重新渲染DOM节点。
    updated:页面更新之后调用,实例的属性值和页面的数据已完成同步,界面重新渲染完成。
    beforeDestroy:vue实例销毁前调用,此时实例仍然可用。
    destroyed:vue实例销毁后调用,此时vue实例指示的所有东西会解除绑定,所有的事件监听器会被移除,所有的子实例也会摧毁。

  3. v-if和v-show的区别

    v-if是将元素添加或移除dom树模型中。v-show只是在这个属性上添加display:none。
    当出现闪现或部分闪烁的时候,可以添加v-cloak,并设置它的样式解决。

    <style>
    	[v-cloak]{
    		display: none;
    	}
    </style>
    <!-- 添加这个v-cloak -->
    <div id='app' v-cloak>
    	<div v-if="isShow">
    		content
    	</div>
    </div>
    
  4. vue组件之间传值

    组件之间传值

  5. vuex是什么

    vuex是专门为vue.js应用程序开发的状态管理模式,可以理解为我们项目中需要共享一些数据,我们把它集中管理起来的容器。把这些数据称为状态。
    state: 所有数据都存放在state中
    定义state

    //
    new Vuex.Store({
        state: {
            token: '',
            todos: [
                { id: 1, text: '...', done: true },
                { id: 2, text: '...', done: false }
            ]
        },
    })
    

    vue组件使用

    //
    // 直接调用
    this.$store.state.token
    // 通过计算属性,直接用{{ token }},或者this.token就能调用
    computed: {
        token () {
            return this.$store.state.token
        }
    }
    // 或者调用 mapState
    import { mapState } from 'vuex'
    
    computed: {
        ...mapState({
            token: state => state.token
        })
        // 或者
        ...mapState([
            'token'
        ])
    }
    

    getter: 可以对state进行过滤和加工,可以认为是store的计算属性。
    定义getter

    new Vuex.Store({
        getters: {
            // state 作为其第一个参数
            doneTodos: state => {
                return state.todos.filter(todo => todo.done)
            },
            // getters 可作为第二个参数
            doneTodosCount: (state, getters) => {
                return getters.doneTodos.length
            },
            // 让 getter 返回一个函数,来实现给 getter 传参,对 store 里的数组进行查询时非常有用
            getTodoById: state => id => {
                return state.todos.find(todo => todo.id === id)
            }
            // 使用:this.$store.getters.getTodoById(2) // -> { id: 2, text: '...', done: false }
        },
    })
    

    在vue组件中使用

    // 直接调用
    this.$store.getters.doneTodos
    // 通过计算属性,直接用{{ doneTodosCount }},或者this.doneTodosCount就能调用
    computed: {
        doneTodosCount () {
            return this.$store.getters.doneTodosCount
        }
    }
    // 或者调用 mapGetters
    import { mapGetters } from 'vuex'
    computed: {
        // getter 属性另取一个名字,使用对象形式
        ...mapGetters({
            doneCount: 'doneTodosCount'
        })
        // 或者
        ...mapGetters([
            'doneTodos',
            'doneTodosCount'
        ])
    }
    

    mutations: 在vuex中只能通过提交mutations来修改store中的状态,且是一个同步的过程。
    定义mutations

    new Vuex.Store({
        mutations: {
            // state 作为第一个参数,接收第二个参数为传入的对象
            setToken (state, obj) {
                const st = state
                st.token = obj
            }
        },
    })
    

    在需要多人协作的大型项目中,使用常亮替代mutation事件类型

    // 新建 mutation-types.js
    export const SET_TOKEN = 'SET_TOKEN' // 设置token
    
    // store.js
    import { SET_TOKEN } from './mutation-types'
    new Vuex.Store({
        mutations: {
            // state 作为第一个参数,接收第二个参数为传入的对象
            [SET_TOKEN] (state, obj) {
                const st = state
                st.token = obj
            }
        },
    })
    

    在vue组件中使用

    // 直接调用
    this.$store.commit('setToken', obj)
    // 在 methods 里使用 mapMutations,就可以 @click="setToken(obj)" 来调用
    import { mapMutations } from 'vuex'
    methods: {
        ...mapMutations({
            setToken: 'SET_TOKEN'
        })
        // 或者
        ...mapMutations([
            'setToken',
            'SET_TOKEN'
        ])
    }
    

    actions: 通过调用mutation方法异步的改变state状态
    定义action

    new Vuex.Store({
        actions: {
            // context 对象作为第一个参数,与 store 实例具有相同方法和属性,但不是 store 实例本身
            login (context) {
                context.commit('SET_TOKEN')
                console.log(context.state)
                console.log(context.getters)
            }
            // es2015 参数结构的方式,接收第二个对象作为参数传入
            login ({ commit, state, getters }, obj) {
                commit('SET_TOKEN')
            }
            // 异步操作,例:
            login ({ commit }, params) {
                const { account, pwd } = params
                // 定义一个promise
                return new Promise((resolve, reject) => {
                    // 异步操作
                    Vue.prototype.$apis.login({ account: account, pwd: pwd }).then(response => {
                        if (response.code === '000') {
                            const { data } = response
                            // 调用mutation
                            commit('SET_TOKEN', data.token)
                            setToken(data.token)
                            // 可以在成功后传出数据
                            resolve(data.loginStats)
                        } else {
                            reject(response.message)
                        }
                    }).catch(error => {
                        reject(error)
                    })
                })
            }
            // 组合 action,利用async await和dispatch来实现多action的嵌套调用
            async actionB ({ dispatch, commit }) {
                await dispatch('actionA') // 等待 actionA 完成
                commit('gotOtherData', await getOtherData())
            }
        },
    })
    

    在vue组件中使用

    // 直接调用
    this.$store.dispatch('login', obj)
    // 调用 action 中的异步操作,并处理
    this.$store.dispatch('login', params).then((val) => {
        this.$message.success('登录成功!')
        val && this.$router.push('home')
    }).catch(err => {
        console.log('登录错误: ', err)
    })
    // 在 methods 里使用 mapActions,就可以 @click="login(obj)" 来调用
    import { mapActions } from 'vuex'
    methods: {
        ...mapActions({
            login: 'login'
        })
        // 或者
        ...mapActions([
            'login'
        ])
    }
    

    modules: 将store分割成模块,每个模块拥有自己的state、mutation、action、getter、甚至是嵌套子模块
    定义modules

    // 定义一个 user.js 模块
    const user = {
        namespaced: false,
        state: {
            userInfo: {}
        },
        getters: {
            // rootState是根节点状态
            getUser (state, getters, rootState) {}
        },
        mutations: {
            setUser (state) {}
        },
        actions: {
            // rootState是根节点状态
            getUserInfo ({ state, commit, rootState }) {}
        }
    }
    export default user
    
    // 在store.js中导入
    import Vue from 'vue'
    import Vuex from 'vuex'
    import user from './modules/user' // 导入模块user
    Vue.use(Vuex)
    export default new Vuex.Store({
        state: {},
        getters: {},
        mutations: {},
        actions: {},
        modules: {
            user
        }
    })
    

    在vue组件中使用
    默认情况下,模块内的action、mutation和getter是注册在全局命名空间的,只有state注册在自己的模块内,调用需要加上模块名。调用的方式:

    // state
    computed: {
        ...mapState({
            userInfo: state => state.user.userInfo
        })
        ...mapGetters({
            getUser: 'getUser'
        })
    }
    // getters
    this.$store.getters.getUser
    // mutations
    this.$store.commit('setUser', obj)
    // actions
    this.$store.dispatch('getUserInfo', obj)
    

    设置 namespaced:true 使模块具有更高的封装度和复用性。
    这是模块内的getter会有第四参数 rootGetters,作为访问全局getter:

    getters: {
        // rootState是根节点状态
        getUser (state, getters, rootState, rootGetters) {}
    },
    actions: {
        // rootState是根节点状态
        getUserInfo ({ state, commit, rootState, rootGetters }) {}
    }
    

    在组件中调用commit和dispatch时,需要在具体mutation和action前把模块名加上:

    // mutations
    this.$store.commit('user/setUser', obj)
    // actions
    this.$store.dispatch('user/getUserInfo', obj)
    

    在设置 namespaced: true 子模块内想要调用全局的 mutation 或者 action 时需要将 { root: true } 作为第三参数传给 dispatch 或 commit:

    // mutations
    commit('SET_TOKEN', obj, { root: true })
    // actions
    dispatch('otherModule/getUserInfo', obj, { root: true })
    
  6. http和https有什么不同

    http协议:是超文本传输协议,信息是明文传输。如果攻击者截取了Web浏览器和网站服务器之间的传输报文,就可以直接读懂其中的信息。

    https协议:是具有安全性的ssl加密答传输协议,为浏览器和服务器之间的通信加密,确保数据传输的安全。

  7. JavaScript 中 call()、apply()、bind() 的用法和区别

    JavaScript 中有三个方法Function.prototype.call()、Function.prototype.apply()和Function.prototype.bind()可以用来指定函数 this 值。call() 和 apply() 类似,都是调用函数,并指定函数的 this 值thisArg和参数,区别在于call()传入参数是通过参数列表的形式arg1, arg2, …,apply()传入参数是通过数组的形式[arg1, arg2, …]:

    function.call(thisArg, arg1, arg2, ...)
    function.apply(thisArg, [arg1, arg2, ...])
    

    bind()方法与前两个不同,它创建一个新的函数,在调用新函数时,会调用原函数,并指定原函数的 this 值和参数。bind() 执行的时候并没有调用函数。bind()传入参数的方式和call()一样,都是用参数列表:

    fucntion.bind(thisArg, arg1, arg2, ...)
    

    用法
    call()
    使用call()调用父类构造函数来实现继承,也可以用apply(),只不过传参方式略有区别:

    // 使用 call 实现继承
    	var Pet = function (name, age) {
    	  this.name = name
    	  this.age = age
    	}
    	var Cat = function (name, age, color) {
    	  Pet.call(this, name, age)
    	  this.color = color
    	}
    	var cat = new Cat('Garfield', 1, 'orange')
    	console.log(cat.name)  // Garfield
    	console.log(cat.age)  // 1
    	console.log(cat.color)  // orange
    	
    	// 使用 apply 实现继承:
    	var Dog = function (name, age, size) {
    	  Pet.apply(this, [name, age])
    	  this.size = size
    	}
    	当调用一个对象的方法时,方法中 this 指向的是对象本身,用call()改变方法的 this 值:
    	
    	var utils = {
    	  setName: function (name) {
    	    this.name = name
    	  }
    	}
    	// 使用 call 指定 setName 中的 this 指向自己
    	var Person = function (name) {
    	  utils.setName.call(this, name)
    	}
    	var p = new Person('John')
    	console.log(p.name)  // 'John'
    

    apply()
    apply()方法除了用来指定函数 this 值,还可以用来传递参数。例如,Math.max()允许传入多个参数,求它们的最大值,可以用apply()方法将数组元素作为参数传递给Math.max()方法:

    // 使用循环求最大值
    	var numbers = [1, 0, 0, 8, 6], max = -Infinity
    	for (var i = 0; i < numbers.length; i++) {
    	  max = Math.max(numbers[i], max)
    	}
    	
    	// 使用 apply 求最大值,代码更简洁
    	var numbers = [1, 0, 0, 8, 6]
    	max = Math.max.apply(null, numbers)
    	
    	// 使用 apply 给数组添加元素
    	var numbers = [1, 0, 0, 8, 6], arr = []
    	arr.push.apply(arr, numbers)
    

    另外,因为 JS 引擎有参数长度的限制,如果参数数组太长,可能会造成程序异常。所以,对于超长参数数组,应切分成更小的尺寸,分多次调用该方法。

    bind()
    在给setTimeout和setInterval传入函数时,函数中 this 指向的是全局 window 对象。使用bind()方法,重新指定 this 值:

    var Person = function (name) {
    	  this.name = name
    	}
    	Person.prototype.say = function () {
    	  setTimeout(function () {
    	    console.log('My name is ' + this.name)
    	  }.bind(this))
    	}
    	var p = new Person('John')
    	p.say()  // My name is John
    

    在给 Dom 对象添加监听函数时,监听函数作为 Dom 对象的一个方法,函数中 this 指向的是 Dom 对象。使用bind()方法,重新指定 this 值,使用箭头函数也可以达到同样的效果:

    var fakeDom = { a: 'fakeDom' }
    	var addEvent = function () {
    	  this.a = 'addEvent'
    	  fakeDom.onClick = function () {
    	    console.log(this.a)
    	  }
    	  fakeDom.onClickBind = function () {
    	    console.log(this.a)
    	  }.bind(this)
    	  fakeDom.onClickArrow = () => {
    	    console.log(this.a)
    	  }
    	}
    	addEvent()
    	fakeDom.onClick()  // 'fakeDom'
    	fakeDom.onClickBind()  // 'addEvent'
    	fakeDom.onClickArrow()  // 'addEvent'
    	使用bind()绑定参数后,新函数只需要传入剩余参数:
    	
    	var add = function (a, b) {
    	  return a + b
    	}
    	var add5 = add.bind(null, 5)
    	console.log(add5(3))  // 8
    
  8. css动画和js动画的区别

    JS动画
    缺点:
    (1)JavaScript在浏览器的主线程中运行,而主线程中还有其它需要运行的JavaScript脚本、样式计算、布局、绘制任务等,对其干扰导致线程可能出现阻塞,从而造成丢帧的情况。
    (2)代码的复杂度高于CSS动画
    优点:
    (1)JavaScript动画控制能力很强, 可以在动画播放过程中对动画进行控制:开始、暂停、回放、终止、取消都是可以做到的。
    (2)动画效果比css3动画丰富,有些动画效果,比如曲线运动,冲击闪烁,视差滚动效果,只有JavaScript动画才能完成
    (3)CSS3有兼容性问题,而JS大多时候没有兼容性问题

    CSS动画
    缺点:
    (1)运行过程控制较弱,无法附加事件绑定回调函数。CSS动画只能暂停,不能在动画中寻找一个特定的时间点,不能在半路反转动画,不能变换时间尺度,不能在特定的位置添加回调函数或是绑定回放事件,无进度报告
    (2)代码冗长。想用 CSS 实现稍微复杂一点动画,最后CSS代码都会变得非常笨重。
    优点:
    (1)浏览器可以对动画进行优化。
    浏览器使用与 requestAnimationFrame类似的机制,requestAnimationFrame比起setTimeout,setInterval设置动画的优势主要是:
    1)requestAnimationFrame会把每一帧中的所有DOM操作集中起来,在一次重绘或回流中就完成,并且重绘或回流的时间间隔紧紧跟随浏览器的刷新频率,一般来说,这个频率为每秒60帧。
    2)在隐藏或不可见的元素中requestAnimationFrame不会进行重绘或回流,这当然就意味着更少的的cpu,gpu和内存使用量。
    强制使用硬件加速 (通过 GPU 来提高动画性能)
    CSS动画流畅的原因
    渲染线程分为main thread(主线程)和compositor thread(合成器线程)。
    如果CSS动画只是改变transform和opacity,这时整个CSS动画得以在compositor thread完成(而JS动画则会在main thread执行,然后触发compositor进行下一步操作)
    在JS执行一些昂贵的任务时,main thread繁忙,CSS动画由于使用了compositor thread可以保持流畅

    在主线程中,维护了一棵Layer树(LayerTreeHost),管理了TiledLayer,在compositor thread,维护了同样一颗LayerTreeHostImpl,管理了LayerImpl,这两棵树的内容是拷贝关系。因此可以彼此不干扰,当Javascript在main thread操作LayerTreeHost的同时,compositor thread可以用LayerTreeHostImpl做渲染。当Javascript繁忙导致主线程卡住时,合成到屏幕的过程也是流畅的。
    为了实现防假死,鼠标键盘消息会被首先分发到compositor thread,然后再到main thread。这样,当main thread繁忙时,compositor thread还是能够响应一部分消息,例如,鼠标滚动时,加入main thread繁忙,compositor thread也会处理滚动消息,滚动已经被提交的页面部分(未被提交的部分将被刷白)。

CSS动画比JS流畅的前提:

  • JS在执行一些昂贵的任务

  • 同时CSS动画不触发layout或paint
    在CSS动画或JS动画触发了paint或layout时,需要main thread进行Layer树的重计算,这时CSS动画或JS动画都会阻塞后续操作。
    只有如下属性的修改才符合“仅触发Composite,不触发layout或paint”:

  • backface-visibility

  • opacity

  • perspective

  • perspective-origin

  • transfrom
    所以只有用上了3D加速或修改opacity时,css3动画的优势才会体现出来。

    (2)代码相对简单,性能调优方向固定

    (3)对于帧速表现不好的低版本浏览器,CSS3可以做到自然降级,而JS则需要撰写额外代码

  1. css选择器都有什么

    1、标签选择器,以标签名开头
    2、类选择器,给标签取class名,以 . 加class名开头,选择所有该class名的元素
    3、id选择器,给标签取id名,以#加id名开头,具有唯一性。
    4、子选择器,以>隔开父子级元素,(模块名>模块名,修饰>前模块内的子模块)
    5、包含选择器,以空格隔开包含关系的元素,(模块名 模块名,修饰空格前模块内所有该模块)
    6、兄弟选择器,以~隔开兄弟关系的元素(模块名~模块名 修饰~前模块往下的所有兄弟模块)
    7、相邻选择器,以+隔开相邻关系的元素(模块名+模块名 修饰加号前模块往下的相邻的模块 只一个)
    8、全局选择器,以*开头(星号标在大括号前,修饰了包含body所有的标签)
    9、群选择器,以分隔(逗号分隔开需要修饰的模块名)
    10、属性选择器,[] ([type=text]修饰属性为type=text的模块)
    在这里插入图片描述
    在这里插入图片描述
    11、伪类选择器
    (1) li:first-child{} (修饰第一个li)
    在这里插入图片描述
    (2) li:last-child{} (修饰最后一个li)
    在这里插入图片描述
    (3) li:nth-child{} (修饰第()个li)
    在这里插入图片描述
    (4) li:not(){} (不修饰第()个li,括号里面可以填以上的选择器)
    在这里插入图片描述

  2. css覆盖优先级

    内联>ID选择器>伪类=属性选择器=类选择器>元素选择器【p】>通用选择器(*)>继承的样式

  3. css实现loading效果 、js实现loading效果

    css实现loading效果
    在页面未加载完之前显示loading动画
    js实现的页面加载完毕之前loading提示效果

  4. HTML里的iframe

    iframe详解

  5. js中的双等号和三等号区别

    当进行双等号比较时候: 先检查两个操作数数据类型,如果相同, 则进行 === 比较, 如果不同, 则愿意为你进行一次类型转换, 转换成相同类型后再进行比较, 而 === 比较时, 如果类型不同,直接就是false.

  6. js判断和记录数组中出现次数最多的数据

    JS获取数组中出现次数最多及第二多元素的方法

    function f(arr){
      class num{
        constructor(value){
          this.value=value;
          this.index=1;
        }
        add(){
          this.index++;
        }
      }
      arr.sort();
      let temp=[];
      temp[0]=new num(arr[0]);
      for(let i=1;i<arr.length;i++){
        if(arr[i]==arr[i-1]){
          temp[temp.length-1].add();
        }else{
          temp.push(new num(arr[i]));
        }
      }
      temp.sort(function(a,b){
        return a.index<b.index;
      })
      let max=temp[0].index;
      let maxV=temp[0].value;
      let second=temp[1].index;
      let secondV=temp[1].value;
      return {max,maxV,second,secondV};
    }
    var arr=['a','b','a','b','a','c','d','d','d','d'];
    var {max,maxV,second,secondV}=f(arr);
    console.log(max,maxV,second,secondV);
    
  7. js统计字符串里出现最多的字符

    	var str = "nininihaoa";
    	var o = {};
    	for (var i = 0, length = str.length; i < length; i++) {
    		var char = str.charAt(i);
    		if (o[char]) {
    			o[char]++; //次数加1
    		} else {
    			o[char] = 1; //若第一次出现,次数记为1
    		}
    	}
    	console.log(o); //输出的是完整的对象,记录着每一个字符及其出现的次数
    	//遍历对象,找到出现次数最多的字符的次数
    	var max = 0;
    	for (var key in o) {
    		if (max < o[key]) {
    			max = o[key]; //max始终储存次数最大的那个
    		}
    	}
    	for (var key in o) {
    		if (o[key] == max) {
    			//console.log(key);
    			console.log("最多的字符是" + key);
    			console.log("出现的次数是" + max);
    		}
    	} 
    
  8. Js获取元素怎么操作

    js的dom元素操作

  9. js深拷贝、js克隆一个对象、嵌套拷贝,拷贝对象内的函数

    深入 js 深拷贝对象

  10. js数据去重

    JS数组去重的几种常见方法

  11. jQuery中prop和attr的用法和区别

  12. linux一些基本命令

  13. 浏览器的存储

  14. 你是怎么写css3动画的

  15. ES6模块化怎么写

    一、默认导入导出
    默认导出语法 export default 默认导出的成员,代码如下:

    // 当前模块 为 export1.js
    //定义私有成员 a 和 c
    let a = 10
    let c = 20 
    
    // 外界访问不到 变量 d 因为其没有被 暴露出去
    let d = 30
    function show(){}
    
    // 将 本模块中的私有成员 暴露出去,供其他模块使用
    export default  {
        a,
        c,
        show
    }
    

    默认导入语法 import 接收名称 from ‘模块接收符’,代码如下:

    // 导入模块成员
    import export1 from './export1.js'
    
    console.log(export1)
    
    //打印输出结果为 
    // { a: 10, c: 20, show: [function show] }
    

    二、按需导入与导出
    按需导出 export let a = 10,代码如下:

    // 当前模块 为 export1.js
    
    // 向外按需 导出 a
    export let a = 'aaa'
    // 向外按需 导出 b
    export let b = 'bbb'
    // 向外按需 导出方法 show
    export function say(){
     console.log('say')
    }
    

    按需导入 import { a1 } from '模块接收符’,代码如下:

    // 默认导入和按需导入同时使用
    // import export1,{ a, b, say } from './export1.js'
    
    // 导入模块成员
    import { a, b, say } from './export1.js'
    console.log(a) // 打印 输出 aaa
    console.log(b) // 打印 输出 bbb
    console.log(say) // 打印 输出 [Function: say]
    
  16. webpack配置文件都有什么

  17. 用过什么实现响应式布局,都有什么可以实现响应式布局

  18. js构造函数是什么,怎么写

  19. vue如何将数据渲染在html中

  20. vue如何渲染列表,如何判断是否渲染

  21. 前端图片优化

  22. css兼容性问题怎么解决

  23. 跨域问题如何解决

  24. form关闭自动完成怎么实现

  25. undefined和null转成number是什么

  26. 文本超出宽度显示省略号如何实现

  27. http请求头有哪些

  28. http请求上传文件使用哪种方式

  29. vue混入

  30. 优化首屏时间

  31. js防止多次提交

  32. VUE的this指向问题

  33. 盒模型

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值