前端常见面试题总结

159 阅读8分钟

1:vue响应式原理

Vue 的响应式原理是核心是通过 ES5 的保护对象的 Object.defindeProperty 中的访问器属性中的 get 和 set 方法,data 中声明的属性都被添加了访问器属性,当读取 data 中的数据时自动调用 get 方法,当修改 data 中的数据时,自动调用 set 方法,检测到数据的变化,会通知观察者 Wacher,观察者 Wacher自动触发重新render

当前组件(子组件不会重新渲染),生成新的虚拟 DOM 树,Vue 框架会遍历并对比新虚拟 DOM 树和旧虚拟 DOM 树中每个节点的差别,并记录下来,最后,加载操作,将所有记录的不同点,局部修改到真实 DOM 树上。 Object.defindProperty虽然能够实现双向绑定了,但是还是有缺点,只能对对象的属性进行数据劫持,所以会深度遍历整个对象,不管层级有多深,只要数组中嵌套有对象,就能监听到对象的数据变化无法监听到数组的变化,Proxy就没有这个问题,可以监听整个对象的数据变化,所以用vue3.0会用Proxy代替definedProperty。

2:http通信机制问题

这类问题可能会问你http是什么?通信的过程内容,下面具体来解答 http超文本传输协议(Hypertext TransferProtocol)的简写,是一套计算机通过网络进行通信的规则是一个设计来使客户端和服务器顺利进行通信的协议。http遵循请求(request)/应答(response)模型,web浏览器向web服务器发送请求,web服务器处理请求并返回适当的应答。 http内容类型含:html文档、gif格式图像、声音文件,还有独立的应用程序。

http通信机制是在一次完整的通信过程中,web浏览器和web服务器完成以下7个步骤: 1:建立tcp连接, 2:web浏览器像web服务器发出连接请求, 3:web服务器发送应答头信息, 4:服务器应答, 5:服务器发送应答信息, 6:服务器向浏览器发送数据, 7:关闭tcp连接

3:谈谈闭包

在一个函数中定义一个内部函数,并且这个内部函数引用了外部函数的作用域变量,将这个内部函数作为外部函数的返回值,这样就形成了闭包。如下例:

function a() {
    let name = "xiaoming"
    function b(){
        console.log("你好"+ name)
    }
    return b
}

适当使用闭包有利于模块化的开发,减少形参的个数,延长了形参的生命周期。不恰当的使用闭包会导致这些变量一直保存在内存当中,这样占用大量的内存,可能造成内存泄漏。

4:数组中的常用方法总结

Array.push(),Array.unshift()

这两种方法分别是在数组末尾和数组开头添加上新元素。

Array.pop(),Array.shift()

与上述相反,这两种方法分别是删除数组末尾和开头的元素。

Array.map()

该方法遍历数组为数组每一个元素提供一个函数方法,结果作为一个新数组返回,不会影响原来的数组。

let arr = [1, 2, 3, 4, 5]
let newArr = arr.map(x => x*2)
// arr= [1, 2, 3, 4, 5]  原数组保持不变
// newArr = [2, 4, 6, 8, 10] 返回新数组

Array.forEach()

该方法与map()方法类似,区别在于该方法没有返回值直接改变元素组。

Array.filter()

对数组内所有元素进行遍历筛选,将满足条件的元素作为一个新数组返回。

let arr=[1,2,3,4,5]
const selectNum =>num => num >3
let newArr = arr.filter(selectNum)
// newArr =[4,5] 返回新数组

Array.toString()和Array.join()

这两种方法都能够将数组转化为字符串,区别是join是可以指定连接字符

let arr =[1,2,3]
arr.join('#') // 1#2#3

Array.splice(开始位置, 删除的个数,元素)

该方法可以对数组进行增,删,改的操作

let arr=[1,2,3,4,5]
arr.splice(0, 0, 'wa') // ['wa', 1,2,3,4,5]
arr.splice(1,1) // [1,3,4,5]

Array.concat()

该方法可以将多个数组拼接成一个数组

let arr1=[1,2,3] arr2=[4,5]
let arr= arr1.concat(arr2) // [1,2,3,4,5]

Array.isArray()

判断一个对象是不是数组,返回一个布尔值

Array.reduce()

此方法是所有元素调用返回函数,返回值为最后结果,传入的值必须是函数类型:

let arr = [1, 2, 3, 4, 5]
const add = (a, b) => a + b
let sum = arr.reduce(add)
//sum = 15 相当于累加的效果

与之相对应的还有一个 Array.reduceRight() 方法,区别是这个是从右向左操作的

Array.some()

此方法是将所有元素进行判断返回一个布尔值,如果存在元素都满足判断条件,则返回true,若所有元素都不满足判断条件,则返回false

let arr= [1, 2, 3, 4, 5]
const isLessThan4 => value => value < 4
const isLessThan6 => value => value > 6
arr.some(isLessThan4 ) //true
arr.some(isLessThan6 ) //false

Array.every()

此方法是将所有元素进行判断返回一个布尔值,如果所有元素都满足判断条件,则返回true,否则为false:

let arr = [1, 2, 3, 4, 5]
const isLessThan4 => value => value < 4
const isLessThan6 => value => value < 6
arr.every(isLessThan4 ) //false
arr.every(isLessThan6 ) //true

5:this指向问题

this表示当前对象,如果在全局作用范围内使用this,则指代当前页面对象window;如果在函数中使用this,则this指代什么是根据运行时此函数在什么对象上被调用。 我们还可以使用apply和call两个全局方法来改变函数中this的具体指向。

// 定义一个全局函数
        function foo() {
            console.log(this.fruit);
        }
        // 定义一个全局变量,等价于window.fruit = "apple";
        var fruit = "apple";
        // 此时函数foo中this指向window对象
        // 这种调用方式和window.foo();是完全等价的
        foo();  // "apple"

        // 自定义一个对象,并将此对象的属性foo指向全局函数foo
        var pack = {
            fruit: "orange",
            foo: foo
        };
        // 此时函数foo中this指向window.pack对象
        pack.foo(); // "orange"

全局函数apply和call可以用来改变函数中this的指向,如下:

// 定义一个全局函数
        function foo() {
            console.log(this.fruit);
        }

        // 定义一个全局变量
        var fruit = "apple";
        // 自定义一个对象
        var pack = {
            fruit: "orange"
        };

        // 等价于window.foo();
        foo.apply(window);  // "apple"
        // 此时foo中的this === pack
        foo.apply(pack);    // "orange"

6:null和undefined的区别

null表示没有对象,即该处不应该有值,undefined表示缺少值,即此处应该有值,但没有定义

console.log(null==undefined);    //true  因为两者都默认转换成了false
console.log(typeof undefined);    //"undefined"  
console.log(typeof null);       //"object"  
console.log(null===undefined);    //false   "==="表示绝对相等,null和undefined类型是不一样的,所以输出“false”

null和undefined转换成number数据类型

null 默认转成 0

undefined 默认转成 NaN

7:浏览器本地储存问题

Web Storage包括了两种存储方式:localStorage。 sessionStorage不是一种持久化的本地存储,仅仅是会话级别的存储。

web storage和cookie的区别

cookie相似,区别是它是为了更大容量存储设计的。Cookie都会被发送过去,这样无形中浪费了带宽,另外 除此之外,setItem,getItem,removeItem,clear等方法,不像setCookie,getCookie。 但是Cookie的作用是与服务器进行交互,作为Web Storage仅仅是为了在本地“存储”数据而生 浏览器的支持除了UserData其实就是web storage。
sessionStorage都具有相同的操作方法,例如removeItem等

8:display:none和visibility:hidden的区别

display:none 隐藏对应的元素,在文档布局中不再给它分配空间,它各边的元素会合拢,

visibility:hidden 隐藏对应的元素,但是在文档布局中仍保留原来的空间。

9:vue-router query和params区别

this.$router.push({path: '/home/sort/detail',query:{id: 'abc'}}) 获取参数 {{this.$route.query.userId}}

this.$router.push({name: 'detail',params:{id: 'abc'}}) 获取参数 {{this.$route.params.userId}}

query要用path来引入,params要用name来引入,接收参数都是类似的,分别是this.route.query.userId和this.route.params.userId。

query更加类似于我们ajax中get传参,params则类似于post,说的再简单一点,前者在浏览器地址栏中显示参数,后者则不显示.

10.从输入url到页面加载完成发生了什么?——前端角度

1: 浏览器查找是否存在缓存记录存在的话显示缓存网页内容

2:DNS解析URL对应的IP。

3:根据IP建立TCP连接(三次握手)。

4:HTTP发起请求。

5:服务器处理请求,浏览器接收HTTP响应。

6:渲染页面,构建DOM树。

7:关闭TCP连接(四次挥手)

11.模板字符串

就是这种形式varible,在以往的时候我们在连接字符串和变量的时候需要使用这种方string+varible+string但是有了模版语言后我们可以使用string{varible},在以往的时候我们在连接字符串和变量的时候需要使用这种方式'string' + varible + 'string'但是有了模版语言后我们可以使用string{varible}string这种进行连接。基本用途有如下:

//es5 
var name = 'lux';
console.log('hello' + name);
//es6
const name = 'lux';
console.log(`hello ${name}`); //hello lux

12.画一条0.5px的直线

height: 1px;
transform: scale(0.5);

13.css可继承属性和不可继承属性

可继承的属性:font-size, font-family, color

不可继承的样式:border, padding, margin, width, height

14.webpack的一些常见面试题

1:什么是webpack

webpack是一个静态的模块打包器,会根据模块的依赖关系进行静态分析,然后将模块按照指定规则生成对应的静态资源。

2:webpack的核心概念

Entry: 入口点,指定哪个文件或哪几个文件来作为打包的入口文件。

Output: 出口点,可设置打包完成后的输出文件的位置和输出文件名。

Loader: Loader能够将所有模块文件类型处理成webpack能够识别的有效模块,相当于一个转化器功能

Plugin: 插件功能,可以扩展webpack的功能,当loader不能满足需求时,就需要Plugin来处理了。

总结了一些最近面试遇到的一些面试题,写的不对或者不完善的地方欢迎指出虚心学习。