2023前端面试题汇总(最新) 您所在的位置:网站首页 大学生案例分析题及答案的app 2023前端面试题汇总(最新)

2023前端面试题汇总(最新)

2024-06-28 14:50| 来源: 网络整理| 查看: 265

目录 1. 防抖和节流2. js闭包3. Vue相关总结3.1 vue中的data为什么是一个函数?(面试常问)3.2 MVC 和 MVVM的区别3.3 v-model 原理3.4 vue中的data为什么是一个函数?(面试常问)3.5 v-if 和 v-show的区别3.6 v-for中为什么要有key3.7 打包后 dist 目录过大,解决办法?3.8 computed 和 watch 的区别3.9 vue组件之间的数据传递3.9.1 父 传 子3.9.2 子 传 父3.9.3 全局事件总线:可以实现任意组件间的数据传递4.0 vue原型 和 原型链 4.1 深拷贝 与 浅拷贝4.2 $nextTick的作用4.3 Vue生命周期 4. ES6面试题4.1 var let const 区别4.2 解构赋值4.3 如何利用es6快速的去重?4.4 Promise 面试题 以下代码的执行结果是?4.5 跨域的解决方法4.5.1. webpack 里的proxy4.5.2. jsonp (需要后端支持 )4.5.3. webpack plugin (插件)4.5.4. cors (后端解决) 4.6 git命令(实际工作中常用)4.6.1 基本4.6.2 分支明细4.6.3 分支命令4.6.4 暂时保存更改的代码4.6.5 代码回退 4.7 get与post请求有什么区别4.8 cookie、localStorage、sessionStorage的区别4.9 async 和 await 的区别5.0 setTimeout 时间为0, 以及误差的原因5.1 求数组的最大值?5.2 求数组的最小值?5.3 数组去重5.3.1 利用filter 、indexof5.3.2 sort 、splice 实现去重5.3.3 最短的方法,使用new Set([...])5.3.4 indexOf 、push 实现5.3.5 对象属性名唯一性实现 数组去重 5.4. 数组求和5.5 生成从0 到 指定数字的数组 5.6 js的数据类型5.7 js的变量提升5.8 this指向5.9 map和forEach的区别6.0 箭头函数和普通函数的区别?6.1 es6新增6.2 数组方法汇总6.3 项目性能优化方案6.4 forEach 和 map的区别6.5 forEach 和 for 循环的区别6.6 Vue2 和 Vue3 的区别6.7 call、apply、bind使用和区别

1. 防抖和节流

防抖(debounce):单位时间内,频繁触发事件,只执行最后一次。 比如点击按钮,2秒后调用函数,结果在1.5秒的时候又点了,则会重新计算2秒后在调用函数。

应用场景:搜索框、输入框、手机邮箱验证等

思路:利用定时器,每次触发先清除定时器() 底层代码实现:

const box = document.querySeleter(".box") let i = 1 function mouseMove() { box.innerHTML = i++ } function debounce(fn, t) { let timer // return 返回一个匿名函数 return function() { if(timer) clearTimeout(timer) timer = setTimeOut(function() { fn() }, t) } } box.addEventListener('mousemove', debounce(mouseMove, 500))

节流(throttle):单位时间内,频繁触发事件,只执行一次

应用场景比较多的是:鼠标经过、页面缩放、滚动条滚动scroll事件、下拉刷新等高频事件 思路:利用定时器,判断是否有定时器,如果有等定时器结束再开启新的定时器 代码实现:

const box = document.querySeleter(".box") let i = 1 function mouseMove() { box.innerHTML = i++ } function throttle(fn, t) { let timer // return 返回一个匿名函数 return function() { if(!timer) { timer = setTimeOut(function() { fn() // 清空定时器 此处使用timer=null清除定时器是因为写在了定时器里面,setTimeout中是无法清除定时器的,因为定时器还在运作 timer = null }, t) } } } box.addEventListener('mousemove', throttle(mouseMove, 500)) 2. js闭包

什么是闭包:闭包就是能够读取其他函数内部变量的函数

function fn0 () { const aaa = 0 return function() { return aaa console.log('打印', aaa) } }

闭包存在意义:

可以延长变量的生命周期4可以创建私有的环境

闭包好处:

可以读取其他函数的内部变量 将变量始终保存在内存中 可以封装对象的私有属性和方法

坏处:

消耗内存、使用不当会造成内存溢出问题 3. Vue相关总结 3.1 vue中的data为什么是一个函数?(面试常问) Vue 中的 data 必须是个函数,因为当 data 是函数时, 组件实例化的时候这个函数将会被调用,返回一个对象, 计算机会给这个对象分配一个内存地址,实例化几次就分配几个内存地址, 他们的地址都不一样,所以每个组件中的数据不会相互干扰,改变其中一个组件的状态,其它组件不变。 简单来说,就是为了保证组件的独立性和可复用性,如果 data 是个函数的话, 每复用一次组件就会返回新的 data,类似于给每个组件实例创 建一个私有的数据空间, 保护各自的数据互不影响 3.2 MVC 和 MVVM的区别 MVC:M(model数据)、V(view视图),C(controlle控制器) 缺点是前后端无法独立开发,必须等后端接口做好了才可以往下走; 前端没有自己的数据中心,太过依赖后台 MVVM:M(model数据)、V(view视图)、VM(viewModel控制数据的改变和控制视图) html部分相当于View层,可以看到这里的View通过通过模板语法来声明式的将数据渲染进DOM元素, 当ViewModel对Model进行更新时,通过数据绑定更新到View。 Vue实例中的data相当于Model层,而ViewModel层的核心是Vue中的双向数据绑定, 即Model变化时VIew可以实时更新,View变化也能让Model发生变化 MVVM与MVC最大的区别就是:它实现了View和Model的自动同步, 也就是当Model的属性改变时,我们不用再自己手动操作Dom元素,来改变View的显示, 而是改变属性后该属性对应View层显示会自动改变 3.3 v-model 原理 是采用数据劫持结合发布者-订阅者模式的方式, 通过Object.defineProperty()来劫持各个属性的setter,getter, 在数据变动时发布消息给订阅者,触发相应的监听回调从而达到数据和视图同步。 3.4 vue中的data为什么是一个函数?(面试常问) 实际上就是一个闭包,因为vue是单页面应用,是由很多组件构成,每一个组件中都有一个data, 所以通过闭包给每一个组件创建了一个私有的作用域,这样就不会相互影响。 3.5 v-if 和 v-show的区别 v-if是通过添加和删除元素来进行显示或者隐藏 v-show是通过操作DOM修改display样式来修改元素的显示和隐藏 如果需要频繁的进行元素的显示和隐藏使用v-show性能更好 3.6 v-for中为什么要有key

key 可以提高虚拟DOM的更新效率。

在vue中,默认“就地复用”的策略,在DOM操作的时候,如果没有key 就会造成选项错乱

key 只能是字符串或者number,其他类型不可以

1. 虚拟DOM中key的作用:

key是虚拟DOM对象的标识,当数据发生变化时, Vue会根据【新数据】生成【新的虚拟DOM】, 随后Vue进行【新的虚拟DOM】与【旧的虚拟DOM】差异比较比较规则如下:

2. 比较规则:

1)旧虚拟DOM找到了与新虚拟DOM相同的key:

若虚拟DOM中内容没变,直接使用之前的真实DOM 若虚拟DOM中内容变了,则生成新的真实DOM,随后替换掉页面中之前的真实DOM

3. 用index作为key可能会引发的问题:

1)若对数据进行:逆序添加、逆序删除等破坏顺序的操作,会产生没有必要的真实DOM更新==>界面效果没问题,但效率低 2)如果结构中还包含输入类的DOM,会产生错误的DOM更新 ==> 界面有问题 3.7 打包后 dist 目录过大,解决办法? dist打包生成的文件中有 .map 文件,可以删除。在 vue.config.js文件中配置:productionSourceMap: false组价和路由使用懒加载、按需引入等对于文件和图片进行压缩。 安装压缩组件: compression-webpack-plugin 安装后进行导入配置: 最小化代码 minisize: true 分割代码: splitChunksl 超过限定值的文件进行压缩,threshold: 文件大小(字节为单位) 3.8 computed 和 watch 的区别 computed是计算属性,watch是监听器,用来监听某一个值的变化进而触发相应的回调computed中的函数必须要有return返回、watch没有必须的要求返回returncomputed是第一次加载就触发一次,watch首次加载不会触发,如果需要首次加载需要设置immediate属性computed中的函数所依赖的属性没有发生变化,那么调用当前的函数的时候会从缓存中获取;而watch在每次监听值发生变化的时候都会执行回调。 3.9 vue组件之间的数据传递 3.9.1 父 传 子

通过在子组件身上绑定自定义属性,然后再子组件里使用props属性来接收即可 ​​在这里插入图片描述

3.9.2 子 传 父

1)第一种方式:通过父组件给子组件传递函数类型的props实现:子组件给父组件传递数据 父组件: 在这里插入图片描述 在这里插入图片描述

子组件: 在这里插入图片描述

2)第二种方式:通过父组件给子组件绑定一个自定义事件实现:子组件给父组件传递数据 父组件 在这里插入图片描述 在这里插入图片描述

子组件 在这里插入图片描述

3)第三种方式:通过父组件给子组件绑定一个自定义事件实现:使用ref实现 父组件 在这里插入图片描述 在这里插入图片描述

子组件 在这里插入图片描述

3.9.3 全局事件总线:可以实现任意组件间的数据传递

main.js:将全局事件bus,挂载到Vue的原型上,这样所有的组件都可以使用 在这里插入图片描述 兄弟组件A: 在这里插入图片描述 兄弟组件B: 在这里插入图片描述 4. 消息订阅与发布 一种组件间的通信方式,适用于任意组件间通信。

使用步骤:

安装pubsub: npm i pubsub-js引入: import pubsub from ‘pubsub-js’接收数据: A组件想要接收数据,则在A组件中订阅消息,订阅的回调留在A组件自身 mounted() { this.pid = punsub.subscribe('xxx', (data)=>{ ...... }) } 提供数据: pubsub.publish(‘xxx’, 数据)最好在beforeDestory钩子中,用pubsub.unsubscribe(pid)取消订阅 4.0 vue原型 和 原型链 不管是普通函数还是构造函数,都有一个属性prototype,用来指向这个函数的原型对象。 同时原型对象也有一个constructor属性,用来指向这个原型对象的构造函数。 原型对象的作用:用来存储实例化对象的公有属性和方法

例如

function Person (name, age) { this.name = name this.age = age this.say = function () { console.log('我会说话') } } let person1 = new Person('小明', 20) console.log(person1.name) // 小明 console.log(person1.age) // 20 console.log(person1.say()) // 我会说话

如上:实例化出来的person1,就可以使用构造函数Person里面的属性和方法

总结

访问对象的一个属性,先在自身查找,如果没有,会访问对象的__proto__,沿着原型链查找,一直找到Object.prototype.proto。每个函数都有prototype属性,会指向函数的原型对象。所有函数的原型对象的__proto__,会指向Object.prototype。原型链的尽头是Object.prototype.proto,为null。

具体可参考下方文章链接地址(写的非常详细易懂):https://blog.csdn.net/weixin_56505845/article/details/119683904

4.1 深拷贝 与 浅拷贝

首先浅拷贝和深拷贝只针对引用类型 浅拷贝:拷贝的是地址,适合拷贝单层的数据 浅拷贝 创建一个对象,这个对象有着原始对象的值的精确拷贝。 这里要引入基本数据类型 和 引用数据类型 ,浅拷贝的如果是基本数据类型,则拷贝的直接是这个数据的值;如果是引用类型,则是创建了一个新的指针,用来指向原类型的内存地址(即拷贝了这个内存地址),如果一个对象改变了,则会影响另一个对象

常见方法: 1、拷贝对象:Object.assign() / 展开运算符{…obj} 拷贝对象 2、拷贝数组:Array.prototype.concat() / […arr]

弊端:如果拷贝的数据复杂,此时修改拷贝对象,会影响原数据 例如:

const obj = { name: '你好', age: 18, family: { son: '大儿子' } } const newObj = {} Object.assign(newObj, obj) newObj.family.son = '小儿子' console.log(obj) // 此时打印出来的原数据obj里面的family对象值被修改

浅拷贝代码实现:

function clone(target) { let cloneTarget = {}; for (const key in target) { cloneTarget[key] = target[key]; } return cloneTarget; };

深拷贝 与之相对,深拷贝指的是创建一个新的指针,同时也会生成一个新的内存地址,这个新的指针指向新的内存地址。与原对象是相互独立,互不影响

实现深拷贝的方法

最常用的 JSON.parse(JSON.stringify()) 递归实现 创建一个新的对象,遍历需要克隆的对象,将需要克隆对象的属性依次添加到新对象上,返回新对象。

考虑到要拷贝的对象可能嵌套很深,因此可以通过递归的方法来实现,优化上方代码:

1. 如果是原始类型,无需拷贝,可以直接返回 2. 如果是引用类型,可以创建一个新的对象,遍历需要克隆的对象,将需要克隆对象执行深拷贝后依次添加到新对象上 module.exports = function clone(target) { if (typeof target === 'object') { // 此处要先判断是否是数组,因为数组也属于对象 let cloneTarget = Array.isArray(target) ? [] : {}; for (const key in target) { // key 是属性名,target[key]是属性值 cloneTarget[key] = clone(target[key]); // cloneTarget[key] 是创建属性名 } return cloneTarget; } else { return target; } };

详细可参考:https://www.jianshu.com/p/a447d7325736 3)js库lodash里面的cloneDeep实现 例如:

let obj = [{'a' : 1}, {'b': 2}] let deepObj = _.cloneDeep(obj) console.log(obj) 4.2 $nextTick的作用

首先我们要先明白一个道理:Vue的响应式并不是数据发生变化后,DOM立即跟着发生变化的,而是按一定的策略进行DOM更新的。

作用:$nextTick 是在下次 DOM 更新循环结束之后执⾏延迟回调,在修改数据之后使⽤ $nextTick,则可以在回调中获取更新后的 DOM,在下次 DOM 更新循环结束之后执行延迟回调

说白了就是:当数据更新了,在DOM更新后,自动执行该函数

什么时候用?

Vue⽣命周期的created()钩⼦函数进⾏的DOM操作⼀定要放在Vue.nextTick()的回调函数中,原因是在created()钩⼦函数执⾏的时候,DOM 其实并未进⾏任何渲染,⽽此时进⾏DOM操作⽆异于徒劳,所以此处⼀定要将DOM操作的js代码放进Vue.nextTick()的回调函数中。当项⽬中改变data函数的数据,想基于新的dom做点什么,对新DOM⼀系列的js操作都需要放进Vue.nextTick()的回调函数中

想了解更详细的🉑️参考:https://www.jianshu.com/p/8efa5cba7d07

4.3 Vue生命周期

可点击参考文档详细了解

4. ES6面试题 4.1 var let const 区别

var: 存在变量提升;存在变量覆盖,已经被定义且赋值的变量,如果再次被赋值,则以后一次值为准;没有块级作用域;

const: 定义的是常量,声明之后必须赋值;定义的值不能去修改,否则报错;有块级作用域;不存在变量提升和变量覆盖;对于数组和对象的元素修改,不算做对常量的修改,不会报错。

let: 有块级作用域;不存在变量提升和变量覆盖;let不允许在相同的作用域中重复声明,注意是相同作用域,不同作用域重复声明不会报错

4.2 解构赋值

let a = 1; let b = 2; 如果在不声明第三个变量的前提下,使a=2, b=1?

答案:[a, b] = [b, a]

4.3 如何利用es6快速的去重? let arr = [23, 12, 13, 33, 22, 12, 21] let item = [...new Set(arr)] 4.4 Promise 面试题 以下代码的执行结果是? const promise = new Promise((resolve, reject) => { console.log(1) resolve() console.log(2) }) promise.then(() => { console.log(3) }) console.log(4)

答案:1,2,4,3

解释:以上考察的是关于promise的原理,promise的构造函数是同步执行的,当new Promise的一瞬间,1,2 就立刻被执行,而 .then方法是异步执行的,当执行完1和2之后,会执行输出4,最后执行输出3

4.5 跨域的解决方法

跨域:只要协议、域名和端口号有一个不相同就会产生跨域问题。同源策略是一个安全策略。同源,指的是协议,域名,端口相同。浏览器处于安全方面的考虑,只允许本域名下的接口交互,不同源的客户端脚本,在没有明确授权的情况下,不能读写对方的资源。

解决办法:

4.5.1. webpack 里的proxy devServer: { proxy: { //配置跨域 '/api': { target: 'http://121.121.67.254:8185/', //这里后台的地址模拟的;应该填写你们真实的后台接口 changOrigin: true, //用于控制请求头中的post值,默认开启 pathRewrite: { /* 重写路径,当我们在浏览器中看到请求的地址为:http://localhost:8080/api/core/getData/userInfo 时 实际上访问的地址是:http://121.121.67.254:8185/core/getData/userInfo,因为重写了 /api */ '^/api': '' } }, } } 4.5.2. jsonp (需要后端支持 )

方案1 *:通配符,全部允许,存在安全隐患(不推荐)。

一旦启用本方法,表示任何域名皆可直接跨域请求: 1 server { 2 ... 3 location / { 4 # 允许 所有头部 所有域 所有方法 5 add_header 'Access-Control-Allow-Origin' '*'; 6 add_header 'Access-Control-Allow-Headers' '*'; 7 add_header 'Access-Control-Allow-Methods' '*'; 8 # OPTIONS 直接返回204 9 if ($request_method = 'OPTIONS') { 10 return 204; 11 } 12 } 13 ... 14 }

方案2:多域名配置(推荐)

配置多个域名在map中 只有配置过的允许跨域:

map $http_origin $corsHost { 2 default 0; 3 "~https://zzzmh.cn" https://zzzmh.cn; 4 "~https://chrome.zzzmh.cn" https://chrome.zzzmh.cn; 5 "~https://bz.zzzmh.cn" https://bz.zzzmh.cn; 6 } 7 server { 8 ... 9 location / { 10 # 允许 所有头部 所有$corsHost域 所有方法 11 add_header 'Access-Control-Allow-Origin' $corsHost; 12 add_header 'Access-Control-Allow-Headers' '*'; 13 add_header 'Access-Control-Allow-Methods' '*'; 14 # OPTIONS 直接返回204 15 if ($request_method = 'OPTIONS') { 16 return 204; 17 } 18 } 19 ... 20 } 4.5.3. webpack plugin (插件)

npm i -S webpack-dev-middleware 安装中间键,把前端和后端的服务绑在一起

中间件 let webpack = require('webpack') let middle = require('webpack-dev-middleware') let compiler = webpack(require('./webpack.config.js')) app.use(middle(compiler)) 4.5.4. cors (后端解决) var allowCrossDomain = function(req,res,next) { // 请求源 res.header("Access-Control-Allow-Origin", "*") // 请求头 token res.header("Access-Control-Allow-Headers", "*") // 请求方法 get post put del res.header("Access-Control-Allow-Methods", "*") next(); } app.use(allowCrossDomain ) 4.6 git命令(实际工作中常用) 4.6.1 基本 1. git init 初始化git仓库 (mac中Command+Shift+. 可以显示隐藏文件) 2. git status 查看文件状态 3. git add 文件列表 追踪文件 4. git commit -m 提交信息 向仓库中提交代码 5. git log 查看提交记录 4.6.2 分支明细 (1)主分支(master):第一次向 git 仓库中提交更新记录时自动产生的一个分支。 (2)开发分支(develop):作为开发的分支,基于 master 分支创建。 (3)功能分支(feature):作为开发具体功能的分支,基于开发分支创建 4.6.3 分支命令 (1)git branch 查看分支 (2)git branch 分支名称 创建分支 (3)git checkout 分支名称 切换分支 (4)git merge 来源分支 合并分支 (备注:必须在master分支上才能合并develop分支) (5)git branch -d 分支名称 删除分支(分支被合并后才允许删除)(-D 强制删除) 4.6.4 暂时保存更改的代码 (1)存储临时改动:git stash (2)恢复改动:git stash pop 4.6.5 代码回退 git reset --soft HEAD~n 4.7 get与post请求有什么区别 get是从服务器上获取数据,post是向服务器传送数据。 POST比GET安全,因为数据在地址栏上不可见。 get方式提交的数据最多只能有1024字节,而post则没有此限制。 GET使用URL或Cookie传参。而POST将数据放在request BODY中。 GET与POST都有自己的语义,不能随便混用。

据研究,在网络环境好的情况下,发一次包的时间和发两次包的时间差别基,本可以无视。而在网 络环境差的情况下,两次包的TCP在验证数据包完整 性上,有非常大的优点。post 发送两次,get 只发送一次。

4.8 cookie、localStorage、sessionStorage的区别

共同点: 都是保存在浏览器端、且同源的

不同点:

cookie数据始终在同源的http请求中携带(即使不需要),即cookie在浏览器和服务器间来回传递。cookie数据还有路径(path)的概念,可以限制cookie只属于某个路径下sessionStorage和localStorage不会自动把数据发送给服务器,仅在本地保存。

存储大小限制也不同:

cookie数据不能超过4K,sessionStorage和localStorage可以达到5M

sessionStorage:仅在当前浏览器窗口关闭之前有效;

localStorage:始终有效,窗口或浏览器关闭也一直保存,本地存储,因此用作持久数据;

cookie:只在设置的cookie过期时间之前有效,即使窗口关闭或浏览器关闭

作用域不同

sessionStorage:不在不同的浏览器窗口中共享,即使是同一个页面;

localstorage:在所有同源窗口中都是共享的;也就是说只要浏览器不关闭,数据仍然存在

cookie: 也是在所有同源窗口中都是共享的.也就是说只要浏览器不关闭,数据仍然存在

4.9 async 和 await 的区别

区别:

async是来定义函数的,定义异步函数,打印函数名可以得到一个promise对象,言外之意可以通过这个 函数名称.then 这个方法

await 后面跟的是任意表达式,一般使用promise的表达式

async 内部实现,有返回值 成功返回promise.resolve() ,出错返回promise.reject() 返回值用catch捕获

await 等待后面的promise对象执行完毕,拿到了promise.resolve()的值之后,执行后面的代码。await后面的表达式,能是promise.reject(),所以建议await放在try…catch语句中

优点:async和await 属于es7语法。编写方便,提高程序效率,避免了回调地狱

补充:promise和async和await的区别

promise es6语法,promise中包含catch,async需要自己定义catch

promise 提供的方法会多一些,all、race等方法,aync中是没有的。

5.0 setTimeout 时间为0, 以及误差的原因 setTimeout,如果时间为0,则会立即插入队列,不是立即执行,等待前面的代码执行完毕。 5.1 求数组的最大值? function getMaxArryNum(arr) { return Math.max(...arr) } getMaxArryNum([1,2,3,4,5,6]) 5.2 求数组的最小值? const getMinArryNum= (arr) => { return Math.min(...arr) } getMinArryNum([1,2,3,4,5,6]) 5.3 数组去重 5.3.1 利用filter 、indexof const removeEqual = (arr) => { const result = arr.filter((item, index, self) => { return self.indexof(item) === index }) return result } removeEqual([1, 2, 2, 3, 4, 5, 5, 6, 7, 7])

第一次循环,传入元素1,index(1)的索引为0,而此时1的索引本来就是0,OK,满足。 第二次循环,传入元素2,index(2)的索引为1,而此时2的索引也是1,OK,也满足。 第三次循环,传入元素2,index(2)的索引为1,而此时2的索引为2,OK,不满足,被PASS,这里就是巧妙的借用了indexOf始终查找到第一次出现的位置。 总结 filter(x,index,self)可以为数组提供过滤功能,其中x代表元素,index是与X一同传入元素的索引,而self代表数组本身。 14. 生成从0 到 指定数字的数组

5.3.2 sort 、splice 实现去重

先对数组进行排序,再循环,如果相邻的两项相同,则删除一项,i–,再继续对比。

var arr = [1, 2, 3, 2, 4, 1]; arr.sort(); for (var i = 0; i < arr.length; i++) { if (arr[i] === arr[i+1]) { arr.splice(i,1); i--; } } console.log(arr); // [1, 2, 3, 4] 5.3.3 最短的方法,使用new Set([…])

var arr = [1, 2, 3, 2, 4, 1]; var newArr = new Set(arr);

console.log(newArr); // [1, 2, 3, 4];

5.3.4 indexOf 、push 实现

最简单的思路,先创建一个新数组作为容器,遍历原数组,判断每一项在新数组中是否存在,若不存在则把这一项push到新数组中,若存在则忽略。

var arr = [1, 2, 3, 2, 4, 1]; var newArr = []; for (var i = 0; i < arr.length; i++) { if (newArr.indexOf(arr[i]) === -1) { newArr.push(arr[i]); } } console.log(newArr); // [1, 2, 3, 4] 5.3.5 对象属性名唯一性实现 数组去重

利用对象的属性名不能重复这一特性,创建一个对象,把数组中的值依次添加为对象的属性,再使用Object.keys()得到包含所有属性名的数组。但要注意对象的属性名都是字符串形式,所以在本例中还要把它们转回数字。

var arr = [1, 2, 3, 2, 4, 1]; var obj = {}; var res = []; arr.forEach(n => obj[n] = 1); // 把每一项添加为对象的属性,重复的属性不会再次添加,而是修改已存在的属性的值 res = Object.keys(obj).map(n => +n); // 得到包含字符串属性名的数组并把每一项转换成数字 console.log(res); // [1, 2, 3, 4] 5.4. 数组求和 const arrSum = (arr) => { const temp = arr.reduce((pre, now) => { return pre+now },0) return temp } arrSum([1,2,3,4]) 5.5 生成从0 到 指定数字的数组 const getArr = (startNum, endNum) => { let arr = [] for(var i=startNum; i setup() created -> setup() beforeMount -> onBeforeMount mounted -> onMounted beforeUpdate -> onBeforeUpdate updated -> onUpdated beforeDestroy -> onBeforeUnmount destroyed -> onUnmounted activated -> onActivated deactivated -> onDeactivated 对文件上的引用 vue2 中new出的实例对象,所有的东西都在vue对象上,无论是否用到,都是跑一边 vue3.0中可以用ES module imports按需引入,如:keep-alive内置组件、v-model指令,等等。项目启动方式 vue2 是 npm run dev vue3 是 npm run serve语法上的区别 取消v-model,采用modelValue

弃用全局API new Vue 采用 createAPP

const app = Vue.creatApp()

不能使用vue.nextTick()或this.$nextTick(),改用如下:

import { nextTick } from 'vue' nextTick(() => { // something }) 6.7 call、apply、bind使用和区别

call作用: 语法: fun.call(thisArg, arg1,arg2, …) thisArg: fun函数运行时指定的this值; arg1,arg2参数;返回值是函数的返回值

调用函数改变this指向 const obj = {name: 'red'} function fn(x, y) { console.log(this) console.log(x+y) // 3 } fn.call() // 此时this指向为window fn.call(obj, 1, 2) //此时this指向为obj

apply作用: 语法: fun.apply(thisArg, [argsArray]) thisArg: fun函数运行时指定的this值;argsArray数组参数,传递的值必须在数组里面;返回值是函数的返回值

调用函数改变this指向 const obj = {name: 'red'} function fn(x, y) { console.log(this) console.log(x+y) // 3 } fn.apply() // 此时this指向为window fn.apply(obj, [1, 2]) //此时this指向为obj

apply主要和数组有关系,可以使用Math.max()求数组最大值等 // const max = Math.max(1, 2, 3) const max = Math.max.apply(Math, [1,2,3])

bind作用: 语法:fun.bind(thisArg, arg1, arg2, …) thisArg: fun函数运行时指定的this值;arg1, arg2传递的参数;返回值是拷贝后的新函数,且this更改过 注意:不会调用函数,但是可以改变this指向

const obj = {name: 'tiger'} function fn() { console.log(this) } const fun = fn.bind(obj) console.log(fun) // 打印出来是fn()函数,但是this指向obj fun()

总结: 相同点: 三者都可以改变this的指向 不同点: call和apply 可以调用函数 call和apply,传递的参数不同,call是以arg1,arg2形式传递,apply是以数组形式传递[argsArr] bind不会调用函数



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有