赞
踩
闭包是什么:JS中内层函数可以访问外层函数的变量,外层函数无法操作内存函数的变量的特性。我们把这个特性称作闭包。
闭包的好处:
闭包的弊端:内层函数引用外层函数变量,内层函数占用内存。如果不释放内存,过多时,易引起内存泄露。
解决办法:无法自动销户,就及时手动回收,使用后将函数的引用赋null。
1、深拷贝与浅拷贝的区别?
拷贝的层级不同,深拷贝是指每一层数据的改动都不会影响原对象和新对象,浅拷贝只有第一层的属性变动不互相影响,深层的数据变动还会互相影响。
2、实现拷贝的方法有哪些?
浅拷贝:数组可以用拓展运算符[...arr],或者slice().浅拷贝对象可以用Object.assign({},obj)
深拷贝:JSON.parse(JSON.stringify(obj)),或封装递归方法,或使用第三方库的方法,比如 JQuery的$.extend({},obj),或者lodash 的cloneDeep
3、JSON.parse(JSON.stringify(obj))处理的缺点?
constructor
;判断空对象
区分数据类型
- let a = [1,2]
- Object.prototype.toString.call(a) // '[object Array]'
call 和 apply 都是可以改变this 指向的问题, call 方法中传递参数要求一个 一个传递参数。 但是apply 方法要求传递参数是一个数组形式。
- let a = {
- name: 'sunq',
- fn:function(action){
- console.log(this.name + ' love ' + action);
- }
- }
- let b = {name:'sunLi'}
-
- // 正常的this指向
- a.fn('basketball'); // sunq love basketball
- // 改变this指向,并体现call与apply的区别
- a.fn.apply(b,['football']); // sunLi love football
- a.fn.call(b,'football'); // sunLi love football
还是上面的示例,bind也可以实现call和apply的效果。bind的不同之处在于bind会返回一个新的函数。如果需要传参,需要再调用该函数并传参
a.fn.bind(b)('piano'); // sunLi love piano
使用iframe可以实现,变量隔离
localStorage/sessionStorage是window的属性,cookie是document的方法
slice和splice的区别?
数组如何滤重?
[...new Set(arr)]
当页面上的一个元素被点击时,先从document向下一层层捕获到该元素。然后再向上冒泡,一层层触发。
事件委托是将事件写在父级元素上,e.target是事件捕获时那个最小的元素,即选中的元素。所以可以根据e.target操作选中的元素。这样不需要给每个子元素绑定事件,代码更加简约。
js通过原型链模拟实现面向对象,比如通过实例化一个构造函数可以给每个对象挂载自己专属的属性,通过给类的prototype上赋方法是所有对象所共有的方法。每次实例化不再赋值原型链上的方法。
区别:防抖只会在最后一次事件后执行触发函数,节流不管事件多么的频繁,都会保证在规定时间段内触发事件函数。
原理是维护一个定时器,将很多个相同的操作合并成一个。规定在delay后触发函数,如果在此之前触发函数,则取消之前的计时重新计时,只有最后一次操作能被触发。例如:实时搜索的input,一直输入就不发送。
- let input = document.querySelector("input");
- let time = null;//time用来控制事件的触发
-
- input.addEventListener('input',function(){
- //防抖语句,把以前的定时删除,只执行最后一次
- if(time !== null){
- clearTimeout(time);
- }
- time = setTimeout(() => {
- console.log(this.value);//业务实现语句,这里的this指向的是input
- },500)
- })
原理是判断是否达到一定的时间来触发事件。某个时间段内只能触发一次函数。例如:在指定的时间内多次触发无效
- //节流
- function throttle(fn, time) {//连续触发事件 规定的时间
- let flag = false;
- return function () {
- //使用标识判断是否在规定的时间内重复触发了函数,没有就触发,有就不触发
- if (!flag) {//不为假时 执行以下
- fn();//触发事件
- flag = true;//为真
- setTimeout(() => {//超时调用(在规定的时间内只执行一次)
- flag = false;
- }, time);
- }
- }
- }
-
- mybtn.onclick = throttle(btn, 3000);//单击事件 节流(btn,3s时间)
ES5实现继承有哪几种方式?
避免循环插入dom,比如table的行。可以js循环生成多个dom后,一次性插入。
- 方法一:
- .pop{
- width: 300px;
- height: 300px;
- position: fixed;
- left: 0;
- right: 0;
- top: 0;
- bottom: 0;
- margin: auto;
- border: 1px solid red;
- }
-
- 方法二:
- .chartLengend { // 父元素
- width: 60px;
- height: 40px;
- position: relative;
- .line { // 子元素
- width: 100%;
- height: 3px;
- background-color: #DEA182;
- position: absolute;
- top: 50%;
- left: 50%;
- transform: translate(-50%, -50%);
- border-radius: 2px;
- }
- }
- .class:last-child{}
- .class:first-child{}
-
- a:link {color:green;}
- a:visited {color:green;}
- a:hover {color:red;}
- a:active {color:yellow;}
- // :before用于在某个元素之前插入某些内容。
- // :after用于在某个元素之后插入某些内容。
- css
- p:before{
- content:"Read this: ";
- }
-
- html:
- <p>I live in Ducksburg</p>
-
- 页面展示:
- Read this: I live in Ducksburg
-
- F12看dom中:
- before
- Read this: I live in Ducksburg
单页面对一个入口DOM通过路由去更改内容,整个应用只有一个html页面
SPA优点:用户体验好,没有页面切换就没有白屏情况;
SPA缺点:首屏加载慢,不利于SEO
SPA弥补:通过压缩、路由懒加载缓解首屏慢;通过SSR 服务器端渲染解决SEO问题;
2.1、什么是组件?
组件是可复用的 Vue 实例,且带有一个名字:在这个例子中是 。我们可以在一个通过 new Vue 创建的 Vue 根实例中,把这个组件作为自定义元素来使用:
声明组件
- // 定义一个名为 button-counter 的新组件
- Vue.component('button-counter', {
- data: function () {
- return {
- count: 0
- }
- },
- template: '<button v-on:click="count++">You clicked me {{ count }} times.</button>'
- })
使用组件(把组件当作自定义元素)
- <div id="components-demo">
- <button-counter></button-counter>
- </div>
引入组件
new Vue({ el: '#components-demo' })
Prop 是你可以在组件上注册的一些自定义 attribute。当一个值传递给一个 prop attribute 的时候,它就变成了那个组件实例的一个 property。为了给博文组件传递一个标题,我们可以用一个 props 选项将其包含在该组件可接受的 prop 列表中:
组件内部声明prop
- Vue.component('blog-post', {
- props: ['title'],
- template: '<h3>{{ title }}</h3>'
- })
父组件里调用,并给prop赋值,传递到组件内部
<blog-post title="My journey with Vue"></blog-post>
其实就是通过在父组件声明方法,并绑定在子组件上。以子组件内部触发方法的形式,向父组件传参,实现子向父传值的效果。如下
父组件中声明方法,并绑定在子组件上
- <template>
- <lineChart v-on:getQuotaVal="getQuotaVal"></lineChart>
- </template>
- <script>
- methods: {
- // 本事件用来监听折线图子组件,从子组件拿到指标数据
- getQuotaVal:function(obj){
- this.lineDateType = obj.lineDateType; // 这样父组件就拿到了,子组件的obj数据
- }
- },
- </script>
子组件触发方法
- that.val = {};
- that.$emit('getQuotaVal',that.val); // 将子组件的数据发送过去;
2.4、兄弟组件间交互
使用
EventBus(事件总线)
,vue.$bus.on和emit方法。
初始化——全局定义,可以将eventBus绑定到vue实例的原型上,也可以直接绑定到window对象上.
- //main.js
- Vue.prototype.$EventBus = new Vue();
触发事件
this.$EventBus.$emit('eventName', param1,param2,...)
监听事件
- this.$EventBus.$on('eventName', (param1,param2,...)=>{
- //需要执行的代码
- })
移除监听事件
为了避免在监听时,事件被反复触发,通常需要在页面销毁时移除事件监听。或者在开发过程中,由于热更新,事件可能会被多次绑定监听,这时也需要移除事件监听。
this.$EventBus.$off('eventName');
v-if控制Dom是否存在,v-show控制样式
vuex是一个状态管理工具,集中式的管理所有组件的状态数据。统一的去管理组件,将组件的状态抽象为一个store文件,通过commit方法触发mutation里的函数来改变组件属性。
组件中可以使用computed属性监听数据的变化控制组件显隐等。如下举个loading组件的栗子
loading组件中根据Loading数据,控制DOM显隐
- <template>
- <div class="cover" v-show="Loading">
- <div>加载中</div>
- </div>
- </template>
-
- <script>
- import Store from '../../store'
- export default {
- name: "Loading",
- computed:{
- Loading(){
- return Store.state.Loading;
- }
- }
- }
- </script>
vuex集中管理状态,创建一个叫store的js文件
- import Vuex from 'vuex';
- Vue.use(Vuex);
-
- export default new Vuex.Store({
- state: {
- // Loading组件
- Loading:false,
- },
- mutations: {
- // Loading组件
- ChangeLoading:function (State,Value) {
- State.Loading = Value;
- }
- },
- });
使用loading的组件中,这样操作
- import Store from '../../store'
- Store.commit("changeFooter",true);
vuex中 mutation和action的区别和使用?
computed
computed中的属性本质上是一个变量。一个特殊的变量,它由其他变量计算或者说赋值而来。它依赖于其他变量的变化,无需也无法像普通变量一样直接赋值修改。
watch
watch用来监听某个变量,当被监听的值发生变化时,执行相关操作。
与computed的区别是,computed是一个变量,watch用来监听变量。computed监听构成它的变量的变化,watch单纯监听跟他同名的某个变量。computed方法体内只能返回构成它的变量构成,而watch里可以进行任何操作。
- data(){
- return{
- 'first':2
- }
- },
- watch:{
- first(){
- console.log(this.first)
- }
- },
双向绑定主要指修改数据时,无须操作DOM,视图会自动刷新。操作视图时绑定的数据也会跟随变动。
数据 => 视图
vue在初始化实例时,会用Object.defineProperty方法,给所有的数据添加setter函数,实现对数据变更的监听。当数据被修改时,生成新的虚拟DOM树,跟老的虚拟DOM对比,根据对比结果找出需要更新的节点进行更新。
视图 => 数据
从视图到数据较为简单,视图变化后触发监听如oninput等,在绑定的方法中修改数据。
缺陷:数据如果为对象直接新增属性,如果为数组通过下标操作数组项,页面无法触发更新。
原因: Vue 会在初始化实例时对 property 执行 getter/setter 转化,所以 property 必须在 data 对象上存在才能让 Vue 将它转换为响应式的。关于数组作者通过重写push/pop/shift/unshift/splice/reverse/sort这些方法来实现数据的相应绑定,其余的操作无法触发页面更新;
对策:关于对象可以通过Vue.$set(obj,key,value),组件中通过this.$set(obj,key,value)实现新增,修改属性vue可以相应更新视图。关于数组也可以通过Vue.$set(obj,key,value),或者作者重写的那些方法来操作;
如果有些数据需要在初始化时就渲染的,比如select下拉框的下拉内容,在mouted中请求。好处如下
组件内部钩子:beforeRouterEnter()、beforeRouterLeave、beforeRouterUpdate
- this.$router.push({
- path: '/url',
- query: {
- par:parid
- }
- })
接受参数
var parid = this.$route.query.par;
- 父:beforeCreate 首先初始化父原素
- 父:created 父原素挂载数据
- 父:beforeMounte 父原素开始挂载dom,tpl里遇到子组件
- 子:beforeCeate 子组件开始挂载数据
- 子:created 子元素数据挂载成功
- 子:beforeMount 子元素开始挂载dom
- 子:mounted 子元素dom挂载结束
- 父:mounted 父原素dom挂载结束
- 父:beforeUpdate 下面开始类似于dom事件流
- 子:beforeUpdate
- 子:updated
- 父:updated
- 父:beforeDestory
- 子:beforeDestory
- 子:destroyed
- 父:destoryed
子元素在父元素挂载dom时,开始加载。子元素一直到加载完毕dom后,父原素结束dom挂载。后面就类似于dom事件流了。
JS支持两种模块化方式,commonjs和ES6。
commonjs用于nodejs,同步加载模块。ES6的import为了不卡顿,异步加载模块。
新版Nodejs也支持使用import,但是需要修改文件后缀名为.mjs,或者在package.json中,制定type字段为module。
俺朋友面试被问到的,我不会,答案需要你自己查了
17、爷爷组件跟孙子组件如何交互?
- let a = {
- name: 'sunq',
- fn:function(action){
- console.log(this.name + ' love ' + action);
- }
- }
- let b = {name:'sunLi'}
-
- // 正常的this指向调用他的对象
- a.fn('basketball'); // sunq love basketball
- // 改变this指向
- a.fn.apply(b,['football']); // sunLi love football
-
- // 如果将a对象的fn函数改成箭头函数,this.name会是undefined
- // 箭头函数的this指向不会改变,且总是指向函数定义生效时所在的对象。
new
命令,否则会抛出一个错误。- var Person = function(name){
- this.name = name;
- }
- let sunq = new Person('sq'); // {name: 'sq'}
-
- var Person = (name) => {
- this.name = name;
- }
- let sunq = new Person('sq'); // 报错 Person is not a constructor
arguments
对象yield
命令,因此箭头函数不能用作 Generator 函数。Promise、Genarate、async\await
使用Promise.all()方法,将两个promise传入all方法,拿到异步结果再请求第三个
明明知道的语法,面试官一问我偏偏就是跟实际场景联系不到一块,
string number null undefined boolean object bigInt symbol
6、说几个ES6新增的数组的方法 详情
map 实例方法,类似于forEach,但是返回新数组
find和findIndex 实例方法,传入一个匿名函数,ruturn出符合条件的项或下标
... 拓展运算符 基本功能是将一个数组转为用逗号分隔的参数序列
7、for in和for of的区别
8、多个数据请求,如何顺序执行?
使用promise的then方法,或者写多个promise,async中使用await顺序执行。
9、proxy的理解,与defineProperty的区别?
- // es6的proxy
- let obj = {name:1,sex:2}
- let p = new Proxy(obj,{
- get:(value,key)=>{
- return 'sq的'+obj[key]
- }
- });
- p.name // sq的1
- p.sex // sq的2
-
- // es5的代理
- let newObj = {name:1,sex:2}
- Object.defineProperty(newObj,'name',{
- get:function(val){ //defineProperty中get函数没有入参
- return 'sq的' + val
- }
- })
- newObj.name // sq的undefined
- newObj.sex // 2
10、谈谈promise的原理?
2、如何通过继承扩展 element-ui 组件的功能?
通过继承扩展 element-ui 组件的功能_elementui扩展组件_在厕所喝茶的博客-CSDN博客
1、如何获取同一个cl下,最后一个li?
- $("#id").children().eq(3).remove();
-
- // 获取多个class中的某一个
- $(".className").eq(n).attr("class") // 可行
- $(".className")[n].attr("class") // 不可行
2、window.load和$(document).ready()的区别?执行先后顺序?
window.onload
必须等到页面内包括图片的所有元素加载完毕后才能执行。$(document).ready()
是DOM结构绘制完毕后就执行,不必等到加载完毕。通常简写为$()
总结:ready事件在load事件加载之前完成。
3、如何绑定一个点击事件?
- // 方式一
- $("#id").on('click',function(){});
- // 方式二
- $("#id").click(function(){});
- // 方式三
- $("#id").bind("click",function(){});
4、Jquery常用动画?
pull、commit、push、reset、merge、log、branch、stash
stash如何使用?
git reset --soft 版本号
git reset --hard 版本号
soft会退后,代码改动在本地还保存的有。hard会删除本地改动,彻底抹去该版本的痕迹。详情
将自己分支合到目标分支前,最好先将目标分支合到自己分支上处理完冲突,再将自己的分支合回目标分支。
个人理解,敏捷开发就是把一个大需求拆为多个独立的小需求。每个小需求可独立开发、测试、上线,循序渐进的完成整个系统。每个版本的周期可能比较短,比如2周,或者4周。
比如某公司需要开发维护一个巨大的平台,可能把平台外包给多个公司干。如果用如上方法,并行开发,可显著缩减工期。
如果想要保证每个版本又快又顺利的上线,需要有完善的角色支持和流程规范。
个人理解,当团队稍大,工期很紧时,如何有条不紊的保证版本质量就需要一套有效的流程了。
比如一个团队同时收到3个需求,每个需求分发给多个前后端开发。作为版本负责人或者项目负责人,如何把控每个人的代码质量、完成进度、过程留痕、风险规避,其实是有难度的。
一个需求如果经过,需求澄清、方案设计、设计评审、需求传递、版本排期/评审、开发划分、版本开发、测试用例评审、内部测试、代码评审、灰度试用&测试、版本发布、业务验收等完整的流程,可以有效地降低犯错的几率。也方便后期的查找责任人,总结各环节的问题,提升团队的工作效率,使交付越来越平稳。
部分公司面试要求中有写,维护有开源项目且具有50个star者优先。
我业余时间有开发维护一个具备管理后台/用户端/服务端的个人网站:sunq's blog
该个人网站的页面UI/功能设计,用户端/管理后台/服务端代码开发,SEO解决/首屏优化,服务器部署维护等,都由本人独立完成。目前github收获210个star
面试过程中无话可说时,可以拿出来聊聊,缓解尴尬。在面试过程中还真起了点作用,有部分面试官现场看了网站效果,评价网站整体风格简洁唯美。觉得我有独立学习的能力和摸索尝试的习惯,知识面较宽,得到过一些鼓励。
博客的代码全部开源:源码Github地址
1、dependencies和devDependencies区别
安装时 --save -dev会放在devDependencies中,--save放在dependencies
devDependencies中安装的是开发环境使用的包,比如eslint、vue-cli-serve;
dependencies中安装的是生产和开发环境下都需要使用的包,比如vue、element、vant等
devDependencies中的依赖模块,在生产环境下不会被打入包内
2、使用过哪些loader?
3、webpack具备哪些功能?
首先判断是接口慢,还是页面慢。如果接口慢,后端优化。
如果前端页面加载慢,看是否是因为图片等资源过大,尝试替换不同格式体积的图片。定位是否是某些数据处理的函数,比较耗时。或者是否循环操作DOM,js生成dom后再批量插入。
如果页面直接卡死,就需要分析是否内存泄漏。比如大屏展示的定时刷新卡死,排查思路可如下:
使用chrome的任务管理器,操作页面观察的内存占用的变化。定位到是哪些操作,哪块代码导致内存占用飙升。
因为js并没有直接释放缓存的语法,只有靠浏览器的垃圾回收机制自动清理。我们需要做的是及时给不需要的变量赋空。
特别注意大数据的循环实例化后,变量是否及时赋空。定时器等闭包方法中是否存在内存泄漏,循环渲染地图时,是否先将之前地图数据清空等。
单页面一般不会某个页面加载慢,一般都集中在首屏加载时白屏较久。处理方法可参考上文中。
1、用过哪些插件(express中间件)?
2、mongodb和mysql的区别?
3、是否了解nvm?
进程和线程的关系?
为什么要使用superWebview?
1、大屏类的项目怎么做屏幕自适应?
2、如何实现定时刷新?
有空刷刷Leetcode,很多好公司一面前先让写两道算法题。
这种情况下,如果没有一点算法积累,上面的问题咱都没机会被问。
1、除了ajax还有哪些请求?await、aysic、table
2、url输入框后发生什么事
3、加密方式有哪些?对称、非对称
4、mongodb好处?
5、如何辨别ie8是否兼容?
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。