Vue2 核心原理
响应式系统
- 实现步骤
- 首先创建了一个新的空对象
- 设置原型,将对象的原型设置为函数的 prototype 对象。
- 让函数的 this 指向这个对象,执行构造函数的代码(为这个新对象添加属性)
- 判断函数的返回值类型,如果是值类型,返回创建的对象。如果是引用类型,就返回这个引用类型的对象。
function myNew(fn, ...args) {
//创建一个空对象并将对象的原型设置为函数的prototype对象
const obj = {};
obj.__proto__ = fn.prototype;
//以上两步可合成一步
//const obj = Object.create(fn.prototype)
//调用构造函数,并且this绑定到obj上
const value = fn.apply(obj, args);
// 如果构造函数有返回值,并且返回的是对象,就返回value ;否则返回obj
return value instanceof Object ? value : obj;
}
模板编译
- 实现步骤
- 获取类型的原型
- 获得对象的原型
- 一直循环判断对象的原型是否等于类型的原型,直到对象原型为
null
,因为原型链最终为null
//判断构造函数的 prototype 属性是否出现在对象的原型链中的任何位置。
function myInstanceof(left, right) {
let proto = Object.getPrototypeOf(left), // 获取对象的原型
prototype = right.prototype; // 获取构造函数的 prototype 对象
// 判断构造函数的 prototype 对象是否在对象的原型链上
while (true) {
if (!proto) return false;
if (proto === prototype) return true;
proto = Object.getPrototypeOf(proto);
}
}
虚拟 DOM
/**
* @description typeof 可以正确识别:Undefined、Boolean、Number、String、Symbol、Function 等类型的数据,
* 但是对于其他的都会认为是 object,比如 Null、Date 等,
* 所以通过 typeof 来判断数据类型会不准确。但是可以使用 Object.prototype.toString 实现。
*/
function typeOf(obj) {
let type = Object.prototype.toString.call(obj);
return type.slice(8, -1).toLowerCase();
}
console.log(typeOf(new Date()), typeOf(null), typeOf([]));
组件化
this 指向第一个参数
- call
- 传参方式:多个参数
- 立即执行
- apply
- 传参方式:第二个参数为数组或类数组,用数组接收多个参数
- 立即执行
- bind
- 等待执行
// bind 函数实现
Function.prototype.myBind = function (context) {
// 判断调用对象是否为函数
if (typeof this !== "function") {
throw new TypeError("Error");
}
// 获取参数
var args = [...arguments].slice(1),
fn = this;
return function Fn() {
// 根据调用方式,传入不同绑定值
return fn.apply(
this instanceof Fn ? this : context,
args.concat(...arguments)
);
};
};
// call函数实现
Function.prototype.myCall = function (context) {
// 判断调用对象
if (typeof this !== "function") {
console.error("type error");
}
// 获取参数
let args = [...arguments].slice(1),
result = null;
// 判断 context 是否传入,如果未传入则设置为 window
context = context || window;
// 将调用函数设为对象的方法
context.fn = this;
// 调用函数
result = context.fn(...args);
// 将属性删除
delete context.fn;
return result;
};
// apply 函数实现
Function.prototype.myApply = function (context) {
// 判断调用对象是否为函数
if (typeof this !== "function") {
throw new TypeError("Error");
}
let result = null;
// 判断 context 是否存在,如果未传入则为 window
context = context || window;
// 将函数设为对象的方法
context.fn = this;
// 调用方法
result = arguments[1] ? context.fn(...arguments[1]) : context.fn();
// 将属性删除
delete context.fn;
return result;
};