前端面试题

149 阅读29分钟

如下内容均为各平台资料集成,只做学习用途!

javascript有哪些垃圾回收机制?

标记清除
最常见的立即回收方式,首先它会遍历内存上所有的对象,分别给他们标记,然后在代码执行完成后,对所有使用过过的变量取消标记,把具有标记的内存对象进行整体清除,从而释放内存空间

引用计数
当声明一个变量并将这个引用类型赋值给该变量的时候,这个值的引用次数就+1,如果该变量的值变成了另一个,则这个值的引用次数-1,当这个值引用次数变为0的时候,说明没有变量在使用,这个值没法被访问,此时就可以放心地将其清除并回收内存

谈谈script标签中defer和async属性的区别

defer属性规定是否延迟执行脚本,直到页面加载为止,是并行执行,async属性规定脚本一旦可用就异步执行

call和apply的区别是什么?

作用都是在函数执行的时候,动态改变函数的运行环境(执行上下文)

  • call从第二个参数开始,每一个参数都会依次传递给调用函数
  • apply的第二个参数是数组,数组的每一个成员会依次传递给调用函数

如何实现异步编程?

通过Promise实现,它的思想是,每一个异步任务返回一个Promise对象,该对象有一个then方法,允许指定回调函数

请解释一下javascript的同源策略?

同源策略是指协议、域名、端口相同。同源策略是一种安全协议,指一段脚本只能读取来自同一来源的窗口文档和文档属性

MVC\MVVM?

  • MVC即model-view-controller,是项目的一种分层架构思想,它把复杂的业务逻辑,抽离成职能单一的小模块,它保证了模块的智能单一性,方便程序的开发,维护,耦合度低
  • MVVM即model-view-viewModel,它是一种是双向数据绑定的模式,用viewModel来建立起model数据层和view视图层的链接,数据改变会影响视图,视图改变会影响数据

vue双向数据绑定原理?

vue.js是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性setter,getter, 在数据变动时发布消息给订阅者,触发相应的监听回调。

  1. 需要observe的数据对象进行递归遍历。包括子属性对象的属性,都加上getter和setter,这样的话,给这个对象的某个值赋值,就会触发setter,那么就能监听到数据变化。
  2. compile解析模板指令,将模板中的变量替换成数据,然后初始化渲染页面视图,并将每个指令对应的节点绑定更新函数,添加监听数据的订阅者,一旦数据有变动,收到通知,更新视图
  3. Watcher 订阅者是 Observer 和 Compile 之间通信的桥梁,主要做的事情是:
  • 1、在自身实例化时往属性订阅器(dep)里面添加自己
  • 2、自身必须有一个 update() 方法
  • 3、待属性变动 dep.notice() 通知时,能调用自身的 update() 方法,并触发 Compile 中绑定的回调,则功成身退。
  1. MVVM 作为数据绑定的入口,整合 Observer、Compile 和 Watcher 三者,通过 Observer 来监听自己的 model 数据变化, 通过 Compile 来解析编译模板指令,最终利用 Watcher 搭起 Observer 和 Compile 之间的通信桥梁,达到数据变化 -> 视图更新; 视图交互变化(input) -> 数据 model 变更的双向绑定效果。

生命周期?

  • beforeCreate(创建前): 创建前data和method还没有初始化,数据观测还没开始,不能访问到data、computed、watch、methods上的方法和数据。
  • created(创建后): 实例创建完成、data、computed、watch、methods已经初始化完成,但是此时还未挂在到DOM,所以我们在此时访问不到我们的Dom元素(el属性,ref属性此时都为空)。
  • beforeMount(挂在前): 在挂载之前被调用,相关的render函数首次被调用,已经编译好了模板字符串,但是还有没有真正渲染到页面中。
  • Mounted(挂在后): 虚拟Dom已经被挂载到真实Dom上,此时我们可以获取Dom节点,$ref在此时也是可以访问的。
  • beforeUpdate(更新前): 响应式数据更新时调用,此时虽然响应式数据更新了,但是对应的真实 DOM 还没有被渲染。我们在此时可以去获取节点信息,做Ajax请求,对节点做一些操作
  • updated(更新后): 在由于数据更改导致的虚拟DOM重新渲染和打补丁之后调用。此时 DOM 已经根据响应式数据的变化更新了。调用时,组件 DOM已经更新,所以可以执行依赖于DOM的操作。然而在大多数情况下,应该避免在此期间更改状态,因为这可能会导致更新无限循环。该钩子在服务器端渲染期间不被调用
  • boforeDestroy(销毁前): 实例进入准备销毁的阶段、此时 data 、methods 、指令 等还是可用状态
  • destroyed(销毁后): 实例已经完成销毁、此时 data 、methods 、指令等都不可用

数据请求一般放在哪个生命周期

看实际情况,一般在 created(或beforeRouter) 里面就可以,如果涉及到需要页面加载完成之后的话就用 mounted。

在created的时候,视图中的html并没有渲染出来,所以此时如果直接去操作html的dom节点,一定找不到相关的元素 而在mounted中,由于此时html已经渲染出来了,所以可以直接操作dom节点,(此时document.getelementById 即可生效了)。

组件传参

  • Props传递数据

适用于父子传参,子组件定义props属性,接收来自父组件的参数!

  • $emit

子组件 传递数据给父组件,子组件通过$emit自定义事件,第二个参数为传递的数值,父组件绑定监听器获取传过来的参数

`Chilfen.vue`
this.$emit('add', good)  
`Father.vue`
<Children @add="cartAdd($event)" />  
  • ref

父组件在使用子组件的时候设置ref,父组件通过设置子组件ref来获取数据

//父组件
<Children ref="foo" />  
  
this.$refs.foo  // 获取子组件实例,通过子组件实例我们就能拿到对应的数据  
  • EventBus

兄弟组件传值,创建一个中央事件总线EventBus,兄弟组件通过emit触发自定义事件,第二个参数为传递的数值,另一个组件通过emit触发自定义事件,第二个参数为传递的数值,另一个组件通过on监听自定义事件

// 创建一个中央时间总线类  
class Bus {  
  constructor() {  
    this.callbacks = {};   // 存放事件的名字  
  }  
  $on(name, fn) {  
    this.callbacks[name] = this.callbacks[name] || [];  
    this.callbacks[name].push(fn);  
  }  
  $emit(name, args) {  
    if (this.callbacks[name]) {  
      this.callbacks[name].forEach((cb) => cb(args));  
    }  
  }  
}  
  
// main.js  
Vue.prototype.$bus = new Bus() // 将$bus挂载到vue实例的原型上  
// 另一种方式  
Vue.prototype.$bus = new Vue() // Vue已经实现了Bus的功能  
`Children1.vue`
this.$bus.$emit('foo')  
`Children2.vue`
this.$bus.$on('foo', this.handle)  
  • provide与indect

在祖先组件中定义provide属性,在后代组件通过indect接收传值

  • vuex

Vue中的$nextTick有什么作用?

  • 在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM(我们可以理解成,Vue 在更新 DOM 时是异步执行的。当数据发生变化,Vue将开启一个异步更新队列,视图需要等队列中所有数据变化完成之后,再统一进行更新)

  • 如果想要在修改数据后立刻得到更新后的DOM结构,可以使用Vue.nextTick()

    • 第一个参数为:回调函数(可以获取最近的DOM结构)
    • 第二个参数为:执行函数上下文

说说你对slot的理解?slot使用场景有哪些?

  • 通过插槽可以让用户更好的拓展组件,去更好的复用组件和对其他做定制化的处理
  • 通过slot插槽向组件内部指定位置传递内容,完成这个复用组件在不同场景的应用
  • 插槽可以分为三种
    • 默认插槽
    • 具名插槽
    • 作用域插槽

默认插槽

  • 子组件用 <slot> 标签来确定渲染的位置,父组件在使用时,直接在子组件的标签内写入内容即可

具名插槽

  • 子组件用 name 属性来表示插槽的名字,不传为默认插槽
  • 父组件在使用时,在默认插槽上加上slot属性,值为子组件插槽的name

作用域插槽

  • 子组件在作用域上绑定属性来将子组件的信息传给父组件使用,这些属性会被挂载到父组件的v-slot接收的对象上
  • 父组件中通过v-slot简写#获取子组件的信息

Keep-alive

作用:能在组件切换过程中将状态保留在内存中,防止重复渲染DOM(比如说商品列表)

keep可以设置以下属性

  • include - 字符串或正则表达式,只有名称匹配的组件会被缓存
  • exclude - 字符串或正则表达式,任何包含的名称都不会被缓存
  • max - 最多可以缓存多少组件实例

缓存后如何让获取数据

  • beforeRouteEnter

每次组件渲染的时候,都会执行beforeRouteEnter

  • actived

keep-alive缓存的组件被激活的时候,都会执行actived钩子

展开追问:假设从B到A路由不刷新,从C到A需要刷新

  • 在A路由设置meta属性
{ 
  path: '/', name: 'A', 
  component: A, 
  meta: { 
  keepAlive: true // 需要被缓存 
 } 
}
  • 在B组件里设置beforeRouteLeave:
export default { 
  data() { 
    return {}; 
}, 
methods: {}, 
beforeRouteLeave(to, from, next) { 
// 设置下一个路由的 meta 
    to.meta.keepAlive = true; // 让 A 缓存,即不刷新 
next(); 
  } 
};
  • 在C组件里设置beforeRouteLeave:
export default { 
  data() { 
    return {}; 
}, 
methods: {}, 
beforeRouteLeave(to, from, next) { 
// 设置下一个路由的 meta 
    to.meta.keepAlive = false; // 让 A 不缓存,即刷新 
next(); 
  } 
};

vue自定义指令

全局注册主要通过Vue.directive,第一个参数是指令的名字,第二个参数可以是对象数据 自定义指令也像组件那样存在钩子函数:

  • bind:只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置
  • inserted:被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)
  • update:所在组件的 VNode 更新时调用,但是可能发生在其子 VNode 更新之前。指令的值可能发生了改变,也可能没有。但是你可以通过比较更新前后的值来忽略不必要的模板更新
  • componentUpdated:指令所在组件的 VNode 及其子 VNode 全部更新后调用
  • unbind:只调用一次,指令与元素解绑时调用

所有的钩子函数的参数都有以下:

  • el:指令所绑定的元素,可以用来直接操作 DOM

  • binding:一个对象,包含以下 property

    • name:指令名,不包括 v- 前缀。
    • value:指令的绑定值,例如:v-my-directive="1 + 1" 中,绑定值为 2
    • oldValue:指令绑定的前一个值,仅在 update 和 componentUpdated 钩子中可用。无论值是否改变都可用。
    • expression:字符串形式的指令表达式。例如 v-my-directive="1 + 1" 中,表达式为 "1 + 1"
    • arg:传给指令的参数,可选。例如 v-my-directive:foo 中,参数为 "foo"
    • modifiers:一个包含修饰符的对象。例如:v-my-directive.foo.bar 中,修饰符对象为 { foo: true, bar: true }
  • vnodeVue 编译生成的虚拟节点

  • oldVnode:上一个虚拟节点,仅在 update 和 componentUpdated 钩子中可用

async和await

  • async声明了一个fuction是异步的,而await用于等待一个异步方法完成,它可以很好地代替promise中的then
  • async返回了一个promise对象,可以使then方法添加回调函数,当函数执行的时候,一旦遇到await就先返回,等到异步完成后,再接着执行函数体内后面的语句

数组有哪几种循环方式?分别有什么作用?

every() 方法测试一个数组内的所有元素是否都能通过某个指定函数的测试。它返回一个布尔 值。

filter() 方法创建一个新数组, 其包含通过所提供函数实现的测试的所有元素。 注意: filter() 不会对空数组进行检测。 注意: filter() 不会改变原始数组。

forEach() 方法对数组的每个元素执行一次提供的函数。

some() 方法测试是否至少有一个元素可以通过被提供的函数方法。该方法返回一个 Boolean 类型 的值。

数组的方法

不会影响原数组

  • push()添加元素到末尾,返回数组新的长度
  • unshift 开头添加,返回数组的新长度
  • concat 返回新数组
  • slice 创建一个包含原有数组中一个或多个元素的新数组,不会影响原始数组

会影响原数组

  • pop 删除数组的最后一项,同时减少数组的length 值,返回被删除的项
  • shift 删除数组的第一项,同时减少数组的length 值,返回被删除的项
  • splice 传入两个参数,分别是开始位置,删除元素的数量,返回包含删除元素的数组

indexOf 返回要查找的元素在数组中的位置,如果没找到则返回 -1 includes 返回要查找的元素在数组中的位置,找到返回true,否则false find 返回第一个匹配的元素

迭代方法

some()对数组每一项都运行传入的函数,如果有一项函数返回 true ,则这个方法返回 true
every()对数组每一项都运行传入的函数,如果对每一项函数都返回 true ,则这个方法返回 true
forEach()对数组每一项都运行传入的函数,没有返回值
filter()对数组每一项都运行传入的函数,函数返回 true 的项会组成数组之后返回
map()对数组每一项都运行传入的函数,返回由每次函数调用的结果构成的数组.

说说你对SPA单页面的理解,它的优缺点分别是什么?

SPA ( single-page application )仅在Web 页面初始化时加载相应的 HTML、JavaScript 和 CSS。一旦页面加载完成,SPA 不会因为用户的操作而进行页面的重新加载或跳转;取而代之的是利用路由机制实现HTML内容的变换,UI与用户的交互,避免页面的重新加载。

优点:

用户体验好、快,内容的改变不需要重新加载整个页面,避免了不必要的跳转和重复渲染;

SPA 相对对服务器压力小;

前后端职责分离,架构清晰,前端进行交互逻辑,后端负责数据处理;

缺点:

初次加载耗时多:为实现单页 Web 应用功能及显示效果,需要在加载页面的时候将JavaScript、css 统一加载,部分页面按需加载;

前进后退路由管理:由于单页应用在一个页面中显示所有的内容,所以不能使用浏览器的前进后退功能,所有的页面切换需要自己建立堆栈管理;

SEO难度较大:由于所有的内容都在一个页面中动态替换显示,所以在 SEO 上其有着天然的弱势。

怎样理解 Vue 的单向数据流?

所有的 Prop 都使得其父子 Prop 之间形成了一个单向下行绑定:父级Prop 的更新会向下流动到子组件中,但是反过来则不行。这样会防止从子组件意外改变父级组件的状态,从而导致你的应用的数据流向难以理解。

额外的,每次父级组件发生更新时,子组件中所有的Prop 都将会刷新为最新的值。这意味着你不应该在一个子组件内部改变 Prop。如果你这样做了,Vue 会在浏览器的控制台中发出警告。子组件想修改时,只能通过 $emit 派发一个自定义事件,父组件接收到后,由父组件修改。

有两种常见的试图改变一个Prop 的情形:最好定义一个本地的Data 属性并将这个 Prop 用作其初始值

Vue 的父组件和子组件生命周期钩子函数执行顺序?

Vue 的父组件和子组件生命周期钩子函数执行顺序可以归类为以下4部分:

加载渲染过程

父 beforeCreate -> 父 created -> 父 beforeMount -> 子 before Create -> 子created -> 子 beforeMount -> 子 mounted -> 父 mounted

子组件更新过程

父beforeUpdate -> 子 beforeUpdate -> 子 updated -> 父 updated

父组件更新过程

父 beforeUpdate -> 父 updated

销毁过程

父 beforeDestroy -> 子 beforeDestroy -> 子 destroved -> 父 destroved

在哪个生命周期内调用异步请求?

  • 可以在created、beforeMount、mounted中进行,推荐在create中调用异步请求,能更快的获取到服务端的数据,减少页面的loading时间
  • SSR 不支持 beforeMount、mounted 钩子函数,所以放在 created 中有助于一致性;

父组件可以监听到子组件的生命周期吗?

需要手动通过$emit触发父组件的事件,或者通过@hook来监听

使用过 Vue SSR 吗?说说 SSR?

SSR大致的意思就是vue在客户端将标签渲染成的整个HTML 片段的工作在服务端完成,服务端形成的HTML 片段直接返回给客户端这个过程就叫做服务端渲染。

服务端渲染 SSR 的优缺点如下:

(1) 服务端渲染的优点:

更好的SEO:因为SPA页面的内容是通过Ajax获取,而搜索引擎爬取工具并不会等待Ajax异步完成后再抓取页面内容,所以在SPA中是抓取不到页面通过Ajax 获取到的内容;而 SSR 是直接由服务端返回已经渲染好的页面(数据已经包含在页面中),所以搜索引擎爬取工具可以抓取渲染好的页面;

首屏加载更快:SPA 会等待所有 Vue 编译后的js 文件都下载完成后,才开始进行页面的渲染,文件下载等需要一定的时间等,所以首屏渲染需要一定的时间;SSR 直接由服务端渲染好页面直接返回显示,无需等待下载js 文件及再去渲染等,所以 SSR 有更快的内容到达时间;

(2 )服务端渲染的缺点:

更多的开发条件限制:例如服务端渲染只支持 beforCreate 和 created 两个钩子函数,这会导致一些外部扩展库需要特殊处理,才能在服务端渲染应用程序中运行;

能说下 vue-router 中常用的 hash 和history 路由模式实现原理吗?

(1)hash模式的实现原理

hash 路由模式的实现主要是基于下面几个特性:

URL中hash 值只是客户端的一种状态,也就是说当向服务器端发出请求时,hash 部分不会被发送;

hash值的改变,都会在浏览器的访问历史中增加一个记录。因此我们能通过浏览器的回退、前进按钮控制hash 的切换;

我们可以使用hashchange 事件来监听 hash 值的变化,从而对页面进行跳转(渲染)。

history 模式的实现原理

history.pushState() 和 history.repalceStatel)。返两个 API 可以在不迸行刷新的情況下,操作浏览器的历史纪录。唯一不同的是,前者是新增一个历史记录,后者是直接替换当前的历史记录,

一个页面从输入 URL 到页面加载显示完成,这个过程中都发生了什么?

1.首先,在浏览器地址栏输入url,回车

2.根据Url,浏览器先查看浏览器缓存-系统缓存-路由缓存…,如果缓存中有,会从缓存中读取并显示,若没有,则跳到第三步

3.在发送http请求前,先进行DNS域名解析,获取访问的IP地址

4.浏览器向服务器发起tcp连接,与浏览器建立tcp三次握手。

5.握手成功后,浏览器和服务器已经建立了通信,浏览器向服务器发送http请求,请求数据包。

6.服务器接收到请求,处理请求并返回url指定数据给浏览器。

7.浏览器接收到服务器HTTP响应内容

8.浏览器进行渲染,解析HTML生成DOM树,解析CSS生成规则树,js引擎解析js,将解析后DOM树和CSS规则树关联起来构建Renden渲染树树,然后计算布局,绘制页面。

9.渲染完毕,四次挥手,关闭tcp连接

什么是原型链?

每一个实例对象上有一个proto 属性,指向的构造函数的原型对象,构造函数的原型 对象也是一个对象, 也有 proto 属性,这样一层一层往上找的过程就形成了原型链

什么是闭包?

  • 闭包指有权访问另一个函数作用域中变量的函数,一个作用域可以访问另一个函数内部的局部变量
  • 作用:延长变量作用域、在函数的外部可以访问到函数内部的局部变量,容易造成内存泄漏,因为闭包中的局部变量永远不会被回收

常见的继承有哪些?

  • 原型链继承:实例可以继承的属性有:实例的构造函数属性,父类构造函数属性,父类原型的属性
  • 借用构造函数继承:用  .call()和.apply()  将父类构造函数引入子类函数
  • class类实现继承:通过extends和super实现继承

ES6有哪些特性?

  • let和const具有块级作用域,不存在变量提升的问题,新增箭头函数,简化了定义函数的方法
  • 新增了Promise解决了地狱回调的问题,新增了模块化、利用import、export来实现导入、导出
  • 新增了结构赋值,新增了class类的概念

v-for 循环为什么一定要绑定 key ?

页面上的标签都对应具体的虚拟 dom 对象(虚拟 dom 就是 js 对象), 循环中 ,如果没有唯一 key , 页面上删除 一条标签, 由于并不知道删除的是那一条! 所以要把全部虚拟 dom 重新渲染, 如果知道 key 为 x 标签被删除 掉, 只需要把渲染的 dom 为 x 的标签去掉即可!

组件中的 data 为什么要定义成一个函数而不是一个对象?

为了保证组件的独立性和可复用性,data是一个函数,组件实例化的时候就会调用这个函数,返回一个对象,计算机给这个对象分配一个内存地址,实例化几次就会分配几个内存地址,他们的地址不一样,所以数据互不干扰,改变其中的一个组件状态,其他组件不变!

递归有哪些特点?

  • 自己调用自己
  • 优点是结构清晰、可读性强
  • 缺点:效率低、调用栈可能溢出

Vue实例挂载到了哪个标签上?

Vue实例最后会挂载在body标签里面,所以我们在vue中是获取不了body标签的,如果要使用body标签的话要用原生的方式获取

JS的执行机制是怎么样的?

Js是一个单线程、异步、非阻塞i/O模型,event loop事件循化的执行机制

所有的任务可以分为两种,一种是同步任务,另一种是异步任务 什么是同源策略?

所谓同源策略是浏览器的一种安全机制,来限制不同源的网站不能通信。同源就是域名、协议、端口一致。

浏览器运行机制

1、创建DOM树2、构建渲染树,CSS渲染
3、布局渲染,每个元素的大小、位置4、绘制渲染树、再画出来

清除浮动的方法

方法一: 使用带 clear 属性的空元素

在浮动元素后使用一个空元素,并在 CSS 中赋 予.clear{clear:both;}属性即可清理浮动。

方法二: 使用 CSS 的 overflow 属性

给浮动元素的容器添加 overflow:hidden;或 overflow:auto;可以清除浮动

方法四: 使用 CSS 的:after 伪元素 然后给这个 class 添加一个:after 伪元素实 现元素末尾添加一个看不见的块元素清除浮动

常见的行内元素、块元素

  • 块级元素(div、p,h1...h6,ol,ul,table)
    • 每个块级元素都是独占一行,元素的高度宽度都是可以设置的
  • 行内元素(span,a,img,input,strong)
    • 可以和其他元素处于一行上,元素的高度宽度顶部和底部边距不可设置

做好SEO需要考虑什么?

  • 合理的title,description,keywords,
  • 图片都加上alt
  • 语义化html语义化标签
  • 少用iframe,搜索引擎不会抓取iframe中的内容
  • 重要的html代码放前边

Hash和history有什么区别?

区别一:生产环境下:两者无区别

  • 开发环境或者测试环境下:
  • hash:前进和后退正常,刷新页面正常
  • history:前进和后退正常,刷新页面会报错,报错可能有两种结果:一种是404报错,一种是直接把没有处理的数据展示到页面
  • history报错的原因:刷新页面,就走后端路由,如果后边没有该路由,就是404,如果有该路由,会直接数据展示

区别二:原理不同

  • hash采用的是window.onhashchange=()=>{}来实现的
  • history采用的是HTML5新增的interface里面的pushState()和replaceState(),不兼容ie6~8

深浅拷贝,如何实现一个深拷贝

浅拷贝只复制指定某个对象的指针,不会复制对象的本身

深拷贝会创造一个一模一样的对象

  • 浅拷贝:可以使用 for…in、 Object.assign、 扩展运算符 ... 、 Array.prototype.slice()、 Array.prototype.concat() 等
  • 深拷贝:JSON.parse(JSON.stringify(obj)),递归,lodash中的拷贝函数

可以取消promise嘛

无法取消 Promise,一旦新建它就会立即执行,无法中途取消。

rem、em、vh、px各自代表的含义?

  • px:绝对单位,页面按精确像素展示
  • em:相对单位,基准点为父节点字体的大小,如果自身定义了font-size按自身来计算,整个页面内1em不是一个固定的值
  • rem:相对单位,可理解为root em, 相对根节点html的字体大小来计算
  • vh、vw:主要用于页面视口大小布局,在页面布局上更加方便简单
  • 如何让判断一个一个变量是否为数组?

  • Array继承于Object,所以typeof会直接返回object(x)

1.利用Object的toString方法

var list = [1,2,3];
Object.prototype.toString.call(list);    //[object Array]

2.利用ES6的Array.isArray()方法

var list = [1,2,3];
Array.isArray(list);    //true

数组的原生方法有哪些?

不会改变自身的方法

Array.prototype.fill() 用一个固定值填充数组的开始索引到结束索引的全部元素,不包括终止索引。

const array1 = [1, 2, 3, 4];

// 填充数值0,从索引2直到4的位置 
console.log(array1.fill(0, 2, 4));
// expected output: [1, 2, 0, 0]

// 填充数值5,从索引1开始
console.log(array1.fill(5, 1));
// expected output: [1, 5, 5, 5]
 
// 填充数值6,直到结束
console.log(array1.fill(6));
// expected output: [6, 6, 6, 6]

Array.prototype.pop() 删除数组的最后一个元素,并返回这个元素。

Array.prototype.push() 在数组的末尾增加一个或多个元素,并返回数组的新长度。

Array.prototype.reverse() 颠倒数组中元素的排列顺序,即原先的第一个变为最后一个,原先的最后一个变为第一个。

Array.prototype.shift() 删除数组的第一个元素,并返回这个元素。

Array.prototype.sort() 对数组元素进行排序,并返回当前数组。

Array.prototype.splice() 在任意的位置给数组添加或删除任意个元素。

const months = ['Jan', 'March', 'April', 'June'];
months.splice(1, 0, 'Feb');
// 在索引位置为1的位置,插入一个元素Feb
console.log(months);
// expected output: Array ["Jan", "Feb", "March", "April", "June"]

months.splice(4, 1, 'May');
// 在索引4的位置替换一个元素为May
console.log(months);
// expected output: Array ["Jan", "Feb", "March", "April", "May"]

Array.prototype.unshift() 在数组的开头增加一个或多个元素,并返回数组的新长度。

不会改变自身的方法

Array.prototype.concat() 返回一个由当前数组和其它若干个数组或者若干个非数组值组合而成的新数组。

Array.prototype.includes() 判断当前数组是否包含某指定的值,如果是返回 true,否则返回 false。

Array.prototype.join() 连接所有数组元素组成一个字符串。

Array.prototype.slice() 抽取当前数组中的一段元素组合成一个新数组。

Array.prototype.toString() 返回一个由所有数组元素组合而成的字符串。遮蔽了原型链上的 Object.prototype.toString() 方法。

Array.prototype.indexOf() 返回数组中第一个与指定值相等的元素的索引,如果找不到这样的元素,则返回 -1。

Array.prototype.lastIndexOf() 返回数组中最后一个(从右边数第一个)与指定值相等的元素的索引,如果找不到这样的元素,则返回 -1。

Set和Map

1.Map是键值对,Set是值的集合,当然键和值可以是任何的值;

2.Map可以通过get方法获取值,而set不能因为它只有值;

3.都能通过迭代器进行for...of遍历;

4.Set的值是唯一的,可以做数组去重,Map由于没有格式限制,可以做数据存储

5.map和set都是stl中的关联容器,map以键值对的形式存储,key=value组成pair,是一组映射关系。set只有值,可以认为只有一个数据,并且set中元素不可以重复且自动排序。

数组去重

Set数据结构类似于数组,但所有成员的值是唯一的

let a = new Set([1,2,3,3,4]); [...a]; 
// [1,2,3,4] 
a.size; // 4 
// 数组去重 
[...new Set([1,2,3,4,4,4])];
// [1,2,3,4]

// 方法2 
Array.from(new Set([1,2,3,4,4,4])); // [1,2,3,4]

获取交集、并集和差集

let a = new Set([1,2,3]); 
let b = new Set([4,3,2]); 
// 并集 
let c1 = new Set([...a, ...b]); // Set {1,2,3,4} 
// 交集 
let c2 = new Set([...a].filter(x => b.has(x))); // set {2,3} 
// 差集 
let c3 = new Set([...a].filter(x => !b.has(x))); // set {1}

并且 还可以使用 for...of直接遍历 Set

let a = new Set(['a','b','c']);
for(let x of a){console.log(x)};   // 'a' 'b' 'c'

forEach与数组相同,对每个成员执行操作,且无返回值。

let a = new Set(['a','b','c']);
a.forEach((v,k) => console.log(k + ' : ' + v));

Map对象

let a = new Map(); 
let b = {name: 'leo' }; 
a.set(b,'my name'); // 添加值 
a.get(b); // 获取值 
a.size; // 获取总数 
a.has(b); // 查询是否存在 
a.delete(b); // 删除一个值 
a.clear(); // 清空所有成员 无返回
  • 如果一个键多次赋值,后面的值将覆盖前面的值
  • 如果读取一个未知的键,则返回undefined
  • 同样的两个实例,在Map结构中被视为两个键

Css 选择器

Ø  id选择器(#box),选择id为box的元素

Ø  类选择器(.one),选择类名为one的所有元素

Ø  标签选择器(div),选择标签为div的所有元素

Ø  后代选择器(#box div),选择id为box元素内部所有的div元素

Ø  子选择器(.one>one_1),选择父元素为.one的所有.one_1的元素

Ø  相邻同胞选择器(.one+.two),选择紧接在.one之后的所有.two元素

Ø  群组选择器(div,p),选择div、p的所有元素

伪类选择器

Ø  :link :选择未被访问的链接

Ø  :visited:选取已被访问的链接

Ø  :active:选择活动链接

Ø  :hover :鼠标指针浮动在上面的元素

Ø  :focus :选择具有焦点的

Ø  :first-child:父元素的首个子元素

伪元素选择器

Ø  :first-letter :用于选取指定选择器的首字母

Ø  :first-line :选取指定选择器的首行

Ø  :before : 选择器在被选元素的内容前面插入内容

Ø  :after : 选择器在被选元素的内容后面插入内容

属性选择器

Ø  [attribute] 选择带有attribute属性的元素

Ø  [attribute=value] 选择所有使用attribute=value的元素

Ø  [attribute~=value] 选择attribute属性包含value的元素

Ø  [attribute|=value]:选择attribute属性以value开头的元素

在CSS3中新增的选择器有如下:

层次选择器(p~ul),选择前面有p元素的每个ul元素

伪类选择器

:nth-child(n) 根据元素在一组同级中的位置匹配元素

:nth-last-of-type(n) 匹配给定类型的元素,基于它们在一组兄弟元素中的位置,从末尾开始计数

:last-child 表示一组兄弟元素中的最后一个元素

:root 设置HTML文档

:empty 指定空的元素

:enabled 选择可用元素

:disabled 选择被禁用元素

:checked 选择选中的元素

属性选择器

[attribute*=value]:选择attribute属性值包含value的所有元素

[attribute^=value]:选择attribute属性开头为value的所有元素

[attribute$=value]:选择attribute属性结尾为value的所有元素

 

优先级

Ø  内联 > ID选择器 > 类选择器 > 标签选择器

继承属性

字体系列属性

Ø  font:组合字体

Ø  font-family:规定元素的字体系列

Ø  font-weight:设置字体的粗细

Ø  font-size:设置字体的尺寸

Ø  font-style:定义字体的风格

Ø  font-variant:偏大或偏小的字体

文本系列属性

Ø  text-indent:文本缩进

Ø  text-align:文本水平对刘

Ø  line-height:行高

Ø  word-spacing:增加或减少单词间的空白

Ø  letter-spacing:增加或减少字符间的空白

Ø  text-transform:控制文本大小写

Ø  direction:规定文本的书写方向

Ø  color:文本颜色

元素可见性

Ø  visibility

表格布局属性

Ø  caption-side:定位表格标题位置

Ø  border-collapse:合并表格边框

Ø  border-spacing:设置相邻单元格的边框间的距离

Ø  empty-cells:单元格的边框的出现与消失

Ø  table-layout:表格的宽度由什么决定

列表属性

Ø  list-style-type:文字前面的小点点样式

Ø  list-style-position:小点点位置

Ø  list-style:以上的属性可通过这属性集合

引用

Ø  quotes:设置嵌套引用的引号类型

光标属性

Ø  cursor:箭头可以变成需要的形状

继承中比较特殊的几点:

Ø  a 标签的字体颜色不能被继承

Ø  h1-h6标签字体的大下也是不能被继承的

无继承的属性

Ø  display

Ø  文本属性:vertical-align、text-decoration

Ø  盒子模型的属性:宽度、高度、内外边距、边框等

Ø  背景属性:背景图片、颜色、位置等

Ø  定位属性:浮动、清除浮动、定位position等

Ø  生成内容属性:content、counter-reset、counter-increment

Ø  轮廓样式属性:outline-style、outline-width、outline-color、outline

Ø  页面样式属性:size、page-break-before、page-break-after

 

元素水平垂直居中的方法有哪些?如果元素不固定宽高呢?

定位+margin:auto

Ø  子绝父相,四个位置值都设置成0,如果没有宽高,则会和父级宽高一样

Ø  如果设置了宽高,给一个margin;auto,就可以实现上下左右都居中了

定位+margin:负值

Ø  子绝父相,设置left和top为50%,margin-left,margin-top去掉自身高度一半

Ø  但是这个方法要知道自身的宽高,所以要用transform代替此方案

定位+transform

Ø  代码同上,只是用transform:translate(-50%,-50%)代替了margin负值,该方案不需要知道元素自身的宽高

Table

设置父元素为display:table-cell,子元素设置 display: inline-block。利用verticaltext-align可以让所有的行内块级元素水平垂直居中

Flex

Ø  display: flex时,表示该容器内部的元素将按照flex进行布局

Ø  align-items: center表示这些元素将相对于本容器水平居中

Ø  justify-content: center也是同样的道理垂直居中

grid

display:grid

内联元素居中布局

水平居中

Ø  行内元素可设置:text-align: center

Ø  flex布局设置父元素:display: flex; justify-content: center

垂直居中

Ø  单行文本父元素确认高度:height === line-height

Ø  多行文本父元素确认高度:display: table-cell; vertical-align: middle

块级元素居中布局

水平居中

Ø  定宽: margin: 0 auto

Ø  绝对定位+left:50%+margin:负自身一半

垂直居中

Ø  position: absolute设置left、top、margin-left、margin-top(定高)

Ø  display: table-cell

Ø  transform: translate(x, y)

Ø  flex(不定高,不定宽)

Ø  grid(不定高,不定宽),兼容性相对比较差

单行文本溢出省略

理解也很简单,即文本在一行内显示,超出部分以省略号的形式展现

实现方式也很简单,涉及的css属性有:

text-overflow:规定当文本溢出时,显示省略符号来代表被修剪的文本

white-space:设置文字在一行显示,不能换行

overflow:文字长度超出限定宽度,则隐藏超出的内容

用到了VueUse什么库?

useMouseInElement :获取鼠标的偏移量

Ø  // elementX 鼠标基于容器左上角X轴偏移

Ø  // elementY 鼠标基于容器左上角Y轴偏移

Ø  // isOutside 鼠标是否在模板容器外

onClickOutside :检测在一个元素之外的任何点击。点击其他位置生效

useVModel :简化了v-model绑定

IntersectionObserver :跟踪元素可见性

 

封装hooks,

数据懒加载,利用vueuse中的useIntersectionObserver,解构出stop,观察isIntersecting,

如果进入可视区域就停止观察,调用请求数据,需要两个参数,当前组件节点,当前数据定义

power-set 怎么用的?

根据后台返回的skus数据得到有效的sku组合

根据有效的sku组合得到所有的子集集合

根据子集集合组成一个路径字典对象

图片懒加载:定义自定义指令,两个参数,第一个是该元素节点,第二个是当前数据

封装组件

Loading:判断是否进入可视区,loading和findished都不存在,接着执行请求