一、介绍一下this
- 1】其实大部分情况下可以用一句话来概括,this总是指向调用该函数的对象。
- 2】函数的调用方式决定了 this 的指向不同:
- 1.普通函数调用,此时 this 指向 window
- 2.构造函数调用, 此时 this 指向 实例对象
- 3.对象方法调用, 此时 this 指向 该方法所属的对象
- 4.通过事件绑定的方法, 此时 this 指向 绑定事件的对象
- 5.定时器函数, 此时 this 指向 window
- 3】对于常规的函数来说,谁调用该函数,this就指向该调用者,全局环境下调用函数执行。
- 4】this指向window 对于箭头函数的this总结如下: 箭头函数不绑定this,箭头函数中的this相当于普通变量。 箭头函数的this寻值行为与普通变量相同,在作用域中逐级寻找。 箭头函数的this无法通过bind,call,apply来直接修改(可以间接修改)。
5】改变作用域中this的指向可以改变箭头函数的this。 描述this问题,这里我们可以扩展说明如何去改变this指向,通过bind,call,apply,然后说说他们的区别,懂得多的话, 可以说说他们的实现原理,或者手写bind,call,apply的实现。
二、请介绍一下节流函数和防抖函数,简单实现节流函数和防抖函数
- “节流”与“防抖”的本质: 这两个东西都以闭包的形式存在。 它们通过对事件对应的回调函数进行包裹、以自由变量的形式缓存时间信息,最后用 setTimeout 来控制事件的触发频率。
- 防抖函数:就是指触发事件后,在 n 秒内函数只能执行一次,如果触发事件后在 n 秒内又触发了事件,则会重新计算函数延执行时间。
所谓节流:就是指连续触发事件但是在 n 秒中只执行一次函数。节流会稀释函数的执行频率。
对于节流,一般有两种方式可以实现,分别是时间戳版和定时器版。
三、请介绍一下重排(Reflow)与重绘(Repaint)
- 重排:当我们对 DOM 的修改引发了 DOM 几何尺寸的变化(比如修改元素的宽、高或隐藏元素等)时, 浏览器需要重新计算元素的几何属性(其他元素的几何属性和位置也会因此受到影响), 然后再将计算的结果绘制出来。这个过程就是回流(也叫重排)。 重绘:当我们对 DOM 的修改导致了样式的变化、却并未影响其几何属性(比如修改了颜色或背景色)时, 浏览器不需重新计算元素的几何属性、直接为该元素绘制新的样式(跳过了上图所示的回流环节)。这个过程叫做重绘。 由此我们可以看出,重绘不一定导致回流,回流一定会导致重绘。 硬要比较的话,回流比重绘做的事情更多,带来的开销也更大。但这两个说到底都是吃性能的, 所以都不是什么善茬。我们在开发中,要从代码层面出发,尽可能把回流和重绘的次数最小化。
四、闭包
- 首先说明什么是闭包,闭包简单来说就是函数嵌套函数,内部函数引用来外部函数的变量,从而导致垃圾回收 机制没有把当前变量回收掉,这样的操作带来了内存泄漏的影响,当内存泄漏到一定程度会影响你的项目运行 变得卡顿等等问题。因此在项目中我们要尽量避免内存泄漏。
五、原型
- 构造函数是一种特殊的方法,主要用来在创建对象时初始化对象。每个构造函数都有prototype(原型)(箭头函数以及Function.prototype.bind()没有)属性, 这个prototype(原型)属性是一个指针,指向一个对象,这个对象的用途是包含特定类型的所有实例共享的 属性和方法,即这个原型对象是用来给实例对象共享属性和方法的。每个实例对象的__proto__都指向这个 构造函数/类的prototype属性。
- 面向对象的三大特性:继承/多态/封装 关于new操作符:
- 1. new执行的函数, 函数内部默认生成了一个对象
- 2. 函数内部的this默认指向了这个new生成的对象
- 3. new执行函数生成的这个对象, 是函数的默认返回值
- 原型链实际上在上面原型的问题中就有涉及到,在原型的继承中,我们继承来多个原型,这里再提一下实现完美 继承的方案,通过借助寄生组合继承,PersonB.prototype = Object.create(PersonA.prototype) 这是
- 当我们实例化PersonB得到实例化对象,访问实例化对象的属性时会触发get方法,它会先在自身属性上查 找,如果没有这个属性,就会去__proto__中查找,一层层向上直到查找到顶层对象Object,这个查找的过程 就是原型链来。
原型链是实现继承的主要方法。
1、扩展原型对象实现继承
2、利用 apply(),和 call 实现继承
六、ES6新特性
1.ES6引入来严格模式
变量必须声明后在使用
函数的参数不能有同名属性, 否则报错
不能使用with语句 (说实话我基本没用过)
不能对只读属性赋值, 否则报错
不能使用前缀0表示八进制数,否则报错 (说实话我基本没用过)
不能删除不可删除的数据, 否则报错
不能删除变量delete prop, 会报错, 只能删除属性delete global[prop]
eval不会在它的外层作用域引入变量
eval和arguments不能被重新赋值
arguments不会自动反映函数参数的变化
不能使用arguments.caller (说实话我基本没用过)
不能使用arguments.callee (说实话我基本没用过)
禁止this指向全局对象
不能使用fn.caller和fn.arguments获取函数调用的堆栈 (说实话我基本没用过)
增加了保留字(比如protected、static和interface)2.关于let和const新增的变量声明
3.变量的解构赋值
4.字符串的扩展
includes():返回布尔值,表示是否找到了参数字符串。
startsWith():返回布尔值,表示参数字符串是否在原字符串的头部。
endsWith():返回布尔值,表示参数字符串是否在原字符串的尾部。
5.数值的扩展
Number.isFinite()用来检查一个数值是否为有限的(finite)。
Number.isNaN()用来检查一个值是否为NaN。
6.函数的扩展
函数参数指定默认值
7.数组的扩展
扩展运算符
8.对象的扩展
对象的解构
9.新增symbol数据类型
10.Set 和 Map 数据结构
ES6 提供了新的数据结构 Set。它类似于数组,但是成员的值都是唯一的,没有重复的值。 Set 本身是一个构造函数,用来生成 Set 数据结构。
Map它类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键。
11.Proxy
Proxy 可以理解成,在目标对象之前架设一层“拦截”,外界对该对象的访问
都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。
Proxy 这个词的原意是代理,用在这里表示由它来“代理”某些操作,可以译为“代理器”。
Vue3.0使用了proxy
12.Promise
Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大。
特点是:
对象的状态不受外界影响。
一旦状态改变,就不会再变,任何时候都可以得到这个结果。
13.async 函数
async函数对 Generator 函数的区别:
(1)内置执行器。
Generator 函数的执行必须靠执行器,而async函数自带执行器。也就是说,async函数的执行,与普通函数一模一样,只要一行。
(2)更好的语义。
async和await,比起星号和yield,语义更清楚了。async表示函数里有异步操作,await表示紧跟在后面的表达式需要等待结果。
(3)正常情况下,await命令后面是一个 Promise 对象。如果不是,会被转成一个立即resolve的 Promise 对象。
(4)返回值是 Promise。
async函数的返回值是 Promise 对象,这比 Generator 函数的返回值是 Iterator 对象方便多了。你可以用then方法指定下一步的操作。
14.Class
class跟let、const一样:不存在变量提升、不能重复声明...
ES6 的class可以看作只是一个语法糖,它的绝大部分功能
ES5 都可以做到,新的class写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已。
15.Module
ES6 的模块自动采用严格模式,不管你有没有在模块头部加上"use strict";。
import和export命令以及export和export default的区别七、js 的内置对象有哪些?列举一下 arry 和 string 的常用方法?
本地对象为 array obj regexp 等可以 new 实例化
内置对象为 gload Math 等不可以实例化的
宿主为浏览器自带的 document,window 等
JavaScript 常见的内置对象有 Object,Math,String,Array,Number,Function,Boolean,JSON 等,其中 Object 是所有对象的基类,采用了原型继承方式.
String:charAt(); charCodeAt(); indexOf(); match(); replace(); search(); slice(); toUpperCase(); toLowerCase(); 等方法
Array:shift(); unshift(); pop(); push(); concat(); reverse(); splice(); slice(); 等方法
八、例举 3 种强制类型转换和 2 种隐式类型转换?
强制:parseInt()、parseFloat()、Number() 隐式:== 、console.log()、alert()
十 、深拷贝浅拷贝
深拷贝:通过利用JSON.parse(JSON.stringify())来实现深拷贝的目的,但利用JSON拷贝也是有缺点的, 当要拷贝的数据中含有undefined/function/symbol类型是无法进行拷贝的,当然我们想项目开发中需要 深拷贝的数据一般不会含有以上三种类型,如有需要可以自己在封装一个函数来实现
浅拷贝只复制指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存。
深拷贝会另外创造一个一模一样的对象,新对象跟原对象不共享内存,修改新对象不会改到原 对象。
深拷贝的方法:
1、递归拷贝
2、使用 Object.create()方法
3、jquery 有提供一个$.extend 也可以实现 4、函数库 lodash,也有提供 cloneDeep 用来实现
十一、vue 原理双向绑定
Vue是采用数据劫持配合发布者-订阅者模式,通过Object.defineProperty来()来劫持各个属性的getter和setter
在数据发生变化的时候,发布消息给依赖收集器,去通知观察者,做出对应的回调函数去更新视图。
具体就是:
MVVM作为绑定的入口,整合Observe,Compil和Watcher三者,通过Observe来监听model的变化
通过Compil来解析编译模版指令,最终利用Watcher搭起Observe和Compil之前的通信桥梁
从而达到数据变化 => 更新视图,视图交互变化(input) => 数据model变更的双向绑定效果。十二、Vue.js组件设计原则
页面上把每个独立可以交互的区域视为一个组件
每个组件对应一个工程目录,组件所需要的各种资源在这个目录下就近维护
页面不过是组件的容器,组件可以嵌套自由组合形成完整的页面