- 一、闭包
- 二、原型和原型链
- 三、作用域和作用域链
- 四、继承
- 五、js原生事件如何绑定
- 六、JS原生常用dom操作方法
- 七、说一下ES6新增特性
- 八、对面向对象的理解
- 九、说一下JS数组常用方法
- 十、说一下JS数组内置遍历方法有哪些和区别
- 十一、说一下从输入域名URL到页面加载完中间发生了什么?
- 十二、说一下JS事件代理(也称事件委托)是什么,及实现原理?
- 十三、 说一下JS数据类型有哪些?
- 十四、说一下call,apply,bind区别
- 十五、Ajax相关
- 十六、 跨域的解决方案目前有三种主流解决方案。
- 十七、说一下原生ajax的交互过程(即流程)
- 十八、说一下你对同步和异步的理解
- 十九、浅拷贝和深拷贝
- 二十、this的指向问题
- 二十一、数组去重
- 二十二、检查数据类型的方法
- 二十三、进程和线程
- 二十四、promise
- 二十五、重绘和回流是什么
- 二十六、race和all
- 二十七、var let const的区别
- 二十八、说一下vue最大特点是什么或者说vue核心是什么
- 二十九、说一下vue常用基本指令有哪些
- 三十、Vue常用的修饰符
- 三十一、Vue 组件中 data 为什么必须是函数?为什么data函数里面要return一个对象?
- 三十二、 说一下v-if和v-show的区别
- 三十三、自定义指令v-bind
- 三十四、过滤器
- 三十五、说一下vue生命周期钩子函数有哪些
- 三十六、通过vuex实现兄弟组件通信
- 三十七、slot
- 三十八、说一下你对单向数据流的理解
- 三十九、双向数据绑定
- 四十、hash和history
- 四十一、vue路由实现底层原理
- 四十二、路由钩子
- 四十三、Vue 等单页面应用的优缺点
- 四十四、Vue-router 使用params与query传参有什么区别
- 四十五、vuex
- 四十六、mock
- 四十七、注册组件
- 四十八、生命周期
- 四十九、小程序中的路由跳转
- 五十、小程序和H5的区别
- 五十一、小程序页面间传递数据
- 五十二、bindtap 和 catchtap 的区别是什么
- 五十三、小程序tabbar实现原理
- 五十四、说说小程序中wx:if和hidden的区别
- 五十五、跨站脚本攻击(XSS攻击)
- 五十六、跨站请求伪造(CSRF攻击)
- 五十七、使用vue-print-nb实现打印功能
- 五十八、利用h5实现文件导入功能
一、闭包
- 由于作用域的关系,正常情况下函数外部是访问不到函数内部作用域变量的,闭包说的通俗一点就是打通了一条在函数外部访问函数内部作用域的通道。
- 表象判断是不是闭包: 函数嵌套函数,内部函数被return, 内部函数调用外层函数的局部变量
- 优点:可以隔离作用域,不造成全局污染。
- 缺点:由于闭包长期驻留内存,则长期这样会导致内存泄露
- 如何解决内存泄露:将暴露全外部的闭包变量置为null
-
二、原型和原型链
原型:在js中,每个函数都有 prototype 属性,该属性指向原型对象;prototype 里面有一个constructor属性指向函数本身。使用原型对象的好处是所有对象实例共享它所包含的属性和方法。
原型链:js在查找属性的过程中,如果在自有的属性中查不到,就会在原型对象中查找,如果原型对象里面也找不到,就会通过原型链指针—proto—在原型对象的原型上查找,这就是原型链,直到查到原型链的最顶端object。
三、作用域和作用域链
作用域:一个变量可以生效的范围
- 局部作用域:只能在函数内部访问它们
- 全局作用域:网页的所有脚本和函数都能够访问它
作用域链:
原型链继承:让新实例的原型等于父类的实例。
- 构造函数继承:用.call()和.apply()将父类构造函数引入子类函数(在子类函数中做了父类函数的自执行(复制))
- 实例继承:
- 拷贝继承
- 组合继承
-
五、js原生事件如何绑定
html标签事件绑定,就是在html各种标签上直接添加事件,类似于css的行内样式,缺点是不好维护,不建议使用
- js事件绑定:先获取dom元素,然后直接给dom元素添加事件。将事件设置为null可以移除事件。优点:兼容性好。缺点:只支持冒泡,不支持捕获 ```javascript var btn=document.getElementById(‘id元素’)
btn.onclick=function() { //要处理的事件逻辑 } btn.onclick=null
- 事件监听,`addEventListener`绑定,`removeEventListener`移除。- 优点:支持给个元素绑定多个相同事件,支持冒泡和捕获事件机制```javascriptvar btn=document.getElementById(‘id元素’)//绑定事件btn.addEventListener(‘click’,绑定的事件处理函数名,false)//移除事件btn.removeEventListener(‘click’,要移除的事件处理函数名,false)
六、JS原生常用dom操作方法
- 查找:
getElementByidgetElementsByTagNamequerySelectorquerySelectorAll
- 插入:
appendChildinsertBefore
- 删除:
removeChild
- 克隆:
cloneNode
设置和获取属性:
let/const
- 箭头函数
- 模板字符串
- 解构赋值
- 类和继承
- 函数默认参数
- 展开运算符
- 模块化
- 模块的导入(
import)和导出(export default/export),Promise,set和symbol -
八、对面向对象的理解
在js里面,万物皆对象。可以将所需要做的功能抽象成一个“对象”,然后反复调用这个对象来完成你想要的功能
九、说一下JS数组常用方法
push:末尾添加
- pop:末尾删除
- shift:前面删除
- unshift:前面删除
- reverse: 反转数组
- splice:截取数组
- join:将数组的元素链接称字符串
-
十、说一下JS数组内置遍历方法有哪些和区别
forEach
- filter:是一个过滤遍历的方法,将数组中满足条件的数据返回成一个新数组
- map:操作数组的每一个元素,并返回一个新数组
- some:这个some方法用于只要数组中至少存在一个满足条件的结果,返回值就为true,否则返回false, 写法和forEach类似
every: 这个every方法用于数组中每一项都得满足条件时,才返回true,否则返回false, 写法和forEach类似
十一、说一下从输入域名URL到页面加载完中间发生了什么?
DNS解析
- TCP连接
- 发送HTTP请求
- 服务器处理请求并返回需要的数据
- 浏览器解析渲染页面
- 连接结束
输入了一个域名,域名要通过DNS解析找到这个域名对应的服务器地址(ip),通过TCP请求链接服务,发送HTTP请求,通过WEB服务器(apache)返回数据,浏览器根据返回数据构建DOM树,通过css渲染引擎及js解析引擎将页面渲染出来,关闭tcp连接
十二、说一下JS事件代理(也称事件委托)是什么,及实现原理?
JS事件代理或事件委托就是通过给父级元素(例如:ul)绑定事件,不给子级元素(例如:li)绑定事件,然后当点击子级元素时,通过事件冒泡机制在其绑定的父元素上触发事件处理函数,主要目的是为了提升性能,因为我不用给每个子级元素绑定事件,只给父级元素绑定一次就好了,在原生js里面是通过event对象的targe属性实现
十三、 说一下JS数据类型有哪些?
基本数据类型
- number
- string
- Boolean
- null
- undefined
- symbol(ES6新增)
复合类型
call和apply的主要区别是在传递参数上不同,call后面传递的参数是以逗号的形式分开的,apply传递的参数是数组形式 call的性能要比apply好。
bind返回的是一个函数形式,如果要执行,则后面要再加一个小括号 例如:bind(obj,参数1,参数2,)(),bind参数只能以逗号分隔形式,不能是数组形式
十五、Ajax相关
说一下你对ajax的同源策略的理解
- ajax同源策略是因为安全的考虑,ajax不允许访问不同域名下的资源即所谓同源策略的意思。
- 说一下什么情况下会产生跨域及产生跨域的解决方案和实现原理?
- 产生跨域的情况有:不同协议,不同域名,不同端口以及域名和ip地址的访问都会产生跨域。
什么是ajax
jsonp
- jsonp实现原理:主要是利用动态创建script标签请求后端接口地址,然后传递callback参数,后端接收callback,后端经过数据处理,返回callback函数调用的形式,callback中的参数就是json
- 代理(前端代理和后端代理)
- 前端代理我在vue中主要是通过vue脚手架中的config中的index文件来配置的,其中有个proxyTable来配置跨域的
CORS
交互流程:
同步即sync,形象的说就是代码一行行执行,前面代码和请求没有执行完,后面的代码和请求就不会被执行,
- 缺点:容易导致代码阻塞
- 优点:程序员容易理解(因为代码从上往下一行行执行,强调顺序)
- 异步:即async,形象的说就是代码可以在当前程序没有执行完,也可以执行后面的代码
- 缺点:程序员不易理解(因为不是按顺序执行的)
- 优点:可以解决代码阻塞问题,提升代码执行效率和性能
异步解决方案主要有三个:
浅拷贝:
- for···in只循环第一层
- Object.assign方法
- 直接用=赋值
- 深拷贝:
- JSON.parse(JSON.stringify(对象))
-
二十、this的指向问题
全局的 this → 指向的是 Window
- 对象中的 this → 指向其本身
- 事件中 this → 指向事件对象
- 函数:this指向函数的调用者
-
二十一、数组去重
双层循环,外层循环元素,内层循环时比较值如果有相同的值则跳过,不相同则push进新数组
- 利用splice直接在原数组进行操作,双层循环,外层循环元素,内层循环时比较值,值相同时,则删去这个值,删除元素之后,需要将数组的长度也减1.
- indexOf:新建一个新数组,遍历数组,用indexOf判断值不在新数组中就push进新数组
new.set()和Array.from()
typeof
- instanceof
object.prototype.tostring.call()
二十三、进程和线程
进程是系统中正在运行的一个程序,程序一旦运行就是进程。
- 线程是进程的一个实体,是进程的一条执行路径。
一个进程可以拥有多个线程,每个线程使用其所属进程的栈空间。线程与进程的一个主要区别是,同一进程内的多个线程会共享部分状态,多个线程可以读写同一块内存(一个进程无法直接访问另一进程的内存)。
二十四、promise
Promise 是一个构造函数,对回调函数的一种封装,可以解决回调地狱问题。
- 当我们使用new出来的promise对象时。它有三种状态:pending(进行中),resolved(已完成),rejected(已失败),状态一旦发生,就不能改变。执行new的时候状态就开始变化。
- promise对象有两个方法:then()和catch()。
- then()方法有两个参数,resolve和reject第一个参数是状态为已完成时执行的回调函数,第二个参数是状态为已失败时执行的回调函数
- catch()方法用来捕获错误的,错误时不捕获错误会报错
使用promise的好处是:
回流:当 render tree 中的一部分或者全部因为元素的规模尺寸,布局, 隐藏等改变而需要重新构建,这就叫回流,每个页面至少需要一次回流, 就是在页面第一次加载的时候,这时候一定会发生回流,因为要构建 render tree
- 重绘:在回流的时候,浏览器会使渲染树中收到影响的部分失效,并重新构造 这部分渲染树,完成回流后,浏览器会重新绘制受影响的部分到屏幕中, 这就是重绘
当 render tree 中的一些元素需要更新属性,而这些属性只是影响元素的 外观,不会影响布局,就叫重绘
二十六、race和all
Promise.race():
- race的用法:谁跑的快,以谁为准执行回调。
- race的使用场景:比如我们可以用race给某个异步请求设置超时时间,并且在超时后执行相应的操作
Promise.all():
var声明的变量会挂载在window上,而let和const声明的变量不会
- var声明变量存在变量提升,let和const不存在变量提升
- let和const声明形成块作用域
- 同一作用域下let和const不能声明同名变量,而var可以
const一旦声明必须赋值,不能使用null占位,声明后不能再修改,如果声明的是复合类型数据,可以修改其属性
二十八、说一下vue最大特点是什么或者说vue核心是什么
vue最大特点我感觉就是“组件化“和”数据驱动“
v-if
- v-show
- v-for
- v-model
- v-on
- v-bind
-
三十、Vue常用的修饰符
.stop - 调用 event.stopPropagation(),禁止事件冒泡。
- .prevent - 调用 event.preventDefault(),阻止事件默认行为。
- .capture - 添加事件侦听器时使用 capture 模式。
- .self - 只当事件是从侦听器绑定的元素本身触发时才触发回调。
- .native - 监听组件根元素的原生事件。
- .once - 只触发一次回调。
- .left - (2.2.0) 只当点击鼠标左键时触发。
- .right - (2.2.0) 只当点击鼠标右键时触发。
.middle - (2.2.0) 只当点击鼠标中键时触发。
三十一、Vue 组件中 data 为什么必须是函数?为什么data函数里面要return一个对象?
因为如果data是一个对象会导致数据共享,在多次使用该组件时,改变其中一个组件的值会影响到全部组件的值。
而如果是通过函数的形式返回一个对象,在每次使用该组件时返回的对象地址指向都是是不一样的,这样就可以使每个组件数据独立。防止数据污染
三十二、 说一下v-if和v-show的区别
v-if和v-show都可以显示和隐藏一个元素但v-if是控制dom的显示和隐藏,而v-show是控制样式的显示和隐藏。
-
三十三、自定义指令v-bind
全局自定义指令:Vue.directive(‘指令名’,{ inserted (el) { bind函数 } })
局部自定义指令:directives:{ ‘指令名’:{ bind函数 } }
三十四、过滤器
vue过滤器主要用于对渲染出来的数据进行格式化处理。
全局过滤器:
Vue.filter(‘过滤器名’,function(参数1,参数2,…) {return 要返回的数据格式})
局部过滤器:在组件内部添加filters属性来定义过滤器
fitlers:{过滤器名(参数1,参数2,,…参数n) {return 要返回的数据格式}}
三十五、说一下vue生命周期钩子函数有哪些
创建前:beforeCreate, 创建后:created
- 挂载前:beforeMount, 挂载后:mounted
- 更新前:beforeUpdate, 更新后:updated
- 销毁前:beforeDestroy, 销毁后:destroyed
created用于获取后台数据,mounted用于dom挂载完后做一些dom操作
三十六、通过vuex实现兄弟组件通信
具体实现:
- vuex是一个状态管理工具,主要解决大中型复杂项目的数据共享问题,
- 主要包括state,actions,mutations,getters和modules 5个属性
主要流程:
vue的插槽,可以把封装的组件插入页面,给solt定义一个name,就是具名插槽,可以插入指定的组件
三十八、说一下你对单向数据流的理解
单向数据流主要是vue 组件间传递数据是单向的,即数据总是由父组件传递给子组件,子组件在其内部维护自己的数据,但它无权修改父组件传递给它的数据,当开发者尝试这样做的时候,vue 将会报错。这样做是为了组件间更好的维护。
在开发中可能有多个子组件依赖于父组件的某个数据,假如子组件可以修改父组件数据的话,一个子组件变化会引发所有依赖这个数据的子组件发生变化,所以 vue 不推荐子组件修改父组件的数据
三十九、双向数据绑定
双向数据绑定利用了数据劫持和订阅者模式,是使用obiect.defineproperty劫持了所有属性的getter和setter,当数据发生变化时,会给订阅者发送消息,执行回调的函数
四十、hash和history
Hash 模式地址栏中有#,history 没有,history 模式下刷新,会 出现 404 情况,需要后台配置
hash 方案兼容性好,而H5的history主要针对高级浏览器。
四十一、vue路由实现底层原理
在Vue中利用数据劫持defineProperty在原型prototype上初始化了一些getter,劫持_route,当_route触发setter方法的时候,则会通知到依赖的组件。
接下来在init中,会挂载判断是路由的模式,是history或者是hash,点击行为按钮,调用hashchange或者popstate的同时更_route,_route的更新会触发route-view的重新渲染。
四十二、路由钩子
全局钩子:
- Router.beforeEach
- Router.afterEach
- 某个路由独享钩子:
- beforeEnter
- beforeLeave
组件内部钩子:
优点
- 单页应用的内容的改变不需要重新加载整个页面,web应用更具响应性和更令人着迷。
- 单页应用没有页面之间的切换,就不会出现“白屏现象”,也不会出现假死并有“闪烁”现象
- 单页应用相对服务器压力小,服务器只用出数据就可以,不用管展示逻辑和页面合成
- 良好的前后端分离。后端不再负责模板渲染、输出页面工作,后端API通用化,即同一套后端程序代码,不用修改就可以用于Web界面、手机、平板等多种客户端。
缺点
用法上
- query要用path来引入,params要用name来引入,接收参数都是类似的,分别是this.
route.params.name。
- query要用path来引入,params要用name来引入,接收参数都是类似的,分别是this.
展示上
目录下建立一个 store 文件夹,并且在下面建立一个 store.js 文件,先引入 Vue 和 Vuex 并且别忘了 Vue.use(Vuex);
- 在main.js 引入 store 文件 ,并且 Vue 实例上得将 挂载 store
- 在store.js导出 new Vuex.Store({}),里面有一个state
- 通过 this.$store.state 可以拿到 state里面的数据
- getters 可以实时监听state值的变化(最新状态)
在methods使用一个事件this.$store.comit(vuex事件名,参数)提交,在store.js文件,添加mutations,在mutations中定义两个函数修改state
四十六、mock
安装mock依赖:
cnpm i mockjs -D在src下创建mock文件夹,再创建index.js
// (1)引入mockconst Mock = require('mockjs')// (2)mock一个接口Mock.Mock('/api/artList', {code: 200,msg: 'success',"data|10-20": [{"id|+1": 1,"title": "@ctitle", // 标题"desc": "@cparagraph", // 描述"author": "@cname", // 作者中文名"thumb": "@image('100x100','@color','牛夫人)", // 随机图片(里面的乘号是 英文小x)}]})
四十七、注册组件
使用
Vue.component('my-component-name', { /* ... */ })注册组件并导出-
四十八、生命周期
整个小程序的生命周期 – 在app.js中设置
- onLaunch 当小程序初始化完成时,会触发 onLaunch(全局只触发一次)。
- onShow 当小程序启动,或从后台进入前台显示,会触发 onShow
- onHide 当小程序从前台进入后台,会触发 onHide
- onError 当小程序发生脚本错误,或者 api 调用失败时,会触发 onError 并带上错误信息
小程序页面的生命周期
wx.navigateTo():保留当前页面,跳转到应用内的某个页面。但是不能跳到 tabbar 页面
- wx.redirectTo():关闭当前页面,跳转到应用内的某个页面。但是不允许跳转到 tabbar 页面
- wx.switchTab():跳转到 tabBar 页面,并关闭其他所有非 tabBar 页面
- wx.navigateBack()关闭当前页面,返回上一页面或多级页面。可通过 getCurrentPages() 获取当前的页面栈,决定需要返回几层
wx.reLaunch():关闭所有页面,打开到应用内的某个页面
五十、小程序和H5的区别
主要区别时运行环境不同,(小程序运行在安卓,ios或开发者工具,H5运行在浏览器)
,会导致开发成本不一样,获取权限的方式不同,运行流畅度不同五十一、小程序页面间传递数据
使用全局变量实现数据传递
- 在
app.js文件中定义全局变量globalData, 将需要存储的信息存放在里面。使用的时候,直接使用getApp()拿到存储的信息
- 在
- 使用
wx.navigateTo与wx.redirectTo的时候,可以将部分数据放在url里面,并在新页面onLoad的时候初始化 -
五十二、bindtap 和 catchtap 的区别是什么
相同点:首先他们都是作为点击事件函数,就是点击时触发。在这个作用上他们是一样的,可以不做区分
不同点:他们的不同点主要是bindtap是不会阻止冒泡事件的,catchtap是阻止冒泡的
五十三、小程序tabbar实现原理
要实现tabbar的导航条其实很简单
- 全局的tabbar只需要在app.json文件中定义即可
- 局部的就在局部的tabbar文件中实现。
page里设置地址,tabbar对象里设置list,tabbar信息
五十四、说说小程序中wx:if和hidden的区别
wx:if 与 hidden 都用来控制小程序元素的显示
不同点
攻击者往Web页面里插入恶意html代码,当用户浏览该页之时,嵌入其中Web里面的html代码会被执行
- xss常见的攻击方式:
- 用户提交的数据未经处理,直接住注入到动态页面中
- 危害:盗取各类用户帐号 ,企业数据,强制发送电子邮件,网站挂马
- 解决方案:不信赖用户输入,对特殊字符如”<”,”>”转义,或者是替换
小结:
跨站请求伪造(CSRF攻击)
安装vue-print-nb依赖
npm install vue-print-nb --save
main.js里面全局引入
import Print from 'vue-print-nb'Vue.use(Print);
页面中使用
<div id="printMe" ><p>打印内容</p></div><button v-print="'#printMer'">打印</button>
五十八、利用h5实现文件导入功能
使用input标签H5新增的type=“file”属性可以上传文件
- 使用readAsDataURL可以转换为base64编码
const file = this.files[0]const fr = new FileReader()fr.readAsDataURL(file) // 将文件转换成 base64进制编码
