面试复盘1

Js基础

1.js中布尔值为false的情况


js比较规则

1.a与b进行比较,如果a与b是Number,String,Boolean这三种类型中的一种,
并且a与b的类型不同,那么就将a与b都转换成数字再进行比较。

2.如果a是Number,String,Boolean这三种类型中的一种,而b是一个复合对象时(Object,Array等) 则对b执行ToPrimitive操作(这步是JS解释器执行的,ToPrimitive方法的实现,正是依次去调用对象的valueOf,toString方法,直到其中一个方法返回一个基本值,如果这两个方法没有返回基本值 ,那就认定不相等 )

布尔值为false的值

1、undefined(未定义,找不到值时出现)
2、null(代表空值)
3、false(布尔值的false,字符串"false"布尔值为true)
4、0(数字0,字符串"0"布尔值为true)
5、NaN(无法计算结果时出现,表示"非数值";但是typeof NaN===“number”)
6、""(双引号)或’’(单引号) (空字符串,中间有空格时也是true)

[]==false吗

根据比较规则第二点,[]最终会调用toString变成“”,由于“”==false, 所以[] == false。
{}同理,{} == false。

2.js怎么实现继承


2.1 原型链继承

原理: 将父类的实例作为子类的原型

// 父类
function Person(name) {
  // 属性
  this.name = name || 'Tony';
  // 实例方法
  this.sleep = function(){
    console.log(this.name + '正在睡觉');
  }
}
// 原型方法
Person.prototype.eat = function(food) {
  console.log(this.name + '正在吃:' + food);
};
// 子类
function Student(){ 
}
Student.prototype = new Person();
Student.prototype.name = 'Tom';

// 测试代码
var student = new Student();
console.log(student.name); // Tom
console.log(student.eat('chicken')); // Tom正在吃:chicken
console.log(student.sleep()); // Tom正在睡觉
console.log(student instanceof Person); // true 
console.log(student instanceof Student); // true

特点:

  • 容易实现
  • 父类新增原型方法/原型属性,子类都能访问到
  • 实例既是父类实例, 也是子类实例

缺点:

  • 无法实现多继承
  • 来自原型对象的所有属性被所有实例共享
  • 创建子类实例时,无法向父类构造函数传参
  • 要想为子类新增属性和方法,必须要在Student.prototype = new Person() 之后执行,不能放到构造器中
2.2 构造继承

原理:在子类型构造函数中通过call()调用父类型构造函数,相当于复制父类的实例属性给子类

// 父类
function Person(name) {
  // 属性
  this.name = name || 'Tony';
  // 实例方法
  this.sleep = function(){
    console.log(this.name + '正在睡觉');
  }
}
// 原型方法
Person.prototype.eat = function(food) {
  console.log(this.name + '正在吃:' + food);
};
// 子类
function Student(){
  Person.call(this, name)  // 相当于: this.Person(name)
  this.name = name || 'Tom';
}

// 测试代码
var student = new Student();
console.log(student.name); // Tom
console.log(student.eat('chicken')); // VM20:23 Uncaught TypeError: student.eat is not a function (只是实现部分的继承,如果父类的原型还有方法和属性,子类是拿不到这些方法和属性的。)
console.log(student.sleep()); // Tom正在睡觉
console.log(student instanceof Person); // false
console.log(student instanceof Student); // true

特点:

  • 解决了原型链继承中子类实例共享父类引用属性的问题
  • 创建子类实例时,可以向父类传递参数
  • 可以实现多继承(call多个父类对象)

缺点:

  • 实例并不是父类的实例,只是子类的实例
  • 只能继承父类的实例属性和方法,不能继承原型属性和方法
  • 无法实现函数复用,每个子类都有父类实例函数的副本,影响性能
2.3 组合继承

原理:原型链+借用构造函数

// 父类
function Person(name) {
  // 属性
  this.name = name || 'Tony';
  // 实例方法
  this.sleep = function(){
    console.log(this.name + '正在睡觉');
  }
}
// 原型方法
Person.prototype.eat = function(food) {
  console.log(this.name + '正在吃:' + food);
};
// 子类
function Student(){
  Person.call(this, name)  // 相当于: this.Person(name)
  this.name = name || 'Tom';
}
Student.prototype = new Person();
Student.prototype.constructor = Student;

// 测试代码
var student = new Student();
console.log(student.name); // Tom
console.log(student.eat('chicken')); // Tom正在吃:chicken
console.log(student.sleep()); // Tom正在睡觉
console.log(student instanceof Person); // true
console.log(student instanceof Student); // true

特点:

  • 可以继承实例属性/方法,也可以继承原型属性/方法
  • 不存在引用属性共享问题
  • 可传参
  • 函数可复用
  • 既是子类的实例,也是父类的实例

缺点:

  • 调用了两次父类构造函数,生成了两份实例
2.4 实例继承

原理:为父类实例添加新特性,作为子类实例返回

// 父类
function Person(name) {
  // 属性
  this.name = name || 'Tony';
  // 实例方法
  this.sleep = function(){
    console.log(this.name + '正在睡觉');
  }
}
// 原型方法
Person.prototype.eat = function(food) {
  console.log(this.name + '正在吃:' + food);
};
// 子类
function Student(){
  var instance = new Person();
  instance.name = name || 'Tom';
  return instance;
}

// 测试代码
var student = new Student();
console.log(student.name); // Tom
console.log(student.eat('chicken')); // Tom正在吃:chicken
console.log(student.sleep()); // Tom正在睡觉
console.log(student instanceof Person); // true
console.log(student instanceof Student); // false

特点:

  • 不限制调用方式,不管是new 子类()还是子类(),返回的对象具有相同的效果

缺点:

  • 实例是父类的实例,不是子类的实例
  • 不支持多继承
2.5 拷贝继承
// 父类
function Person(name) {
  // 属性
  this.name = name || 'Tony';
  // 实例方法
  this.sleep = function(){
    console.log(this.name + '正在睡觉');
  }
}
// 原型方法
Person.prototype.eat = function(food) {
  console.log(this.name + '正在吃:' + food);
};
// 子类
function Student(){
  var person = new Person();
  for(var p in person){
    Student.prototype[p] = person[p];
  }
  this.name = name || 'Tom';
}

// 测试代码
var student = new Student();
console.log(student.name); // Tom
console.log(student.eat('chicken')); // Tom正在吃:chicken
console.log(student.sleep()); // Tom正在睡觉
console.log(student instanceof Person); // false
console.log(student instanceof Student); // true

特点:

  • 支持多继承

缺点:

  • 效率较低,内存占用高
  • 无法获取父类不可枚举的方法(不可枚举方法,不能使用for in 访问到
  • 实例是子类的实例,不是父类的实例
2.6 寄生组合继承

原理:原型可以基于已有的对象来创建对象,var B = Object.create(A)以A对象为原型,生成了B对象。B继承了A的所有属性和方法。

// 父类
function Person(name) {
  // 属性
  this.name = name || 'Tony';
  // 实例方法
  this.sleep = function(){
    console.log(this.name + '正在睡觉');
  }
}
// 原型方法
Person.prototype.eat = function(food) {
  console.log(this.name + '正在吃:' + food);
};
// 子类
function Student(){
  this.name = name || 'Tom';
}
// 方法一
// 创建一个没有实例方法的类
// var Super = function(){};
// Super.prototype = Person.prototype;
// 将实例作为子类的原型
// Student.prototype = new Super();
// 方法二
Student.prototype = Object.create(new Person())
Student.prototype.constructor = Student

// 测试代码
var student = new Student();
console.log(student.name); // Tom
console.log(student.eat('chicken')); // Tom正在吃:chicken
console.log(student.sleep()); // Tom正在睡觉
console.log(student instanceof Person); // true
console.log(student instanceof Student); // true

特点:

  • 完美实现

3.js基本数据类型有哪些


js中有六种数据类型,包括五种基本数据类型(Number,String,Boolean,Undefined,Null),和一种复杂数据类型(Object)

typeof null 结果是什么

typeof 123   //Number

typeof ‘abc’  //String

typeof true //Boolean

typeof undefined //Undefined

typeof null //Object

typeof { } //Object

typeof [ ] //Object

typeof console.log() //Function

Null类型也只有一个值null。变量或属性赋值为null来表示空值。typeof null等于"object",而不等于"null",这个让人困惑的行为主要是为了向后兼容。

4.es6新特征


  1. 块级作用域、块级变量let、块级常量const
  2. 箭头函数
  3. 参数处理(默认参数/…)
  4. 模板字面量(模板字符串)
  5. 对象的扩展
  6. 解构赋值
  7. 模块(import/export)
  8. 类(class/extends)
  9. Promise

5.遍历数组的方法


  1. forEach
  2. for…of
  3. for…in
  4. map
  5. reduce
  6. filter
  7. every
  8. some
  9. find
  10. findIndex

6.遍历对象属性的方法


  1. for…in
  2. Object.keys
  3. Object.getOwnPropertyNames(obj) + forEach
  4. Reflect.ownKeys(obj) + forEach

7.数组能够调用的函数有那些,哪些会改变数组


  1. push
  2. pop
  3. splice
  4. slice
  5. shift
  6. unshift
  7. sort
  8. find
  9. findIndex
  10. map/filter/reduce 等函数式编程方法
    还有一些原型链上的方法:toString/valudOf

会改变原数组的方法

  1. sort // 返回改变数组
  2. reverse // 返回改变数组
  3. pop // 返回弹出元素
  4. push // 返回插入数组的长度
  5. shift // 返回弹出元素
  6. unshift // 返回插入数组的长度
  7. splice // 返回删除的元素

Vue.js

1.vue实例化生命周期


  1. beforeCreate (组件实例刚被创建,此时无法访问到 el 属性和 data 属性等)
  2. 双向绑定data, 声明methods方法
  3. created (组件实例创建完成,data属性已绑定,但还未生成dom, 无法使用$el)
  4. 将模板编译成函数,运行render方法返回vnode对象(virtual dom)
  5. beforeMount (模板挂载之前)
  6. mounted (模板挂载完成)
  7. beforeUpdate (组件更新之前)
  8. 重新渲染虚拟 dom,并通过 diff 算法对比 vnode 节点差异更新真实 dom (virtual DOM re-render and patch)
  9. updated (组件更新完成)
  10. beforeDestroy (组件销毁之前)
  11. 销毁数据监听,子组件和取消事件监听
  12. destroyed (阻碍你销毁完成)

2.Virtual Dom优缺点


优点:

  • 保证性能下限: 框架的虚拟 DOM 需要适配任何上层 API 可能产生的操作,它的一些 DOM 操作的实现必须是普适的,所以它的性能并不是最优的;但是比起粗暴的 DOM 操作性能要好很多,因此框架的虚拟 DOM 至少可以保证在你不需要手动优化的情况下,依然可以提供还不错的性能,即保证性能的下限;
  • 无需手动操作 DOM: 我们不再需要手动去操作 DOM,只需要写好 View-Model 的代码逻辑,框架会根据虚拟 DOM 和 数据双向绑定,帮我们以可预期的方式更新视图,极大提高我们的开发效率;
  • 跨平台: 虚拟 DOM 本质上是 JavaScript 对象,而 DOM 与平台强相关,相比之下虚拟 DOM 可以进行更方便地跨平台操作,例如服务器渲染、weex 开发等等。

缺点:

  • 无法进行极致优化: 虽然虚拟 DOM + 合理的优化,足以应对绝大部分应用的性能需求,但在一些性能要求极高的应用中虚拟 DOM 无法进行针对性的极致优化。

3.双向绑定原理


占位

4.传递参数的方式


4.1 父子组件

1.父传子(props)
2.子传父($emit)
3.父组件调用子组件方法($refs)

4.2 爷孙组件

通过 provide 和 inject,不受组件层级影响
provide 和 inject 主要为高阶插件/组件库提供用例。并不推荐直接用于应用程序代码中。

4.3 兄弟组件

EventBus

4.4 路由

query和params

5.Vue和Angular和React的对比


Angular
优点:全家桶,依赖注入
缺点:学习成本高

React
优点:UI库,数据单项流动
缺点:仅是View

Vue
优点:轻量级,渐进式,文档清晰
缺点:年龄小

6.Vue Dom渲染是异步的吗


Vue在调用Watcher更新视图时,并不会直接进行更新,而是把需要更新的Watcher加入到Queue队列里,然后把具体的更新方法flushSchedulerQueue 传给nexTick 进行调用。
Vue中的数据更新是异步的,意味着我们在修改完Data之后并不能立刻获取修改后的DOM元素,在Vue的nextTick回调中才能获取到修改后的Dom。

其他

1.浏览器缓存


强缓存

浏览器在加载资源时,会先根据本地缓存资源的 header 中的信息判断是否命中强缓存,如果命中则直接使用缓存中的资源不会再向服务器发送请求。

这里的 header 中的信息指的是 expires 和 cahe-control.

Expires
该字段是 http1.0 时的规范,它的值为一个绝对时间的 GMT 格式的时间字符串,比如 Expires:Mon,18 Oct 2066 23:59:59 GMT。这个时间代表着这个资源的失效时间,在此时间之前,即命中缓存。这种方式有一个明显的缺点,由于失效时间是一个绝对时间,所以当服务器与客户端时间偏差较大时,就会导致缓存混乱。

Cache-Control
Cache-Control 是 http1.1 时出现的 header 信息,主要是利用该字段的 max-age 值来进行判断,它是一个相对时间,例如 Cache-Control:max-age=3600,代表着资源的有效期是 3600 秒。cache-control 除了该字段外,还有下面几个比较常用的设置值:

no-cache:需要进行协商缓存,发送请求到服务器确认是否使用缓存。

no-store:禁止使用缓存,每一次都要重新请求数据。

public:可以被所有的用户缓存,包括终端用户和 CDN 等中间代理服务器。

private:只能被终端用户的浏览器缓存,不允许 CDN 等中继缓存服务器对其缓存。

Cache-Control 与 Expires 可以在服务端配置同时启用,同时启用的时候 Cache-Control 优先级高。

协商缓存

当强缓存没有命中的时候,浏览器会发送一个请求到服务器,服务器根据 header 中的部分信息来判断是否命中缓存。如果命中,则返回 304 ,告诉浏览器资源未更新,可使用本地的缓存。

这里的 header 中的信息指的是 Last-Modify/If-Modify-Since 和 ETag/If-None-Match.

Last-Modify/If-Modify-Since
浏览器第一次请求一个资源的时候,服务器返回的 header 中会加上 Last-Modify,Last-modify 是一个时间标识该资源的最后修改时间。

当浏览器再次请求该资源时,request 的请求头中会包含 If-Modify-Since,该值为缓存之前返回的 Last-Modify。服务器收到 If-Modify-Since 后,根据资源的最后修改时间判断是否命中缓存。

如果命中缓存,则返回 304,并且不会返回资源内容,并且不会返回 Last-Modify。

缺点:

短时间内资源发生了改变,Last-Modified 并不会发生变化。

周期性变化。如果这个资源在一个周期内修改回原来的样子了,我们认为是可以使用缓存的,但是 Last-Modified 可不这样认为,因此便有了 ETag。

ETag/If-None-Match
与 Last-Modify/If-Modify-Since 不同的是,Etag/If-None-Match 返回的是一个校验码。ETag 可以保证每一个资源是唯一的,资源变化都会导致 ETag 变化。服务器根据浏览器上送的 If-None-Match 值来判断是否命中缓存。

与 Last-Modified 不一样的是,当服务器返回 304 Not Modified 的响应时,由于 ETag 重新生成过,response header 中还会把这个 ETag 返回,即使这个 ETag 跟之前的没有变化。

Last-Modified 与 ETag 是可以一起使用的,服务器会优先验证 ETag,一致的情况下,才会继续比对 Last-Modified,最后才决定是否返回 304。

2.大列表处理


分段展示, requestAnimationFrame+DocumentFragment

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值