面试时记录的部分问题
1、vue生命周期?
beforeCreate(创建前):el 和 data 并未初始化,因此无法访问methods, data, computed等上的方法和数据。
created(创建后):完成了data 数据的初始化,el没有
beforeMount(挂载前):编译模板,把data里面的数据和模板生成html,完成了el和data 初始化,注意此时还没有挂载html到页面上。
mounted(挂载后):挂载完成,也就是模板中的HTML渲染到HTML页面中,此时一般可以做一些ajax操作,mounted只会执行一次。
beforeUpdate(更新前):在数据更新之前被调用,发生在虚拟DOM重新渲染和打补丁之前,可以在该钩子中进一步地更改状态,不会触发附加地重渲染过程;
updated(更新后):件DOM已经更新,所以可以执行依赖于DOM的操作
beforeDestroy(销毁前):这一步还可以用this来获取实例,一般在这一步做一些重置的操作,比如清除掉组件中的定时器 和 监听的dom事件。
destroyed(销毁后):在实例销毁之后调用,调用后,所以的事件监听器会被移出,所有的子实例也会被销毁,该钩子在服务器端渲染期间不被调用。
2、vue双向绑定原理?
采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应监听回调。当把一个普通 Javascript 对象传给 Vue 实例来作为它的 data 选项时,Vue 将遍历它的属性,用 Object.defineProperty 将它们转为 getter/setter。用户看不到 getter/setter,但是在内部它们让 Vue 追踪依赖,在属性被访问和修改时通知变化。
vue的数据双向绑定 将MVVM作为数据绑定的入口,整合Observer,Compile和Watcher三者,通过Observer来监听自己的model的数据变化,通过Compile来解析编译模板指令(vue中是用来解析 {{}}),最终利用watcher搭起observer和Compile之间的通信桥梁,达到数据变化 —>视图更新;视图交互变化(input)—>数据model变更双向绑定效果。
js实现的简单的双向绑定3、热更新原理
浏览器和服务器保持长连接。 服务器就可以直接通知到客户端了。服务器和浏览器通过 websocket 建立链接。服务器和浏览器规定好消息的规则,是刷新页面还是更新 css。
4、SSR的优缺点
ssr是Server-Side Rendering的简写,即由服务端负责渲染页面直出,亦即同构应用。程序的大部分代码都可以在服务端和客户端运行。在服务端vue组件渲染为html字符串,在客户端生成dom和操作dom。
优点:1、更好的SEO。2、更快的内容到达时间(首屏加载更快)。服务端返回的内容是具有信息内容的html文档,这对搜索引擎的爬虫是友好的。用户在弱网情况下也无需等待js加载完成才能开始渲染页面,可以更加快速的看到完整的内容。
缺点:1、更多的开发条件限制。例如服务端渲染只支持beforCreate和created两个钩子函数,这会导致一些外部扩展库需要特殊处理,才能在服务端渲染应用程序中运行;并且与可以部署在任何静态文件服务器上的完全静态单页面应用程序(SPA)不同,服务端渲染应用程序,需要处于Node.js server运行环境。2、更多的服务器负载。ssr项目在node中渲染页面显然要比大部分动态网站要消耗更多的cpu资源,如果项目是需要在高流量环境中使用,则需要准备更多的服务器负载和更好的缓存策略。
5、v-html和v-text区别
v-text展示效果: <strong>Hello</strong> Vue!
v-html展示效果:Hello Vue!
v-text和{{}}表达式渲染数据,不解析标签。v-html不仅可以渲染数据,而且可以解析标签。
6、v-html有什么弊端?解决办法?
弊端:动态渲染的任意 HTML 可能会非常危险,因为它很容易导致 XSS 攻击。请只对可信内容使用 HTML 插值,绝不要对用户提供的内容插值。
办法:使用 <pre> 标签替换掉 <div> 标签。 利用的就是 <pre> 标签的这个功能:被包围在 <pre> 元素中的文本通常会保留空格和换行符,并且文本也会呈现为等宽字体。注意:pre标签使用的时候会出现不自动换行的问题,而且存在一些默认样式。解决办法:white-space: pre-wrap; /* css-3 */white-space: -moz-pre-wrap; /* Mozilla, since 1999 */white-space: -pre-wrap; /* Opera 4-6 */white-space: -o-pre-wrap; /* Opera 7 */word-wrap: break-word; /* Internet Explorer 5.5+ */
7、vue有哪些指令?
v-on,v-model,v-if,v-else,v-show,v-for,v-bind,v-once(只会渲染一次,值改变也不会重新渲染),v-html,v-text,v-pre, v-cloak.
8、watch函数
watch: {
// 如果 `question` 发生改变,这个函数就会运行
question: function(newQuestion, oldQuestion){
this.answer = 'Waiting for you to stop typing...' this.debouncedGetAnswer()
}
9、vue的监听事件
v-on 可以用 v-on 指令监听 DOM 事件,并在触发时运行一些 JavaScript 代码。Vue.js 为 v-on 提供了事件修饰符.
.stop:等同于JavaScript中的event.stopPropagation(),阻止冒泡(通俗讲就是阻止事件向上级DOM元素传递)
.prevent:等同于JavaScript中的event.preventDefault(), 默认事件指对DOM的操作会引起自动执行的动作,比如点击超链接的时候会进行页面的跳转,点击表单提交按钮时会重新加载页面等,使用".prevent"修饰符可以阻止这些事件的发生。
.capture:与事件冒泡的方向相反,事件捕获由外到内
.self:只会触发自己范围内的事件,不包含子元素
.once:只会触发一次
js篇
1、怎么判断一个数据是不是数组
var arr = [1,2,3]
1.instanceof Array console.log(arr instanceof Array) //true
2.Object.prototype.toString.call() console.log(Object.prototype.toString.call(arr)) //[object Array]
3.Array.isArray() console.log(Array.isArray(arr)) //true
4.条件判断
function isArrayLike(o) {
if (o && // o is not null, undefined, etc.
typeof o === 'object' && // o is an object
isFinite(o.length) && // o.length is a finite number
o.length >= 0 && // o.length is non-negative
o.length===Math.floor(o.length) && // o.length is an integer
o.length < 4294967296) // o.length < 2^32
return true; // Then o is array-like
else
return false; // Otherwise it is not
}
2、数组去重的几种方法,最快的
1、简单的去重方法:新建一新数组,遍历传入数组,值不在新数组就push进该新数组中。
2、对象键值法去重:速度最快, 占空间最多(空间换时间),该方法执行的速度比其他任何方法都快, 就是占用的内存大一些。 实现思路:新建一js对象以及新数组,遍历传入数组时,判断值是否为js对象的键,不是的话给对象新增该键并放入新数组。 注意点:判断是否为js对象键时,会自动对传入的键执行“toString()”,不同的键可能会被误认为一样,例如n[val]-- n[1]、n["1"];解决上述问题还是得调用“indexOf”。*/
3、排序后相邻去除法:给传入数组排序,排序后相同值相邻,然后遍历时,新数组只加入不与前一值重复的值。 会打乱原来数组的顺序。
4、数组下标法:还是得调用“indexOf”性能跟方法1差不多, 实现思路:如果当前数组的第i项在当前数组中第一次出现的位置不是i,那么表示第i项是重复的,忽略掉。否则存入结果数组。
5、优化遍历数组法:思路:获取没重复的最右一值放入新数组/** 推荐的方法,实现思路:获取没重复的最右一值放入新数组。(检测到有重复值时终止当前循环同时进入顶层循环的下一轮判断。
3、排序的几种方法
1、js语法糖 sort()排序。原理就是冒泡排序。
2、冒泡排序:思路:原始好懂,两层循环,比后面的大交换位置。
3、选择排序:思路:找到数据结构中的最小值并将其放置在第一位,接着找到第二小的值并将其放在第二位,以此类推。改排序算法不稳定会破坏原始序列。
4、快速排序:思路:找到一个中间的数,然后把所有比这个数小的放到这个数前面,把所有比这个数大的放到后面,这样完成一趟,依次对前面一段数据和后面一段数据进行前面步骤的递归。
5、插入:思路:将一系列无序的元素,往一个有序的元素序列里面插入,形成一个有序的序列。插入的时候,将无序的元素序列中每个元素依次和有序的数组最后一个元素开始比较,如果比该元素小,则和该元素交换位置,依次比较,找到一个最合适的位置,即比前一个元素大,比后一个元素小。
4、js中类的继承
1、call方法方式 call方法是Function类中的方法,call方法的第一个参数的值赋值给类(即方法)中出现的this,call方法的第二个参数开始依次赋值给类(即方法)所接受的参数。在children类中写:Parent.call(this,username);
2、apply方法方式 apply方法接受2个参数,A、第一个参数与call方法的第一个参数一样,即赋值给类(即方法)中出现的this;B、第二个参数为数组类型,这个数组中的每个元素依次赋值给类(即方法)所接受的参数。在children方法(类中)Parent.apply(this,new Array(username));
3、原型链方式 子类通过prototype将所有在父类中通过prototype追加的属性和方法都追加到Child,从而实现了继承。Child.prototype = new Parent();//这行的作用是:将Parent中将所有通过prototype追加的属性和方法都追加到Child,从而实现了继承。Child.prototype.world = "world";
4、混合方式 混合了call方式、原型链方式。Child.prototype = newParent();//将父类的方法继承过来
Child.prototype.sayWorld = function(){//新增一些方法
alert(this.world);
}
5、对象冒充 在children方法中写: this.method = Parent; this.method(username);//最关键的一行 delete this.method;
5、js中有哪些数据类型
JS有7种数据类型:三种基本类型(数字,字符串,布尔),两种引用数据类型(对象,数组),两种特殊数据类型(undefined,null)。JS有5种原始类型:数字,字符串,布尔,undefined,null。
typeof 运算符就是检测变量或值的数据类型。
6、js深拷贝和浅拷贝区别,实现深拷贝
深拷贝在于引用类型的时候,浅拷贝只复制地址值,实际上还是指向同一堆内存中的数据,深拷贝则是重新创建了一个相同的数据,二者指向的堆内存的地址值是不同的。这个时候修改赋值前的变量数据不会影响赋值后的变量。
1、使用递归的方式实现深拷贝
递归实现2、通过json的方式实现(无法实现对对象中方法的深拷贝);
JSON实现3、Object.assign()拷贝(当对象中只有一级属性,没有二级属性的时候,此方法为深拷贝,但是对象中有对象的时候,此方法,在二级属性以后就是浅拷贝。)
4、通过Object.create()实现
Object.create实现7、es6新特性
1、定义变量,let和const(常量,不能改变)。
2、字符串模板。反引号和${}配合使用。$("body").html(`hello,my name is ${name}, ${seatNumber}.`);
3、箭头函数。箭头函数最直观的三个特点。不需要 function 关键字来创建函数;省略 return 关键字;继承当前上下文的 this 关键字;
箭头函数对比4、函数的默认参数值。
5、Spread / Rest 操作符。Spread / Rest 操作符指的是 ...,具体是 Spread 还是 Rest 需要看上下文语境。
spread和rest6、对象和数组解构
解构7、对象超类。ES6 允许在对象中使用 super 方法:
对象超类8、for...of 和 for...in
循环9、ES6中的类。ES6 中支持 class 语法,不过,ES6的class不是新的对象继承模型,它只是原型链的语法糖表现形式。extends 允许一个子类继承父类,需要注意的是,子类的constructor 函数中需要执行 super() 函数。当然,你也可以在子类方法中调用父类的方法,如super.parentMethodName()。有几点值得注意的是:类的声明不会提升(hoisting),如果你要使用某个 Class,那你必须在使用之前定义它,否则会抛出一个 ReferenceError 的错误在类中定义函数不需要使用 function 关键词
函数中使用 static 关键词定义构造函数的的方法和属性: 类中的继承和超集8、什么是事件冒泡,事件捕获和事件委托
事件冒泡:事件冒泡是指事件会从最内层的元素开始发生,一直向外传播。比如点击一个P标签,click事件发生的顺序是:p -> div -> body -> html -> document。
事件捕获:事件捕获是指事件会从开始发生,直到最具体的元素。比如点击一个P标签,click事件发生的顺序是:document -> html -> body -> div -> p
事件委托:事件委托是指将事件绑定在父元素上,然后采用事件冒泡的方法,当事件流达到父元素时,可以通过target获取真正触发的当前元素,并执行绑定在父元素上的方法。这样做可以省去一个个给子元素绑定事件。一般的步骤是:确定需要监听时间的父元素,给父元素添加addEventListener('event', function),通过父元素.target获取实际被操作的元素,在函数中进行处理。
9、不用loop循环,创建一个100的数组,并且每个值等于它的下标
ES5:Object.keys(Array.from({length:100}));
ES6:Array.from(Array(100).keys());
10、哪些操作会造成内存泄露
常见的4中内存泄漏:意外的全局变量,被遗忘的定时器或者回调,没有清理的DOM元素引用,闭包。
http和https
HTTP协议是一种使用明文数据传输的网络协议。HTTPS协议可以理解为HTTP协议的升级,就是在HTTP的基础上增加了数据加密。
数据加密传输,是HTTP和HTTPS之间的本质性区别,其实除了这个之外,HTTPS网站和HTTP网站还有一个很重要的区别,就是对搜索排名的提升,这也是很多站长所关注的地方。当你使用Chrome浏览器访问一个HTTP网站的时候,你会发现浏览器会对该HTTP网站显示“不安全”的安全警告,提示用户当前所访问的网站可能会存在风险。
localStorage和sessionStorage区别
localStorage生命周期是永久,这意味着除非用户显示在浏览器提供的UI上清除localStorage信息,否则这些信息将永远存在。删除localStorage中存储信息的方法:localStorage.removeItem("key");//删除名称为“key”的信息。localStorage.clear();//清空localStorage中所有信息
sessionStorage生命周期为当前窗口或标签页,一旦窗口或标签页被永久关闭了,那么所有通过sessionStorage存储的数据也就被清空了。
CSS篇
css选择器有哪些,选择器的权重的优先级
选择器类型:1、ID #id;2、class .class;3、标签 p;4、通用 *;5、属性 [type="text"];6、伪类 :hover;7、伪元素 ::first-line;8、子选择器、相邻选择器。
权重计算规则:1、第一等:代表内联样式,如: style=””,权值为1000。2、第二等:代表ID选择器,如:#content,权值为0100。3、第三等:代表类,伪类和属性选择器,如.content,权值为0010。4、第四等:代表类型选择器和伪元素选择器,如div p,权值为0001。5、通配符、子选择器、相邻选择器等的。如*、>、+,权值为0000。6、继承的样式没有权值。
总结:内联>ID>class>标签,伪元素>通配符>继承.
css中常用的伪类
超链接的几种::link 用这个可以设置未被访问的链接的样式;:visited 用这个设置已经被访问的链接的样式;:hover 用于设置将鼠标悬浮在链接上的样式;:active 用于设置鼠标点击链接时到鼠标松开时的样式;:focus 用于设置用键盘将焦点放在链接上时的样式(如用tab键或者上下键来移动页面焦点时)。
列表元素的i的几种伪类::first-child 选中列表中的第一个元素;:last-child 选中列表中的最后一个元素;:nth-child() 括号里面的取值可以为三类:1)数字 :nth-child(3)表示选中父元素的第三个子元素 2)自变量为n的表达式 :nth-child(3n)代表选中父元素的第3,6,9.....3n的子类; 3)even或者odd 分别代表选中父元素的奇数或者偶数个子元素:nth-last-child() 与 :nth-child()的不同点在于,这个是从最后一个元素开始计算,取值都是一样的。
display:none和visibility:hidden的区别?
dispaly:none 设置该属性后,该元素下的元素都会隐藏,占据的空间消失。
visibility:hidden 设置该元素后,元素虽然不可见了,但是依然占据空间的位置。
1.visibility具有继承性,其子元素也会继承此属性,若设置visibility:visible,则子元素会显示
2.visibility不会影响计数器的计算,虽然隐藏掉了,但是计数器依然继续运行着。
3.在css3的transition中支持visibility属性,但是不支持display,因为transition可以延迟执行,因此配合visibility使用纯css实现hover延时显示效果可以提高用户体验
4. display:none会引起回流(重排)和重绘 visibility:hidden会引起重绘
介绍下position
static 默认值 元素是静止的,没有开启定位。
relative 开启元素的相对定位,1.如果不设置偏移量,元素不会发生任何变化。2.相对定位参照元素在文档中的位置进行定位。3.相对定位会提升元素的层级。4.相对定位不会使元素脱离文档流。5.相对定位不会改变元素性质。
absolute 开启元素的绝对定位,脱离文档流。1.如果不设置偏移量,元素的位置不会发生变化。2.元素会从文档流中脱离。3.绝对定位会改变元素的性质,行内元素变成块元素,块的宽度被内容撑开。4.绝对定位会使元素提升一个层级。5.绝对定位元素是相对于包含块进行定位的。
fixed 开启元素的固定定位,脱离文档流。绝大部分跟相对定位相同。唯一不同的是参照浏览器视口,不会随滚动条滚动改变。
inherit 规定应该从父元素继承 position 属性的值。
做移动端和PC的时候有什么区别
1、PC考虑的是浏览器的兼容性,移动端更多的是考虑手机分辨率的适配。
2、事件处理的时候移动端缺少的是hover事件,包括蒜素hover的样式,鼠标的形状,有时还要处理键盘事件。
3、在布局上,移动端开发一般是要做到布局自适应的,我使用的一直是rem布局,感觉很好。
4、需要考虑网络的问题,引入的资源或者插件,能小则小,一个30k的资源和一个80k的资源,在移动端的差别还是挺大的。
5、性能优化,包括首屏的打开速度、用户响应延迟、渲染性能、动画帧率等在手机上都需要特别注意。
css预处理器有什么好处?
css预处理器有sass,scss,less。我是使用的scss,这里就以scss为例。css预处理器比多出好些功能(如变量($+变量名+:+变量值)、嵌套、运算,混入(Mixin)、继承(@extend)、函数等),更容易阅读。