龙空技术网

万字长文系列:Web前端百度面经(含答案)第三章

码农登陆 107

前言:

而今看官们对“web前端开发设计储久良课后答案”大体比较讲究,姐妹们都想要知道一些“web前端开发设计储久良课后答案”的相关文章。那么小编也在网摘上搜集了一些对于“web前端开发设计储久良课后答案””的相关知识,希望你们能喜欢,朋友们快快来了解一下吧!

前言

全系列分为四个章节,分别是电话面试部分、一面部分、二面部分、三面部分。全系列不光有题目还有详细答案,收藏转发就完事了!

第一章:电话面试部分已经放出万字长文系列:Web前端百度面经(含答案)第一章

以及第二章:一面部分万字长文系列:Web前端百度面经(含答案)第二章

希望这个系列能够助力大家找到好的工作,年年一帆风顺!!

接下来,长文预警~大家有所心理准备

正文

题目:结合页面加载流程流程详细说下过程中的性能优化

这个问题就比较细节化,可以参考我之前写过的关于性能优化的文章,基本的优化方案里边都有,Web前端性能优化:html、css、js篇

这个问题回答期间面试官追问了一些具体的小细节问题,这里就不再给出了,文章中基本都包含了,这里就不展开篇幅讲了

这种笼统的大方向问题建议条理化回答,可以按照自己习惯的或者固定的方面去展开讲,否则这种大问题东一句西一句的容易让面试不耐烦,越条理越好,我自己当时是按照HTML、CSS、JS、网络通信,页面加载的顺序去说的,过程中面试官一直在记录,估计是看有没有说到他想要的那些点。

追问:开发过程中碰到过什么棘手的性能方面的问题么

这个问题当时都是回答的之前在开发过程中确实碰到的,感恩自己当时有心做了总结,总结请点击记一次惨痛的Vue-cli + VueX + SSR经历

这期间穿插着问了一点node,webpack的小知识点

题目:继承的方式有哪些

提供个父类进行继承

function SuperType(name) {    this.name = name;    this.sexy = ["man", "woman", "unknow"];    this.showName = function() {        console.log(name);    };};SuperType.prototype.age = 18;

原型继承

利用原型让一个引用类型继承另外一个引用类型的属性和方法重点:新实例的原型等于父类的实例特点: 1.实例可继承的属性有:实例的构造函数的属性,父类构造函数属性,父类原型的属性。(新实例不会继承父类实例的属性!) 2.基于原型链,既是父类的实例,也是子类的实例缺点: 1.无法实现多继承 2.所有新实例都会共享父类实例的属性

function SubType() {    this.name = 'coder';}SubType.prototype = new SuperType();var subFun = new SubType();console.log(subFun.age) // 18console.log('outer', subFun instanceof SuperType) // true 

构造函数继承

重点:用call()和apply()将父类构造函数引入子类函数(在子类函数中做了父类函数的自执行(复制))特点: 1、只继承了父类构造函数的属性,没有继承父类原型的属性。 2、解决了原型链继承缺点1、2、3。 3、可以继承多个构造函数属性(call多个)。 4、在子实例中可向父实例传参。缺点: 1、只能继承父类构造函数的属性。 2、无法实现构造函数的复用。(每次用每次都要重新调用) 3、每个新实例都有父类构造函数的副本,臃肿。

function SubType() {    SuperType.call(this);}let instance1 = new SubType();instance1.sexy.push("all");console.log(instance1.sexy); // ["man", "woman", "unknow", "all"]let instance2 = new SubType();console.log(instance2.sexy); // ["man", "woman", "unknow"]

组合继承

特点:利用原型链继承父类的原型属性和方法,利用构造函数继承实例属性和方法缺点:调用了两次父类构造函数,生成了俩实例

function SubType(name) {    SuperType.call(this, name);}SubType.prototype = new SuperType();var instance3 = new SubType("newCoder");console.log(instance3.name) // newcoder

使用 ES6 extends 进行继承

class A {    constructor(name, age) {        this.name = name;        this.age = age;    }    getName() {        return this.name;    }}class B extends A {    constructor(name, age) {        super(name, age);        this.job = "IT";    }    getJob() {        return this.job;    }    getNameAndJob() {        return super.getName() + this.job;    }}var b = new B("Tom", 20);console.log(b.name); // Tomconsole.log(b.age); // 20console.log(b.getName()); // Tomconsole.log(b.getJob()); // ITconsole.log(b.getNameAndJob()); // TomIT

追问:new 的原理

在调用 new 的过程中会发生以下四件事: 新生成一个对象 将构造函数的作用域赋值给新对象(即绑定新对象的 this) 执行构造函数中的代码(即为这个新对象添加属性) 返回新对象一个简版的new

function _new() {	// 创建一个新对象    let newObj = {};      // 获取构造函数    let Constructor = Array.prototype.shift.call(arguments);    // 连接新对象原型,新对象可以访问原型中的属性    newObj.__proto__ = Constructor.prototype;    // 执行构造函数,即绑定 this,并且为这个新对象添加属性    Constructor.apply(newObj, arguments);    // 返回该对象    return newObj;}

追问:ES6 extends 的原理

这个问题当时回答的不好,很多关键点没有说出来,面试官也是很友好地帮我答疑解惑

ES6 中是通过 class 关键字去定义类,经过 bable 编码之后其实还是通过构造函数去实现的,但是为了规范类的使用,ES6中是不允许直接调用 class 创建的类,因为编码之后会产生一个 _classCallCheck 阻止你直接调用,会抛出错误继承过程其实归根结底也是类似原型继承,过程请看下图

首先 subClass.prototype.__proto__ = superClass.prototype 保证了 Child 的实例可以访问到父类的属性,包括内部属性,以及原型属性。其次,subClass.__proto__ = superClass,保证了Child.height 也能访问到,也就是静态方法。

题目:ES6 和 ES5

基础的问题我就不展开说了,面试过程中涉及到的我列出来,很多基本的大家开发中肯定都已经很熟悉了

let 和 const解构赋值箭头函数模板字符串for...of 循环展开运算符...Class 类extends继承Modules

题目:闭包的原理和优劣以及使用

闭包产生的原因

JS中存在全局作用域和函数作用域,当访问一个变量时,解释器会首先在当前作用域查找,如果没有找到,就去父作用域找,直到找到该变量或者不在父作用域中(也是作用域链的概念)作用域中的每个子函数都会拷贝上级的作用域,形成一个完整的作用域链条当前作用域中的变量存在着指向父级作用域的引用,便产生了闭包,下面用一段代码说明

// JS的变量逐级查找var a = 1;function f1() {	// f1() 的作用域指向全局作用域(window)和它本身	var a = 2	function f2() {		// f2的作用域指向全局作用域(window)、f1的作用域和它本身		var a = 3;		console.log(a);//3	}}// fun会拿到父级作用域中的变量,输出2。// 因为在当前环境中,含有对f2的引用 ,f2恰恰引用了window、f1和f2的作用域, // 因此f2可以访问到f1的作用域的变量function f1() {	var a = 2	function f2() {		console.log(a); // 2	}	return f2;}var fun = f1();fun();

闭包的表现形式

返回一个函数作为函数参数传递在定时器、事件监听、Ajax请求、跨窗口通信、Web Workers或者任何异步中,只要使用了回调函数,实际上就是在使用闭包立即执行函数表达式 保存了全局作用域和当前作用域,实际也是闭包

闭包的优劣

优点 可以读取函数内部的变量 可以让这些局部变量保存在内存中,实现变量数据共享。缺点 由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题 闭包会在父函数外部,改变父函数内部变量的值。

闭包的使用

匿名自执行函数,因为外部无法引用其内部的变量,使用完会立即释放进行结果缓存进行封装工厂函数实现类的继承函数柯里化

题目:this 的指向问题

记住一点:this最终指向调用它的对象 通俗解释:JS中存在上下文环境window或者函数,当执行的属于window时,则取的window的上下文环境,如果执行的属于函数,则取函数的上下文,this是堆栈的指针,堆栈里有什么就返回什么具体分析 如果是一般函数,this指向全局对象window 在严格模式下"use strict",为undefined 对象的方法里调用,this指向调用该方法的对象 构造函数里的this,指向创建出来的实例 () => console.log(this) 里面 this 跟外面的 this 的值一模一样 事件监听的时候,this是监听元素,setTimeout的函数内this是window(非严格模式下)

// 测试题var app = {  fn1: function () {    console.log(this)  },  fn2: function(){    return function() {      console.log(this)    }  },  fn3: function() {    function fn() {      console.log(this)    }    return fn()  },  fn4: function() {    return {      fn: function () {        console.log(this)      }    }  },  fn5: function() {    setTimeout(function () {      console.log(this)    },10)   },  fn6: function() {    setTimeout( () => {      console.log(this)    },20)   },  fn7: function() {    setTimeout(function () {      console.log(this)    }.bind(this),30)   },  fn8: () => {    setTimeout( () => {      console.log(this)    },40)   }}app.fn1() // appapp.fn2()() // windowapp.fn3() // windowapp.fn4().fn() // fnapp.fn5() // windowapp.fn6() // appapp.fn7() // appapp.fn8() // window

题目:VUE 的生命周期

vue 生命周期流程图(图片来自网络,侵联删)

创建实例,new Vue() 的过程中,首先执行 init()init() 过程首先是执行 beforeCreate ,初始化data、 props、 watch、computed,这些执行都是在 beforeCreate 阶段和 create 阶段,也是创建响应式数据的阶段,这个阶段不要去修改数据create 阶段结束,会去判断实例中有无 el option 选项,如果没有会执行 $mount(), 如果有,直接执行下一步判断 template, 若有,会把 template 打成一个个 render function ,其中的传参h就是vue.createElement, 参数为 标签,对象(可以是props或事件),内容render函数发生在 beforemounted 和 mounted 之间,所以当 beforeMount 时,$el 还只是HTML上的节点,mounted 时才把渲染的内容挂载到 DOM 上,实际就是执行了 renderfunctionbeforeMount 有了 renderfunction 才执行,执行完执行 mount , mounted 执行完,整个生命周期中主动执行的函数就已经完毕,剩下的比如 beforeUpdata、updata、beforDestory、destory 需要外部触发

题目:VUE computed原理

设置 computed 的 getter ,若执行了 computed 的函数,会去读取 data 值,就会触发 data 的 getter ,从而建立data的依赖关系首次mounted的值,会执行vm.computed对应的getter,没有getter的是赋值函数若computed的属性值依赖其他属性值,会将target暂存在栈中,先进行其他的依赖收集

题目:VUE watch流程

创建实例时会去处理watch,这点在前面生命周期中已经提到遍历数据keys去创建监听给监听注册回调(多种处理方式) name:{ handle(){} } 传入为对象去handler字段 name(){} 传入为函数直接监听回调 name: 'getName' 传入为字符串就去实例上获取回调调用vm.$watch 判断是否立即执行回调 每个watch配发watcher(监听的key,callback,options)监听的数据变化时,通知watch-watcher更新,然后使用updata()更新数据

题目:VUE 响应式数据处理流程

init()时,利用object.defineproperty监听vue实例的响应式数据变化从而实现数据的劫持,其实是利用了数据的setter和getter当render function被渲染时,读取实例中与视图相关的响应式数据,从而触发getter进行依赖收集正常的渲染和更新数据变化时,触发setter,通知依赖收集中和视图相关的watcher,告知重新渲染视图,watcher再次通过updata渲染视图

题目:特定状态下浏览器的兼容性

这个问题想必前端开发中大家都碰到过很多奇奇怪怪的兼容性问题,我也没有回答地特别细致,说了几个日常开发中碰到过的,面试官结合实际情况问了几个,具体问的已经记不清了,JS的也有,CSS的也有,IE的那些低版本的兼容性问题个人觉得不说也罢,毕竟用户量少的又少。

尾声

接下来就要迎来咱们系列的“大结局”,最后一篇终面部分啦。觉得系列不错的记得点赞、收藏、分享哦~让更多前端er,看到有用的文章~

标签: #web前端开发设计储久良课后答案