面试题整理2022/6/22

什么是纯函数,什么是函数的副作用

  • 简单来说,一个函数的返回结果只依赖于它的参数,并且在执行过程里面没有副作用,我们就把这个函数叫做纯函数。(输入的参数确定, 则输出的参数也可以确定)
  • 副作用是和纯函数的相对应的概念。副作用让一个函数变得不纯,它是产生非纯函数的一个主要因素。纯函数的根据相同输入始终有相同输出,如果依赖于外部状态,就无法保证输出相同就会产生副作用让函数变得不纯。

深拷贝和浅拷贝

前提知识

  • 基本数据类型 (名值存储在栈内存中)
    • 有哪些,number,string,boolean,null,undefined,symbol以及未来ES10新增的BigInt(任意精度整数)七类
    • 基本数据类型是指存放在栈中的简单数据段(保存的就是数据本身),数据大小确定,内存空间大小可以分配,它们是直接按值存放的,所以可以直接按值访问
  • 引用数据类型 (名存在栈内存中,值存在于堆内存中)
    • 有哪些,对象(Object)、数组(Array)、函数(Function),还有两个特殊的对象:正则(RegExp)和日期(Date)
    • 对象是保存到堆内存中的,每创建一个新的对象,就会在堆内存中开辟出一个新的空间, 而变量保存的是对象的内存地址(对象的引用)
    • 如果两个变量保存的是同一个对象引用,当一个通过一个变量修改属性时,另一个也会受到影响

概念

  • 浅拷贝: 拷贝对象的一层属性,如果对象里面还有对象,拷贝的是地址, 两者之间修改会有影响,适用于对象里面属性的值是简单数据类型的.(只拷贝一层)
  • 深拷贝: 拷贝对象的多层属性,如果对象里面还有对象,会继续拷贝,使用递归去实现. (层层拷贝),
  • 深拷贝是会在堆内存中重新开辟一块空间进行存放, 简单来说判断的标准就是: B复制了A,如果A发生了改变,如果B随之变化,那么是浅拷贝,如果B并没有发生变化,则是深拷贝。

实现

浅拷贝
  • 数组 cancat() slice() 只能实现一维数组的深拷贝, 不能对多维数组进行深拷贝
//  concat()
let list = ['a','b','c'];
let list2 = list.concat();
list2.push('d')
console.log(list);//['a','b','c']
console.log(list2);//['a','b','c','d']

//  slice()
let list = ['a','b','c'];
let list2 = list.slice();
list2.push('d')
console.log(list);//['a','b','c']
console.log(list2);//['a','b','c','d']

//二维数组
let list = ['a','b','c',['d','e','f']];
let list2 = list.concat();
list2[3][0] = 'a';
console.log(list); //['a', 'b', 'c',['a', 'e', 'f']]
console.log(list2); //['a', 'b', 'c',['a', 'e', 'f']]
  • 对象 new Object() 和 Object.assing() 只拷贝第一层, 但是更深的层级不属于深拷贝
let a = {id:1,name:'a',obj:{id:999}};
function fun(obj){
    let o = {};
    Object.assign(o,obj);
    return o;
}
let a2 = fun(a);
a2.name ='a2';
a2.obj.id = 888;
console.log(a); //{id: 1, name: 'a', obj: {id:888}}
console.log(a2);//{id: 1, name: 'a2', obj: {id:888}}
  • JSON.parse(JSON.stringify( )) 对于一层和多层都能实现深拷贝,但是这个方法的缺陷是不能拷贝Function,所以在使用时,一定要注意数据类型。
let a = {
    name : 'a',
    age : 20,
    obj : {id:999},
    action : function(){
        console.log(this.name);
    }
}
let b = JSON.parse(JSON.stringify(a));
a.name = 'b';
a.obj.id = 888;
console.log(a); //{name: 'b', age: 20, obj: {id:888}, action: ƒ}
console.log(b); //{name: 'a', age: 20, obj: {id:999}}
  • 展开运算符 -> 能实现对象数组单层时的深拷贝,但是多层无法实现深拷贝。
let a = {name:'a',id:99};//如果是数组[xx,xx,xx],{...a}需要改成[...a]
let b ={...a};  //[...a]
a.id =88;
console.log(a); // {name:"a",id:88}
console.log(b); // {name:"a",id:99}
深拷贝
  • 递归实现(手写)
let a = {
  name:'a',
  skin:["red","blue","yellow",["123","456"]],
  child:{
    work:'none',
    obj:{
      id:999
    }
  },
  action:function(){
    console.log(this.name);
  }
}
//封装的递归方法
function copyWid(obj){
  let newObj = Array.isArray(obj)?[]:{};
  for (var i in obj){
    if(typeof obj[i] === 'object'){  //判断是不是对象(数组或对象)
      newObj[i] = copyWid(obj[i])  //递归解决多层拷贝
    }else{
      newObj[i] = obj[i]   
    }
  }
  return newObj;
};

let b = copyWid(a);
b.child.obj.id =888;
b.skin[3][0] = "pink";
console.log(a);
console.log(b);
  • lodash插件的_.cloneDeep
var _ = require('lodash');
var obj1 = {
    a: 1,
    b: { f: { g: 1 } },
    c: [1, 2, 3]
};
var obj2 = _.cloneDeep(obj1);
console.log(obj1.b.f === obj2.b.f);// false
  • Immutable

实现的原理是持久化数据结构( Persistent Data Structure),也就是使用旧数据创建新数据时,要保证旧数据同时可用且不变。

html中meta标签

  • <meta> 元素可提供有关页面的元信息(meta-information),比如针对搜索引擎和更新频度的描述和关键词, 可以定义文档的各种元数据,提供各种文档信息,通俗点说就是可以理解为提供了关于网站的各种信息

  • //name用来表示元数据的类型,表示当前<meta>标签的具体作用;content属性用来提供值
    <meta name="参数" content="具体描述信息">
    
<!-- 定义文档的字符编码 -->
<meta charset="utf-8" /> 
<!-- 
    设置视窗大小
    width	设置layout viewport  的宽度,为一个正整数,或字符串"width-device"
    initial-scale	设置页面的初始缩放值,为一个数字,可以带小数
    minimum-scale	允许用户的最小缩放值,为一个数字,可以带小数
    maximum-scale	允许用户的最大缩放值,为一个数字,可以带小数
	shrink-to-fit=no IOS9中要想前面的属性起作用需要加上这个
    height	设置layout viewport  的高度,这个属性对我们并不重要,很少使用
    user-scalable	是否允许用户进行缩放,值为"no"或"yes", no 代表不允许,yes代表允许
-->
<meta name="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit=no, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no"/>
<!-- 页面描述 -->
<meta name="description" content="不超过150个字符"/>
<!-- 页面关键词 -->
<meta name="keywords" content=""/>
<!-- 网页作者 -->
<meta name="author" content="name, email@gmail.com"/>
<!-- 
    搜索引擎抓取
    all:文件将被检索,且页面上的链接可以被查询; 
    none:文件将不被检索,且页面上的链接不可以被查询;
    index:文件将被检索; 
    follow:页面上的链接可以被查询; 
    noindex:文件将不被检索; 
    nofollow:页面上的链接不可以被查询。 
-->
<meta name="robots" content="index,follow"/>
<!-- 忽略页面中的数字识别为电话,忽略email识别-->
<meta name="format-detection" content="telphone=no, email=no"/>

vue中的过滤器, vue3中可以使用过滤器吗

  • 定义: 过滤器是vue中的一个特性,作用是用于对文本进行格式化的作用 ( 在不改变原数据的前提下,对数据进行一定程度的处理,在返回并显示在页面上 )

  • 使用位置: 过滤器只能应用在两个地方:双花括号插值v-bind表达式 (通过管道符(|)来连接)

    <!--在双花括号中使用 格式:{{值 | 过滤器的名称}}-->
    <div>{{3 | addZero}}</div>
    <!--在v-bind中使用 格式:v-bind:id="值 | 过滤器的名称"-->
    <div v-bind:id="1 | addZero">11</div>
    
  • 分类: 全局过滤器和本地过滤器

  • 开发场景:

    • 全局过滤器经常会被在数据修饰上,通常我们把处理函数给抽离出去,统一放在一个.js文件中, 在全局或者组件中引入并使用
    • 格式化日期等

vue项目中token存储的实现

  1. 用户登录时,前端调用后台提供的登录接口;

  2. 后台验证用户名和密码,验证通过后给前端返回token;

  3. 前端解析token后,将token存储在localStorage和vuex,跳转到项目首页;

  4. 实现一:前端在发起请求时,每次发送数据请求时在拦截其中携带token给后台进行验证,不管是本地token被改动,或者是已经过期,均把token放在请求头header里抛给后台来判断和处理,如果是过期的token,后台返回对应的状态码,清除本地token信息,跳转到登录页面。

    实现二:前端在路由跳转,或者发送请求前,先判断localStorage中token是否还存在(是否过期),不存在就清除本地token信息,直接跳转到登录页面。如果还存在就继续将token放在请求的请求头header里面,如果token已过期,后台返回对应的状态码,清除本地token信息,跳转到登录页面。

cookie和WebStorage的区别

  • cookie: cookie 是浏览器 为了 标识用户身份 或者 长时间存储一些信息 而保存在用户本地的数据(其本质是为了提升用户体验而存储来用户本地的数据)
  • WebStorage的目的是克服由cookie所带来的一些限制, WebStorage提供了两种API:localStorage(本地存储)和sessionStorage(会话存储)
    • localStorage: 生命周期是永久的,关闭页面或浏览器之后localStorage中的数据也不会消失, localStorage除非主动删除数据,否则数据永远不会消失
    • sessionStorage是在同源(同一个域名下)的窗口中始终存在的数据。sessionStorage的生命周期是仅在当前会话下有效,关闭会话窗口就失效了 (同网站,同窗口), 只要这个浏览器窗口没有关闭,即使刷新页面或者进入同源(同一个服务器目录/相同的网站)另一个页面,数据依然存在。但是sessionStorage在关闭了浏览器窗口后就会被销毁
  • 区别:
    • 使用场景: localStorage一般用于长期登陆且判断用户是否已登陆, 适合长期保存在本地的数据; 而sessionStorage一般用于敏感账号一次性登录
    • 存储大小: cookie的存储大小只有4K, 而sessionStorage和localStorage都有5M
    • 生命周期: cookie默认浏览器关闭时就过期,设置过期时间之后,等到指定日期之后过期; localStorage除非主动删除数据,否则数据永远不会消失; sessionStorage只要这个浏览器窗口没有关闭,即使刷新页面或者进入同源(同一个服务器目录下)另一个页面,数据依然存在

vuex的数据如何做到刷新页面不丢失

  • 问题描述: 一般在登录成功的时候需要把用户信息,菜单信息放置vuex中,作为全局的共享数据。但是在页面刷新的时候vuex里的数据会重新初始化,导致数据丢失。因为vuex里的数据是保存在运行内存中的,当页面刷新时,页面会重新加载vue实例,vuex里面的数据就会被重新赋值。
  • 解决思路1: 将vuex中数据直接保存到浏览器端的缓存中 ( 缺点是不安全,不适用大数据量的存储;)
  • 解决思路2: 在页面刷新的时候再次请求远程数据,使之动态更新vuex数据 ( 适用于少量的数据,并且不会出现网络延迟 )
  • 解决思路3: 在父页面向后台请求远程数据,并且在页面刷新前将vuex的数据先保存至sessionStorage(以防请求数据量过大页面加载时拿不到返回的数据)

对vuex的理解

  • 概念: Vuex是实现组件全局状态(数据)管理的一种机制,可以方便的实现组件之间数据的共享。可以理解为:将多个组件共享的变量全部存储在一个对象里面,然后将这个对象放在顶层的 Vue 实例中,让其他组件可以使用,它最大的特点是响应式。
  • 适用条件: 多个视图依赖于同一个状态来, 自不同视图的行为需要变更同一个状态

核心概念

state 数据源
  • 保存全局数据, 在一个项目中只使用一个store对象,来存储所有共享的状态信息
  • 数据的访问:
    • this.$store.state.全局数据名称访问
    • mapState映射为计算属性(vue3中没有), 直接可以使用该计算属性
  • 数据的修改:
    • 先拿到 store 对象,然后通过 commit 提交 mutations 中的方法
getters 计算属性
  • Getter 用于对 Store中的数据进行加工处理形成新的数据,Store中数据发生变化, Getter 的数据也会跟着变化。在数据展示前进行一些变化处理,具有缓存功能,能够提高运行效率
  • 访问:
    • this.$store.getters.名称
    • mapGetters 映射为计算属性(vue3中没有)
mutation同步方法
  • mutations 对象中保存着更改数据的回调函数,该函数名官方规定叫 type, 组件中不允许直接修改全局的数据, mutation用于变更store中的数据 (可以集中监控所有数据的变化)
  • 触发:
    • this.$store.commit()
    • MapMutations 映射为当前组件的methods方法(vue3中没有)
action 异步方法
  • 如果通过异步操作变更数据,必须通过 Action, 而不能使用Mutation,但是在 Action中不能直接修改 state中的数据,还是要通过触发Mutation的方式间接变更数据
  • 触发:
    • this.$store.dispatch('方法名','参数') 触发 Actions
    • mapActions 映射为methods方法(vue3中)
module 模块
  • 目的:让代码更好维护,让多种数据分类更加明确。
  • 使用注意: 要在组件中开启命名空间, 然后在store的modules中声明

对于vue中首屏页面加载慢的解决方法

  • 问题: 第一次打包vue的项目部署到服务器下时,发现初次加载特别的缓慢,将近20s页面才加载出来,完全没有开发环境上的那么流畅。主要原因是页面在打包后如果不进行相关配置会导致资源文件特别的大,一次想要全部加载完成会特别的耗时。
  • (1) 安装插件 webpack-bundle-analyzer => 并在vue.config.js中配置 => 在启动项目 npm run serve 可以看到下面的图片 里面有每个资源的大小
  • (2) 使用路由懒加载可以实现部分优化(需要的时候才加载)
  • (3) 使用CDN引入需要的库 (专门挂在静态资源的)
  • (4) 丢弃map文件 (.map文件的作用:项目打包后,代码都是经过压缩加密的,如果运行时报错,输出的错误信息无法准确得知是哪里的代码报错,有了map就可以像未加密的代码一样,准确的输出是哪一行哪一列有错) , 生产环境打包一般需要禁止map输出,map文件会造成项目源码泄漏,可以进行丢弃(增加配置 productionSourceMap: false)
  • (5) js压缩处理 (使用插件 compression-webpack-plugin@5 )
  • (6) 利用服务器进行 gzip 的提速

防抖和节流的原理

  • 防抖和节流的原理都使用到了闭包的概念:闭包的好处是里面的变量只会在闭包中使用,也就是外部的函数是不能使用这个变量的,也就不会修改这个变量,就不会受到外部的污染

防抖:

  • 事件高频率触发时只触发最后一次 (短时间内触发了多个setTimeout只会执行最后一个)
  • 实现: 再执行setTimeout之前,先使用clearTimeout()把上一次定时器给清除掉,这样就达到了只会执行最后一次触发的setTimeout
//连续触发 => 每一次点击全都会被触发
$("button").click(function () {
  console.log("准备提交数据");
});

// 优化1: 普通版 => 利用延时器来设置事件触发到反应的间隔时间
// 如果在这一次的事件发生之前再次点击,整个延时器被删除,上一个事件就没了,只会发生最后一次
var timer = null;
$("button").click(function () {
  clearTimeout(timer); //在这次点击事件触发之前清除之前计时器的干扰
  timer = setTimeout(function () {
    console.log("准备提交数据");
  }, 500);
});

// 优化2: 闭包版 => 利用匿名函数自执行(页面加载时就执行了),直接得到的返回值是一个函数(点击时调用)
$("button").click(
  (function () {
    var timer = null;
    return function () {
      clearTimeout(timer);
      timer = setTimeout(function () {
        console.log("准备提交数据");
      }, 300);
    };
  })()
);

// 优化3: 闭包封装函数版
var func = debounceFn(function (e) {
  console.log(this);
}, 1000);
console.log(func); //得到的func是debounceFn所return的匿名函数
$("button").click(func);

function debounceFn(callback, delay = 300) {
  //callback是点击后执行的事件 delay是事件延迟的间隔时间(默认为300ms)
  var timer = null;
  return function (...list) {
    // 传入 ...list = 1,2,3,4,5,6,7 => 返回 list = [1, 2, 3, 4, 5, 6, 7]
    // 此时this->事件触发的元素
    clearTimeout(timer);
    var _this = this;
    timer = setTimeout(function () {
      //延时器中this->window => 利用中间变量和apply改变this指向
      callback.apply(_this, list);
    }, delay);
  };
}

节流

  • 事件高频率触发时降低触发频率 (短时间内触发多个setTimeout,只会执行第一个,当第一个执行完后,才可以继续触发后面的setTimeout)
  • 实现: 在第一次触发了setTimeout后,先把阀门关闭(使用一个Boolean变量),等执行完后再把阀门打开,这样后面的setTimeou在触发前会先判断阀门是否关闭,如果关闭了则不会继续触发,要等之前的setTimout执行完后,才允许触发后面的setTimeout
// 无优化版 => 无论页面多么细小的滚动都会触发事件
$(window).scroll(function () {
  console.log("正在滚动");
});

// 优化1: 基本版 => 设定一个指定的时间差来降低出发的频率
var start = Date.now(); // 页面加载时的起始时间(ms)
$(window).scroll(function () {
  var now = Date.now(); // 滚动的当前时间(ms)
  if (now - start >= 300) {
    //只有达到了一定时间触发事件后执行的操作函数才会生效
    console.log("正在滚动");
    start = now; //为下次滚动作准备
  }
});

// 优化1: 闭包版 => 匿名函数自调用返回一个函数
$(window).scroll(
  (function () {
    var start = Date.now(); // 页面加载时的起始时间
    return function () {
      var now = Date.now(); // 滚动的当前时间
      if (now - start >= 300) {
        console.log("正在滚动");
        start = now; //为下次滚动作准备
      }
    };
  })()
);

// 优化2: 闭包函数封装版
function throttleFn(callback, delay = 300) {
  var start = Date.now(); // 页面加载时的起始时间
  return function (...list) {
    var now = Date.now(); // 滚动的当前时间
    if (now - start >= delay) {
      callback.apply(this, list);
      start = now; //为下次滚动作准备
    }
  };
}
$(window).scroll(
  throttleFn(function () {
    console.log("正在滚动");
  }, 1000)
);

说一下闭包

  • 闭包是指有权访问另一个函数作用域中的变量的函数, 简单的来说就是一个函数在执行过程中返回另一个函数/对象(引用类型且一般都是函数) => 可以在函数外变相的访问函数内的变量
  • 作用域: 函数在执行过程中的有效区域

  • 作用域链: 在内部函数可以访问外部函数变量的这种机制,用链式查找决定哪些数据能被内部函数访问

  • 闭包的优缺点:
    • 函数关联的活动对象 不会被销毁
      优点: 空间中的内容永远存在(可以长时间存储AO对象)
      缺点: 会占用大量的内存空间,造成内存泄露
    • 可以从函数外部调用,使用函数内部的数据
      优点: 调用数据更加方便
      缺点: 容易泄露数据信息,不安全
    • 保护私有变量(减少全局变量的使用)
      优点: 私有变量,不会被销毁
      缺点: 私有变量存储占用空间
  • 闭包的应用: 多元素绑定事件, 函数防抖, 函数节流等

render函数能使用setState()吗

render函数应该是一个纯函数,完全根据this.state和this.props来决定返回的结果,而且不要产生任何副作用。
在render函数中去调用this.setState是错误的,因为一个纯函数不应该引起状态的变化。

render函数并不做实际的渲染动作,它只负责返回一个JSX描述的结构,最终由React来操作渲染过程。

对promise的理解

  • 产生背景: 回调函数噩梦(恐怖回调),也被称为恶魔金字塔,例如ajax依赖调用时,回调函数会层层嵌套,而这种层层嵌套的写法,往往会让人难以理解,所以称之为噩梦。

  • Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大。

  • Promise对象代表一个异步操作,有三种状态:

    • Pending(进行中)
    • Resolved(已完成,又称Fulfilled)
    • Rejected(已失败)
  • 工作流程: Promise构造函数接受一个函数作为参数,该函数的两个参数分别是resolve和reject。它们是两个函数,由 JavaScript 引擎提供,不用自己部署。resolve函数的作用是,将Promise对象的状态从“未完成”变为“成功”(即从 pending 变为 resolved),在异步操作成功时调用,并将异步操作的结果,作为参数传递出去;reject函数的作用是,将Promise对象的状态从“未完成”变为“失败”(即从 pending 变为 rejected),在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去。总结: 官方提供改变状态的方法 resolve,reject, 除了可以改变状态,还可以将数据存储到Promise对象中 => 传递出去

  • Promise的优缺点:

    • 优点: 有了Promise对象,就可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数
    • 缺点:
      • 无法取消Promise,一旦新建它就会立即执行,无法中途取消。
      • 如果不设置回调函数,Promise内部抛出的错误,不会反应到外部。(直接报错)
      • 当处于pending状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)

vue中路由的模式及其区别

hash模式 (默认)
  1. 使用URL的hash值来作为路由。支持所有浏览器。
  2. url地址中带有#, 使用 URL 的 hash 来模拟一个完整的 URL,于是当 URL 改变时,页面不会重新加载,其显示的网路路径中会有 “#” 号, 这是最安全的模式,因为他兼容所有的浏览器和服务器。
  3. 不能随意的修改path地址
  4. 在 HTTP 请求中,对后端完全没有影响,因此改变 hash 不会重新加载页面。
history模式
  1. 整个地址重新加载,可以保存历史记录,方便前进后退
  2. 使用 HTML5 API(旧浏览器不支持)和 HTTP服务端配置,没有后台配置的话,页面刷新时会出现404
  3. 可以随意修改path地址,可以进入404
总结
  • hash 模式和 history 模式都属于浏览器自身的特性,Vue-Router 只是利用了这两个特性(通过调用浏览器提供的接口)来实现前端路由.
  • hash 模式下,仅 hash 符号之前的内容会被包含在请求中,如 http://www.abc.com,因此对于后端来说,即使没有做到对路由的全覆盖,也不会返回 404 错误。
  • history 模式下,前端的 URL 必须和实际向后端发起请求的 URL 一致,如 http://www.abc.com/book/id。如果后端缺少对 /book/id 的路由处理,将返回 404 错误。Vue-Router 官网里如此描述:“不过这种模式要玩好,还需要后台配置支持……所以呢,你要在服务端增加一个覆盖所有情况的候选资源:如果 URL 匹配不到任何静态资源,则应该返回同一个 index.html 页面,这个页面就是你 app 依赖的页面。”
  • 结合自身例子,对于一般的 Vue + Vue-Router + Webpack + XXX 形式的 Web 开发场景,用 history 模式即可,只需在后端(Apache 或 Nginx)进行简单的路由配置,同时搭配前端路由的 404 页面支持。

websocket和http的区别

  • WebSocket概念:

    • WebSocket 是 HTML5 开始提供的一种在单个 TCP 连接上进行全双工通讯的协议。WebSocket 使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。

    • 在 WebSocket API 中,浏览器和服务器只需要做一个握手的动作,然后,浏览器和服务器之间就形成了一条快速通道。两者之间就直接可以数据互相传送。

    • WebSocket 的最大特点就是,服务器可以主动向客户端推送信息,客户端也可以主动向服务器发送信息,是真正的双向平等对话。浏览器通过 JavaScript 向服务器发出建立 WebSocket 连接的请求,连接建立以后,客户端和服务器端就可以通过 TCP 连接直接交换数据。当你获取 Web Socket 连接后,你可以通过 send() 方法来向服务器发送数据,并通过 onmessage 事件来接收服务器返回的数据。

  • 与http的区别

    • WebSocket是双向通信协议,模拟Socket协议,可以双向发送或接受信息,而HTTP是单向的
    • WebSocket是需要浏览器和服务器握手进行建立连接的,而http是浏览器发起向服务器的连接

set和map

  • set和map是ES6新增的数据结构, 最大优点就是运行时间少大大提高了性能。
  • map和set一样是关联式容器,它们的底层容器都是红黑树
set
  • 概念: 类似于数组,但是成员的值都是唯一的,没有重复的值(用于去重)。Set本身是一个构造函数,用来生成 Set 数据结构。(var s = new Set(); ) 常用于数组去重
  • 常用方法:
    • add() 向set结构中添加一个成员 (返回值:原本的set结构=>是同种类型的数据=>可以链式操作)
    • delete() 删除set结构中的指定成员(单删) (返回值:删除成功返回true,删除失败返回false)
    • clear() 清空set数据结构
    • has() 判断set结构中是否存在某个成员/元素
map
  • 概念: Map 数据结构类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键值 (var m = new Map()😉

vue中插槽的作用

  • 插槽就是子组件中的提供给父组件使用的一个占位符,用 表示,父组件可以在这个占位符中填充任何模板代码,如 HTML、组件等,填充的内容会替换子组件的标签。(如果子组件没有使用插槽,父组件如果需要往子组件中填充模板或者html, 是没法做到的)
//在子组件中放一个占位符
<template>
    <div>
        <h1>今天天气状况:</h1>
        <slot></slot>
    </div>
</template>
<script>
    export default {
        name: 'child'
    }
</script>

//在父组件中给这个占位符填充内容
<template>
    <div>
        <div>使用slot分发内容</div>
        <div>
            <child>
                <div style="margin-top: 30px">多云,最高气温34度,最低气温28度,微风</div>
            </child>
        </div>
    </div>
</template>
<script>
    import child from "./child.vue";
    export default {
        name: 'father',
        components:{
            child
        }
    }
</script>

vue中的计算属性能接受参数吗

  • computed计算属性的概念: 要用的属性不存在,要通过已有属性计算得来
  • 原理:底层借助了Objcet.defineProperty方法提供的getter和setter
  • get函数什么时候执行?
    • (1).初次读取时会执行一次
    • (2).当依赖的数据发生改变时会被再次调用
  • 优势:与methods实现相比,内部有缓存机制(复用),效率更高,调试方便
  • 计算属性默认是无法传递参数的,
  • 主要用于对当前文件组件的数据(data/props),进行操作,缓存当前计算属性的依赖, 而有些情况需要使用到计算属性来传递参数,可以使用**闭包函数
posted @ 2022-06-22 11:55  嘻嘻不是菜鸟了  阅读(50)  评论(0)    收藏  举报