1. 判断一个变量是数组有几种方式?
(1) instanceof ,原型判断,写法:变量 instanceof Array
(2) __proto__,原型判断,写法:变量.__proto__ === Array.prototype
(3) constructor,原型判断,写法:变量.constructor === Array
(4) .prototype.toString,通过object类型的副属性class去判断的其中函数的class是Function,结果是[object Function], 普通的对象是Object,结果是[object Object],写法:Object.prototype.toString.call(变量) === '[object Array]'
(5) Array.isArray,es6新增的方法,写法:Array.isArray(变量)
2.tree-shaking原理
参考原网址详解,十分详细,清晰明了
https://zhuanlan.zhihu.com/p/127804516
3.flex布局的详解
https://www.runoob.com/w3cnote/flex-grammar.html
4.vue.nextTick原理
Vue.nextTick 的原理和用途 - 知乎
5.css垂直居中的方法
https://www.cnblogs.com/qianxiaoPro/p/14276519.html
6.ES5的继承和ES6的继承有什么区别?
ES5的继承时通过prototype或构造函数机制来实现。ES5的继承实质上是先创建子类的实例对象,然后再将父类的方法添加到this上(Parent.apply(this))。
ES6的继承机制完全不同,实质上是先创建父类的实例对象this(所以必须先调用父类的super()方法),然后再用子类的构造函数修改this。
具体的:ES6通过class关键字定义类,里面有构造方法,类之间通过extends关键字实现继承。子类必须在constructor方法中调用super方法,否则新建实例报错。因为子类没有自己的this对象,而是继承了父类的this对象,然后对其进行加工。如果不调用super方法,子类得不到this对象。
ps:super关键字指代父类的实例,即父类的this对象。在子类构造函数中,调用super后,才可使用this关键字,否则报错。
7.浏览器渲染页面的过程
https://www.cnblogs.com/tootwo2/p/7208890.html
8.能否模拟实现 JS 的 new 操作符
(1)首先创建了一个新的空对象
(2)设置原型,将对象的原型设置为函数的prototype对象。
(3)让函数的this指向这个对象,执行构造函数的代码(为这个新对象添加属性)
(4)判断函数的返回值类型,如果是值类型,返回创建的对象。如果是引用类型,就返回这个引用类型的对象。
// new 操作的实现
function newOperator(ctor) {
if (typeof ctor !== "function") {
throw "newOperator function the first param must be a function";
}
newOperator.target = ctor;
var newObj = Object.create(ctor.prototype);
var argsArr = [].slice.call(arguments, 1);
var ctorReturnResult = ctor.apply(newObj, argsArr);
var isObject =
typeof ctorReturnResult === "object" && ctorReturnResult !== null;
var isFunction = typeof ctorReturnResult === "function";
if (isObject || isFunction) {
return ctorReturnResult;
}
return newObj;
}
案例来源:https://juejin.cn/post/7075332630417244173
以下4点借鉴来源:https://juejin.cn/post/7075332630417244173
9.继承(含 es6)、多种继承方式
function Animal(name) {
// 属性
this.name = name || "Animal";
// 实例方法
this.sleep = function () {
console.log(this.name + "正在睡觉!");
};
}
// 原型方法
Animal.prototype.eat = function (food) {
console.log(this.name + "正在吃:" + food);
};
(1)第一种是以原型链的方式来实现继承,但是这种实现方式存在的缺点是,在包含有引用类型的数据时,会被所有的实例对象所共享,容易造成修改的混乱。还有就是在创建子类型的时候不能向超类型传递参数。
// 原型链继承
function Cat() {}
Cat.prototype = new Animal("小黄"); // 缺点 无法实现多继承 来自原型对象的所有属性被所有实例共享
Cat.prototype.name = "cat";
(2)第二种方式是使用借用构造函数的方式,这种方式是通过在子类型的函数中调用超类型的构造函数来实现的,这一种方法解决了不能向超类型传递参数的缺点,但是它存在的一个问题就是无法实现函数方法的复用,并且超类型原型定义的方法子类型也没有办法访问到。
// 借用构造函数继承
function Cat() {
Animal.call(this, "小黄");
// 缺点 只能继承父类实例的属性和方法,不能继承原型上的属性和方法。
}
(3)第三种方式是组合继承,组合继承是将原型链和借用构造函数组合起来使用的一种方式。通过借用构造函数的方式来实现类型的属性的继承,通过将子类型的原型设置为超类型的实例来实现方法的继承。这种方式解决了上面的两种模式单独使用时的问题,但是由于我们是以超类型的实例来作为子类型的原型,所以调用了两次超类的构造函数,造成了子类型的原型中多了很多不必要的属性。
(4)第四种方式是原型式继承,原型式继承的主要思路就是基于已有的对象来创建新的对象,实现的原理是,向函数中传入一个对象,然后返回一个以这个对象为原型的对象。这种继承的思路主要不是为了实现创造一种新的类型,只是对某个对象实现一种简单继承,ES5 中定义的 Object.create() 方法就是原型式继承的实现。缺点与原型链方式相同。
function object(o) {
function F() {}
F.prototype = o;
return new F();
}
(5)第五种方式是寄生式继承,寄生式继承的思路是创建一个用于封装继承过程的函数,通过传入一个对象,然后复制一个对象的副本,然后对象进行扩展,最后返回这个对象。这个扩展的过程就可以理解是一种继承。这种继承的优点就是对一个简单对象实现继承,如果这个对象不是我们的自定义类型时。缺点是没有办法实现函数的复用。
function createAnother(original) {
var clone = object(original); //通过调用object函数创建一个新对象
clone.sayHi = function () {
//以某种方式来增强这个对象
alert("hi");
};
return clone; //返回这个对象
}
(6)第六种方式是寄生式组合继承,组合继承的缺点就是使用超类型的实例做为子类型的原型,导致添加了不必要的原型属性。寄生式组合继承的方式是使用超类型的原型的副本来作为子类型的原型,这样就避免了创建不必要的属性。
function extend(subClass, superClass) {
var prototype = object(superClass.prototype); //创建对象
prototype.constructor = subClass; //增强对象
subClass.prototype = prototype; //指定对象
}
10.箭头函数和普通函数的区别
箭头函数没有this,this是继承于当前的上下文,不能通过call,apply,bind去改变 this
箭头函数没有自己的 arguments 对象,但是可以访问外围函数的 arguments 对象
不能通过 new 关键字调用(不能作为构造函数),同样也没有 new.target 和原型
11.vue 生命周期
beforeCreate 实例化之前这里能拿到this,但是还不能拿到data里面的数据
created 实例化之后
beforeMount()
mounted() $el
beforeUpdate
updated
beforeDestroy 清除定时/移除监听事件
destroyed
// 被keep-alive 包裹的
// keep-alive 标签 include exclude max
activated() {},
deactivated() {},
// 父子
父beforeCreate->父created->父beforeMount->子beforeCreate->子created->子beforeMount->子mounted->父mounted。
// 离开页面:实例销毁 --> DOM卸载
parent beforeDestroy
child beforeDestroy
child destroyed
parent destroyed
12.Vue3 有哪些变化
(1)新增了三个组件:Fragment 支持多个根节点、Suspense 可以在组件渲染之前的等待时间显示指定内容、Teleport 可以让子组件能够在视觉上跳出父组件(如父组件 overflow:hidden)
(2)新增指令 v-memo,可以缓存 html 模板,比如 v-for 列表不会变化的就缓存,简单说就是用内存换时间
支持 Tree-Shaking,会在打包时去除一些无用代码,没有用到的模块,使得代码打包体积更小
(3)新增 Composition API 可以更好的逻辑复用和代码组织,同一功能的代码不至于像以前一样太分散,虽然 Vue2 中可以用 minxin 来实现复用代码,但也存在问题,比如方法或属性名会冲突,代码来源也不清楚等
用 Proxy 代替 Object.defineProperty 重构了响应式系统,可以监听到数组下标变化,及对象新增属性,因为监听的不是对象属性,而是对象本身,还可拦截 apply、has 等 13 种方法
(4)重构了虚拟 DOM,在编译时会将事件缓存、将 slot 编译为 lazy 函数、保存静态节点直接复用(静态提升)、以及添加静态标记、Diff 算法使用 最长递增子序列 优化了对比流程,使得虚拟 DOM 生成速度提升 200%
(5)支持在 里使用 v-bind,给 CSS 绑定 JS 变量(color: v-bind(str))
(6)用 setup 代替了 beforeCreate 和 created 这两个生命周期
(7)新增了开发环境的两个钩子函数,在组件更新时 onRenderTracked 会跟踪组件里所有变量和方法的变化、每次触发渲染时 onRenderTriggered 会返回发生变化的新旧值,可以让我们进行有针对性调试
tips: 毕竟 Vue3 是用 TS 写的,所以对 TS 的支持度更好,Vue3 不兼容 IE11