手写instanceof (详解原型链) 和 实现绑定解绑和派发的事件类
A instanceof B 是判断 A 是否继承自B,是返回true, 否返回false
再精确点就是判断B 是否 再 A 的 原型链上,
什么是原型链,举个例子:
我们定义三个对象:
const grandFather = {
name: 'liu',
age: 80
},father = {
age: 50
},son = {
age: 18
};
怎么让这三个对象形成一种继承关系呢 ? 让father 和 son 继承 grandFather 的 name 属性
我们知道对象上有一个内部属性__proto__ , 该属性的属性值指向改对象的原型,
我们是否可以这样写:
const grandFather = {
name: 'liu',
age: 80
},father = {
age: 50,
__proto__: grandFather
},son = {
age: 18,
__proto__: father
};
console.log(father.name);
console.log(son.name);
ok ,打印出:
原理就是如果对象本身没有查找的属性, 就会沿着原型链也就是__proto__属性往上找直到为null为止。
这就是原型链的概念。
但是__proto__前后加双下划线说明它本质是一个内部属性, 而不是一个正式的对外的API,只是由于浏览器广泛支持,才被加入了ES6,
所以只有浏览器必须部署这个属性,其他运行环境不一定要部署,因此,无论从语义的角度,还是从兼容性的角度,都最好不要使用这个属性,
而是使用Object.setPrototyleOf(写操作), Object.getPrototyleOf(读操作), Object.create(生成操作),
所以我们改成这样:
const grandFather = {
name: 'liu',
age: 80
},father = {
age: 50,
},son = {
age: 18,
};
Object.setPrototypeOf(father, grandFather);
Object.setPrototypeOf(son, father);
console.log(father.name);
console.log(son.name);
打印结果是一样的。
又或者这样:
const grandFather = {
name: 'liu',
age: 80
},
father = Object.create(grandFather),
son = Object.create(father);
father.age = 50;
son.age = 18;
console.log(father.name);
console.log(son.name);
打印结果也是一样的。
原型链大家弄清楚了 我们就可以写一个instanceof 的 方法了:
function instanceofMy (A, B) {
const proto = Object.getPrototypeOf(A), prototype = B.prototype;
if (proto === null || proto === undefined) {
return false;
} else if (proto === prototype) {
return true;
} else {
return instanceofMy(Object.getPrototypeOf(proto), B);
}
}
// 测试
console.log(instanceofMy({}, Object));
console.log(instanceofMy([], Array));
function Test() {}
let test = new Test();
console.log(instanceofMy(test, Test));
console.log(instanceofMy('', Array));
测试结果:
利用递归来沿着原型链往上查找, 有同学不想用递归,太耗费内存了,我们可以改成while循环:
function instanceofMy (A, B) {
let proto = Object.getPrototypeOf(A), prototype = B.prototype;
while (proto !== null && proto !== undefined) {
if (proto === prototype) {
return true;
} else {
proto = Object.getPrototypeOf(proto);
}
}
return false;
}
proto = null 作为while循环的出口, 出来了就return false。
---------------------------------------------------------------------------分割线
实现绑定/派发自定义事件的事件类
有时候我们需要自定义一个事件并在特定的条件下手动触发该事件绑定的函数,
这个时候我们就需要这样一个事件类:
class Event {
constructor() {
// 存事件和回调函数的对象
this.cache = {};
}
// 绑定事件
on (type, callback) {
if (this.cache[type] && !this.cache[type].includes(callback)) {
this.cache[type].push(callback);
} else if (this.cache[type] && this.cache[type].includes(callback)) {
return this;
} else {
this.cache[type] = [callback];
}
return this;
} // 触发事件
trigger(type, ...params) {
if (this.cache[type]) {
this.cache[type].forEach(fn => {
fn(...params);
})
}
return this;
} // 解绑事件
off(type, callback) {
// 传了callback清除指定callback, 没传清空数组
if (this.cache[type] && this.cache[type].includes(callback)) {
this.cache[type].split(this.cache[type].findIndex(callback), 1);
} else if (this.cache[type] && !callback) {
this.cache[type] = [];
}
return this;
}
}
const event = new Event(); // 测试
function start(str) {
console.log(str + ' start');
}
function end(str) {
console.log(str + ' end');
}
event.on('start', start)
.on('start', end)
.trigger('start', 'Hello world')
.off('start')
;
我们先给一个自定start事件绑定两个函数,然后传参触发, 最后解绑
打印结果:
这样这个事件类就写完了
手写instanceof (详解原型链) 和 实现绑定解绑和派发的事件类的更多相关文章
- 前端面试手写代码——模拟实现new运算符
目录 1 new 运算符简介 2 new 究竟干了什么事 3 模拟实现 new 运算符 4 补充 预备知识: 了解原型和原型链 了解this绑定 1 new 运算符简介 MDN文档:new 运算符创建 ...
- JavaScript提高篇之面向对象之单利模式工厂模型构造函数原型链模式
1.单例模式 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UT ...
- 手写promise
写在前面: 在目前的前端分开中,我们对于异步方法的使用越来越频繁,那么如果处理异步方法的返回结果,如果优雅的进行异步处理对于一个合格的前端开发者而言就显得尤为重要,其中在面试中被问道最多的就是对Pro ...
- javascript中的原型和原型链(三)
1. 图解原型链 1.1 “铁三角关系”(重点) function Person() {}; var p = new Person(); 这个图描述了构造函数,实例对象和原型三者之间的关系,是原型链的 ...
- JavaScript ES5类 原型 原型链 组合、原型、寄生式继承
ES5类 原型 原型链 继承 JavaScript中,原型是相对于构造函数(类)的叫法(或者说概念),原型链是相对于构造函数(类)的实例对象的叫法. 对于JavaScript对象,如果在对象自身上找 ...
- mnist手写数字识别——深度学习入门项目(tensorflow+keras+Sequential模型)
前言 今天记录一下深度学习的另外一个入门项目——<mnist数据集手写数字识别>,这是一个入门必备的学习案例,主要使用了tensorflow下的keras网络结构的Sequential模型 ...
- 浅析MyBatis(二):手写一个自己的MyBatis简单框架
在上一篇文章中,我们由一个快速案例剖析了 MyBatis 的整体架构与整体运行流程,在本篇文章中笔者会根据 MyBatis 的运行流程手写一个自定义 MyBatis 简单框架,在实践中加深对 MyBa ...
- 【js基础修炼之路】— 我理解的原型链
提起原型链,大家并不陌生,但是对于新人来说一提到原型方面的东西就会比较懵.在我自一次面试的时候,面试官也给我提了这样的问题,当时就按照我的理解说了一些,但是很肤浅,在此我希望给刚入门的前端小伙伴聊一下 ...
- js---15深拷贝浅拷贝 原型链
//&&得到的结果不是布尔类型,如果前面都是 true就执行最后一个,并返回最后一个表达式的值,前面有一个为false,后面不执行,返回前面表达式的值 var a = 3; var b ...
随机推荐
- TCP/IP协议的分层
T C P / I P协议族是一组不同的协议组合在一起构成的协议族.尽管通常称该协议族为 T C P / I P,但T C P和I P只是其中的两种协议而已(该协议族的另一个名字是 I n t e r ...
- go构建脚本ansible分发时出现的问题总结“non-zero return code”
背景介绍: 在Jenkins服务器配置go项目发布脚本,编译完成后,使用ansible分发到部署服务器上,然后将启动项目脚本start_coachcore.sh发布到目标服务器上,执行启动,目标服务器 ...
- centos7中python3.6报错ModuleNotFoundError: No module named '_ssl' 或者 Max retries exceeded with url: / (Caused by SSLError("Can't connect to HTTPS URL because the SSL module is not available.",))
如果在运行爬虫时报此错:requests.exceptions.SSLError: HTTPSConnectionPool(host='www.baidu.com', port=443): Max r ...
- 迎国庆 itest(爱测试) 4.1.0 发布,开源BUG 跟踪管理 & 敏捷测试管理软件
v4.1.0 下载地址 :itest下载 itest 简介:查看简介 在线体验 https://itest.work/demo/ V4.1.0 根据用户反馈,共增加了23个更新:其中有11个功能增强和 ...
- 后台传给前端字符串为null或解析JSON字符错误——SyntaxError: JSON.parse: unterminated string literal at line 1 column 9018638 of the JSON data
第一种情况: 第二种情况: 首先看看你的JSONObject或JSONArray的引用有没有Getter()和Setter()方法,这个必须要加上 问题:两张表双向多对一.一对多时.响应给后台使,出现 ...
- C++ int 和string互相转化
1.int转换成string );//"-12" );//"12" +);//"1" 2.string转换成int );//"-1 ...
- vmvare虚拟机篇
新建虚拟机-典型-稍后安装-Linux-管理-从磁盘删除-虚拟机名称-位置- 安装Tools-用于虚拟机和本地文件共享和传送 网络适配器桥接模式-桥接本地网卡 NAT模式-再重新连接本地网卡 仅主机模 ...
- Testng 简介
Testng是一套开源测试框架,是从Junit继承而来,testng意为test next generation,主要有以下特性: annotations 注释,如 @test @BeforeMet ...
- [PHP] laravel5.5 搭建流程
1.nginx 配置 server { listen 80; server_name laravel5-test.d.com; charset utf-8; location ...
- <Tree> 298 250 366 199(高频) 98(高频)
298. Binary Tree Longest Consecutive Sequence 先序遍历,根左右.如果该节点的 value == 父节点value + 1, 则长度+1; 否则重置为1. ...