面试答案1

vuex的属性

  1. state:声明定义数据
  2. getters:存放有依赖关系的数据,类似于computed计算属性
  3. mutation:同步的修改state中的数据
  4. actions:异步修改数据
  5. modules:让每一个模块都有自己的state,getters,mutation,actions

vue双向绑定的原理

Vue实现双向绑定的原理就是利用了Object.defineProperty()这个方法重新定义了对象获取属性值(get)和设置属性值(set)的操作来实现的。

vue全家桶有什么(❎)

  1. Vue-cli项目构建工具
  2. vue-router 路由
  3. vuex状态管理
  4. axios http 请求工具
  5. webpack

vue常见的一些指令

  1. v-for 现在要配合 :key使用
  2. v-if 是否渲染这个标签
  3. v-bind 简写:
  4. v-show display控制 none/block
  5. v-else 配合v-if使用
  6. v-on 简写@

vue中的data为什么是返回的函数

因为一个组件是可以共享的,但他们的data是私有的,所以每个组件都要return一个新的对象,返回一个唯一的对象,不要和其他组件共用一个对象

合并数组的方法

  1. concat
var a = [1,2,3]
var b = [4,5,6]
var c = a.concat(b)  //c = [1,2,3,4,5,6]
  1. apply
var a = [1,2,3]
var b = [4,5,6]
var c = a.push.apply(a,b)
  1. 数组合并去重
let arr1 = [1,2,3]
let arr2 = [2,3,4]
let arr = arr1.concat(arr2) //合并数组
let arrNew = new Set(arr)  //通过set集合去重
Array.from(arrNew)  //将set集合转化为数组

垂直居中的方式(❎)

  1. absolute+transform:绝对定位+转换
.parent {
    position: relative;
}
.child {
    position: absolute;
    left: 50%;
    rigth: 50%;
    transfrom: translate(-50%,-50%)
}
  1. flex + justify-content + align-items
.parent {
    display: flex;
    justify-content: center; //水平居中
    align-items: center;   //垂直居中
}

面试第二天

call,apply,bind的区别,实现以下方法(❎)

  1. call和apply都是为了解决改变this的指向。作用都相同,只是传参的方式不同。除了第一个参数外,call可以接受一个参数的列表,apply只接受一个参数的数组

call的实现思路

//call的实现思路
Function.prototype.myCall = function (context){
  if (typeof this !== 'function') {
     throw new TypeError('Error')
  }
  var context = context || window
  //给context添加一个属性
  context.fn = this
  //通过参数伪数组将context后面的参数取出来
  var args = [...arguments].slice(1)
  var result = context.fn(...args)
  //删除 fn
  delete context.fn
  return result
}

apply的实现思路

//apply的实现思路
Function.prototype.myApply = function (context) {
    if (typeof this !== 'function') {
     throw new TypeError('Error')
  }
    var context = context || window
    //为context添加一个属性
    context.fn = this
    var result 
    //判断是否存在第二个参数
    //如果存在就将第二个参数也展开
    if(arguments[1]) {
        result = context.fn(...arguments[1])
    } else {
        result = context.fn()
    }
    delete context.fn
    return result
}

bind的实现思路:bind返回了一个函数,对于函数来说有两种调用方式,一种是直接的调用,一种是通过new的方式

Function.prototype.myBind = function (context) {
    if (typeof this !== 'function') {
        throw new TypeError('Error')
    }
    const _this = this 
    const args = [...arguments].slice(1)
    //返回一个函数
    return function F () {
        if (this instanceof F) {
            return new _this(...args, ...arguments)
        }
        return _this.apply(context,args.concat(...arguments))
    }
}

vue中为什么使用axios

vue是虚拟DOM操作的,JQuery.ajax和都需要操作DOM,官方不推荐,而且axios本身就可以解决回调地狱的问题

cookie和session和window.localstore的区别(❎)

loaclStorage声明周期是永久的,存放数据一般为5MB;sessionStorage仅在当前会话下有效,关闭页面或者浏览器后被清除,存放数据大小一般为5MB;cookie具有极高的扩展性和可用性,存放数据大小为4k左右,有个数限制,一般不能超过20个。 localStorage、sessionStorage、Cookie共同点:都是保存在浏览器端,且同源的。

new操作的过程(❎)

在调用new的过程中会发生四件事: 1. 新生成了一个对象 2. 链接到原型 3. 绑定this 4. 返回新对象 其实我们完全可以自己实现一个new的过程

function createNew() {
  let obj  = {}
  let Sunday  = [].shift.call(arguments)
  obj.__proto__ = Sunday.prototype
  let result = Sunday.apply(obj,arguments)
  return result instanceof Object ? result : obj
}

vue-router的原理(❎)

vue-router路由提供了两种路由模式:hash模式和history模式。 - hash模式:ue-router 默认 hash 模式 —— 使用 URL 的 hash 来模拟一个完整的 URL,于是当 URL 改变时,页面不会重新加载。 - history模式:如果不想要很丑的 hash,我们可以用路由的 history 模式,这种模式充分利用 history.pushState API 来完成 URL 跳转而无须重新加载页面

vue组件通信

组件通信一般分为三种: 1. 父子组件通信 - 父组件通过props传递给子组件数据,子组件通过$emit发送数据传递数据,子组件不能修改父组件的数据,父子组件通信属于典型的单向数据流。 2. 兄弟组件通信 - 对于这种情况可以通过查找父组件中的子组件实现,也就是 this.$parent.$children,在 $children 中可以通过组件 name 查询到需要的组件实例,然后进行通信。 3. 跨多层级组件通信 待定

面试第三天

跨域

  1. JSONP
//jsonp的原理很简单,就是利用 <script> 标签没有跨域的限制的漏洞。当需要通讯时,通过 <script> 标签指向一个需要访问的地址,并提供一个回调函数来接收数据。
//JSONP使用简单并且兼容性不错,但是只限于get请求
<script src="http://sunday/api?param8=a&param2=b&callback=jsonp"></script>
<script>
    function jsonp(data) {
        console.log(data)
    }
</script>
  1. CORS
cors需要浏览器和后端同时支持。IE 8 和 9 需要通过XDonmainRequest来实现。
 浏览器会自动进行 CORS 通信,实现 CORS 通信的关键是后端,只要后端实现了 CORS ,就实现了跨域。
 服务端设置 Access-C动态容量—Allow-Origin 就可以开启CORS。此属性表示哪些域名可以访问资源。
  1. document.domain
这种方式只能用于主域名相同的情况下,例如sunday.test.com 和 zhaojiujiu.test.com 适用于该方式。
只需要给页面添加 document.domain = 'test.com'表示主域名都相同就可以实现跨域
  1. postMessage
// 发送消息端
window.parent.postMessage('message','http://sunday.com')
//接收消息端
var zhaojiujiu = new MessageChannel()
zhaojiujiu.addEventListener('message',event => {
    var origin = even.origin || event.originalEvent.origin
    if(origin === 'http://sunday.com') {
        console.log('验证通过')
    }
})

函数的节流和防抖

首先我们先明确一下函数节流和防抖的定义

  • 函数节流:在指定时间间隔内只会执行一次任务
  • 函数防抖:任务频繁触发的情况下,只有任务触发的时间间隔超过指定间隔的时候,任务才会执行

函数节流(throttle)

最形象的例子就是,当我们在滚动页面的时候,判断是否滚动到底部,在不考虑函数节流和代码性能的情况下,就是通过监听==window.scorll==的事件

$(window).on('scroll',function () {
  //判断滚动条是否滚动到页面的底部
  let pagHeight = $('body').height(),
      scroolTop = $(window).scrollTop(),
      winHeight = $(window).height(),
      thresold = pageHeight - scorllTop - winHeight;
  if(thresold > -100 && thresold <= 20) {
    console.log('bottom');
  }
});
//这种情况会非常消耗性能的,在滚动时,浏览器会时刻的监听是否满足滚动的条件,但是在实际的开发中我们是每隔一段时间去执行一次,所以就出现了函数节流的概念
下面试解决函数节流的解决方案:
function throttle(fn) {
  let tag = true;
  return function() {
    if (!tag) return;
    tag = false;
    setTimeout(() => {
      fn.apply(this,arguments);
      tag = true;
    },500)
  }
}

函数防抖(debounce)

这种情况也非常常见,在我们做搜索功能是,在input中输入数据时,每输入一个数据就会被触发一次请求,在我们输完搜索内容时,会发生几次请求,不仅用户体验不好,就连对服务器的的压力也会变大。 我们大多数的解决方案就是引入一个函数防抖(debounce)

//函数防抖的原理
function debounce (fn) {
  let tag = null;
  return function () {
    clearTimeout(tag);
    tag = setTimeout(() => {
      fn.apply(this, arguments);
    },500);
  };
}

其实函数节流和函数防抖的目的,就是节约计算机资源。

闭包

-

  • 闭包的定义:
    闭包就是能够读取其他函数内部变量的函数,在js中可以将闭包理解为“函数中的函数”
  • 闭包的用途:
    1.读取函数内部的变量
    2.让变量始终保持在内存中,延长变量的生命周期
  • 闭包的条件:
    1.有外层函数和子函数 
    2.外层函数有局部变量
    3.子函数能操控外层函数的局部变量
    4.子函数与外部函数有关联
function A() {
  let a = 1
  window.B = function () {
      console.log(a)
  }
}
A()
B() // 1
  • 闭包的存在意义:
// 使用闭包的方式解决var定义函数问题
for (var i = 0;i<=3;i++){
  (function(j){
    setTimeout(function timer() {
      console.log(j)
    },j*1000)
  })(i)
}

面试第四天

原型继承和class继承

原型继承

  • 如何实现原型继承?
    先更改子类的原型prototype指向一个New父类()对象。
子类.prototype = new 父类()

再给子类的原型设置一个constructor指向子类

子类.prototype.constructor = 子类
  • 代码
// 人类 → 父类
 function Person() {
   this.name = '名字';
   this.age = 10;
   this.gender = '男';
 }
 Person.prototype.sayHi = function () { console.log('你好'); };
 Person.prototype.eat = function () { console.log('我会吃。。。'); };
 Person.prototype.play = function () { console.log('我会玩'); };


 // 学生类 → 子类
 function Student() {
   this.stuId = 1000;
 }
 // 子类的原型prototyp指向父类的一个实例对象
 Student.prototype = new Person();
 // 添加一个constructor成员
 Student.prototype.constructor = Student;

 // 如何实现原型继承:
 // 给子类的原型prototype重新赋值为父类的一个实例对象。
 // 利用了原型链上属性或方法的查找规则。


 // 创建一个学生对象
 var stu1 = new Student();
 console.log(stu1.constructor)

class继承

  • 在es6中可以使用class去实现继承,并且实现起来很简单
class Parent {
  constructor(value) {
    this.val = value
  }
  getValue() {
    console.log(this.val)
  }
}
class Child extends Parent {
  constructor(value) {
    super(value)
    this.val = value
  }
}
let child = new Child(1)
child.getValue() // 1
child instanceof Parent // true
  • class 实现继承的核心在于使用 extends 表明继承自哪个父类,并且在子类构造函数中必须调用 super,因为这段代码可以看成 Parent.call(this, value)

猜你喜欢

转载自www.cnblogs.com/teahouse/p/11313847.html