美盈智能 - 前端面试

面试时间:2023-02-22

公司全称:广州美盈智能科技有限公司

公司位置:广州天河区中天大楼天河区华观路明旭街1号,中天大楼5楼501室

面试题

数组迭代器种类
查看答案

共有 6 种迭代器。forEach、map、filter、every、some、reduce。


JS 继承方式有哪些
查看答案

参考:https://blog.csdn.net/weixin_41759744/article/details/125299029open in new window

共有 6 种继承方式:原生链继承、构造函数继承、组合式继承、原型式继承、寄生式继承、寄生组合式继承。寄生组合式继承是这 6 种里面最优的继承方式,在 ES6 中也提供继承的关键字 extends 更方便的实现继承。

  1. 原型链继承 核心:将父类实例作为子类的原型
function Parent() {
    this.name = 'parent'
    this.play = [1, 2, 3]
  }

  function Child() {
    this.type = 'child'
  }

  Child.prototype = new Parent()
  console.log(new Child())
  1. 构造函数继承(借助 call) 核心:使用父类的构造函数来增强子类实例,等于是复制父类的实例属性给子类。
  function Parent(){
    this.name = 'parent'
    this.fn = function() {
        console.log('Hello')
    }
  }
 
  function Child(){
    Parent.call(this)
    this.type = 'child'
  }

  console.log(new Child())
  1. 组合继承(前两种组合) 核心:通过调用父类构造,继承父类的属性并保留传参的优点,然后通过将父类实例作为子类原型,实现函数复用。
function Parent () {
    this.name = 'parent'
    this.play = [1, 2, 3]
  }
 
  Parent.prototype.getName = function () {
    return this.name
  }

  function Child() {
    Parent.call(this)
    this.type = 'child'
  }
 
  Child.prototype = new Parent()
  // 手动挂上构造器,指向自己的构造函数
  Child.prototype.constructor = Child
  const s3 = new Child()
  const s4 = new Child()
  s3.play.push(4)
  console.log(s3.play, s4.play)  // 不互相影响
  console.log(s3.getName()) // 正常输出'parent'
  console.log(s4.getName()) // 正常输出'parent'
  1. 原型式继承 ES5 里面的 Object.create 方法,这个方法接收两个参数:第一个参数用作新对象原型的对象,第二个参数是为新对象定义额外属性的对象(可选参数)
let parent = {
    name: "parent",
    friends: ["p1", "p2", "p3"],
    getName: function() {
      return this.name
    }
  }
 
  let person1 = Object.create(parent)
  person1.name = "tom"
  person1.friends.push("jerry")
  let person2 = Object.create(parent)
  person2.friends.push("lucy")
 
  console.log(person1.name) // tom
  console.log(person1.name === person1.getName()) // true
  console.log(person2.name) // parent
  console.log(person1.friends) // ['p1', 'p2', 'p3', 'jerry', 'lucy']
  console.log(person2.friends) // ['p1', 'p2', 'p3', 'jerry', 'lucy']
  1. 寄生式继承 使用原型式继承可以获得一份目标对象的浅拷贝,然后利用这个浅拷贝的能力再进行增强,添加一些方法,这样的继承方式就叫做寄生式继承。

虽然其优缺点和原型式继承一样,但是对于普通对象的继承方式来说,寄生式继承相比于原型式继承,还是在父类基础上添加了更多的方法。

   let parent = {
    name: "parent",
    friends: ["p1", "p2", "p3"],
    getName: function() {
      return this.name
    }
  }
 
  function clone(original) {
    let clone = Object.create(original)
    clone.getFriends = function() {
      return this.friends
    }
    return clone
  }
 
  let person = clone(parent)
  console.log(person.getName()) // parent
  console.log(person.getFriends()) //  ['p1', 'p2', 'p3']
  1. 寄生组合式继承 结合第四种中提及的继承方式,解决普通对象的继承问题的 Object.create 方法,我们在前面这几种继承方式的优缺点基础上进行改造,得出了寄生组合式的继承方式,这也是所有继承方式里面相对最优的继承方式。
function clone (parent, child) {
    // 这里改用 Object.create 就可以减少组合继承中多进行一次构造的过程
    child.prototype = Object.create(parent.prototype)
    child.prototype.constructor = child
  }
 
  function Parent() {
    this.name = 'parent'
    this.play = [1, 2, 3]
  }
   Parent.prototype.getName = function () {
    return this.name
  }
  function Child() {
    Parent.call(this)
    this.friends = 'child'
  }
 
  clone(Parent, Child)
 
  Child.prototype.getFriends = function () {
    return this.friends
  }
 
  let person = new Child()
  console.log(person)  // child {name: "parent",play: [1, 2, 3], friends: "child"}
  console.log(person.getName()) // parent
  console.log(person.getFriends()) // child

总体看下来,这六种继承方式中,寄生组合式继承是这六种里面最优的继承方式

ES6 提供了继承的关键字 extends

class Person {
  constructor(name) {
    this.name = name
  }
  // 原型方法
  // 即 Person.prototype.getName = function() { }
  // 下面可以简写为 getName() {...}
  getName = function () {
    console.log('Person:', this.name)
  }
}
 
class Child extends Person {
  constructor(name, age) {
    // 子类中存在构造函数,则需要在使用“this”之前首先调用 super()。
    super(name)
    this.age = age
  }
}
 
const person = new Child('Tom', 20)
person.getName() // 成功访问到父类的方法

正则表达式的标记有哪些
查看答案

共有 3 个。/g、/i、/m

/g (global)全局匹配

/i (ignoreCase)匹配时不区分大小写

/m (multiple)多行匹配。m 会影响 ^、$。若不指定 m,则 ^ 只在字符串的最开头,$ 只在字符串的最结尾。即匹配整个串的开始和结束;若指定 m,则 ^ 在字符串每一行的开头,$ 在字符串每一行的结尾。即匹配每一行的开始和结束


Vue 的双向绑定原理
查看答案

Vue2 通过 Object.defineProperty() 拦截对象对象属性并添加 get() 和 set() 方法的方式实现。

Vue3 通过 Proxy 直接拦截整个对象的方式实现。


Vue 如何让样式只在本页面生效
查看答案

只需要给 style 标签加上 scoped 属性即可。


v-if 与 v-show 的区别和应用场景
查看答案

v-if:通过创建、销毁 dom 的方式控制元素的显隐。

v-show: 通过添加、删除 CSS 属性 display: none 的方式控制元素的显隐。

v-if 适用于运行条件很少改变的场景;v-show 适用于频繁切换显隐的场景。


Vue 中 data 为什么是一个函数
查看答案

data 为一个函数是为了防止多个组件实例对象之间公用一个 data,产生数据污染。


如何生成动态海报
查看答案

参考:怎么使用 js 动态生成海报?open in new window

方案一:DOM -> canvas -> image

方案二:DOM -> SVG -> canvas -> image

笔试题


delete 与 Vue.delete 删除数组的区别
查看答案

delete:只是将被删除的元素变成 empty/undefined,数组长度不变。

Vue.delete:删除数组元素,数组长度会减少。

const arr1 = [1, 2, 3, 4]
delete arr1[1]
console.log(arr1) // [1, empty, 3, 4]

const arr2 = [1, 2, 3, 4]
this.$delete(arr2, 1)
console.log(arr2) // [1, 3, 4]

监听对象的某个属性变化的方式有哪些
查看答案

共 3 种方式。

方式一:watch + deep 深度监听

方式二:computed + watch

方式三:watch 直接使用对象的某个属性


谈谈对 MVVM 的理解
查看答案

MVVM 是一种架构模式,它的核心思想是把每个页面分为了 Model、View、ViewModel 三部分。其中 Model 表示数据模型,View 表示 UI 组件,ViewModel 用于实现 View 和 Model 的双向数据绑定。


Vue 实现组件数据双向绑定(手写代码)
查看答案

Contributors: tanqin