详解JavaScript中的原型和继承-转自颜海镜大大
本文将会介绍面向对象,继承,原型等相关知识,涉及的知识点如下:
- 面向对象与继承
- CEOC
- OLOO
- 臃肿的对象
- 原型与原型链
- 修改原型的方式
面向对象与继承
最近学习了下python,还写了篇博文《重拾编程乐趣——我的Python笔记》,加深了我对面向对象的一些理解。
我们会对我们写的程序进行抽象,而不同的语言都提供了不同的抽象工具,比如各种语言里面的数组,集合(键值数组,哈希表,字典等)等提供了对数据的抽象;而VB里面的子程序,类C语言里面的函数,提供了抽象代码段的能力。
有时我们希望将数据和对数据的操作封装到一起,这被称作对象,是一种更高唯独的抽象工具,而这种抽象工具——对象可以对现实世界进行建模。
现实世界中的事物都有一些联系,比如我们可以抽象出来猫,然后又公猫,母猫,显然公猫应该拥有猫的特性,这也就是继承,细分的事物应该有高纬度事物的特点。
想要实现对象和继承这套思维,目前有两种实现方法,分别是CEOC和OLOO。
CEOC
CEOC(class extend other class)是一套基于类和实例的实现方式,这种方式实用的比较广泛,大部分流星的面向对象语言都在使用,比如java,python等。
类作为对象的抽象描述,对象是类的实例,也称作类的泛化,泛化和抽象对应。最恰当的类比就是盖房子了,类就相当于房子的图纸,图纸是对房子属性和功能的描述,根据图纸可以盖很多个类似的房子;另一种类比就是磨具和零件,磨具相当于类,零件相当于对象,通过磨具我们可以造出来很多零件。
其实与其说是面向对象还不如说是面向类编程,在这种机制中解决上面提到的继承逻辑时,是在类上实现的,子类可以继承父类。
在类的机制中更像是对工厂里通过磨具造零件机制的模拟,而非动物世界这种繁衍继承机制的模拟,下面介绍的OLOO则是对世界更好的模拟。
OLOO
OLOO(object link other object)是一套基于对象和原型的实现方式,这种方式唯一实现广泛语言就是js了,熟悉类机制的同学,初次接触这个,可能会觉得不是很好理解,而很多前端同学理解的也不是很明白,之前写过一篇原型的文章,推荐大家阅读《JavaScript原型之路》。
其实面向类的机制有些多此一举了,因为最后使用的是对象,而不是类,那么我们直接让对象可以集成对象不就行了,在这种机制中可以通过某种操作让对象和对象之间可以建立继承的关系,当继承的对象(子对象)中没有某些属性时可以去被继承的对象(父对象)中去查找。
在OLOO中,父对象也可以成为子对象的原型,这有些类似我们的人类的繁衍,每一个人都是一个对象,都是父母所生,而不是用模版建造出来的,每一个人都有一个父亲,孩子和父亲之间有一种特殊的关系,成为父子。
臃肿的对象
来说说JS中的对象机制,JS中的对象显得有些臃肿,JS中的对象承接了两个功能,一是面向对象机制中的对象,另一个是数据抽象中的集合——其他语言中称为键值数组,哈希表或字典。
其实在其它语言中的对象都不耦合集合的功能,比如python中有字典,php中有键值数组,好在es2015中引入新的map类型,来把这个功能解耦出去,但我相信很多人都习惯这么使用了o(╯□╰)o
而本文所说的对象不包括后面的这一部分功能,特指js中面向对象机制中的对象。
原型与原型链
js语言是基于原型的语言,在js中几乎一切都是对象,每个对象都有原型,而原型也是一个对象,也有自己的原型,从而形成原型链。
当试图访问一个对象的属性时,它不仅仅在该对象上搜寻,还会搜寻该对象的原型,以及该对象的原型的原型,依此层层向上搜索,直到找到一个名字匹配的属性或到达原型链的末尾。
js中提到原型可能有不同的意思,我们得先区分清楚,需要清除到底是哪个原型:
- js是基于原型的语言中的prototype
- 每个对象都有自己的原型中的prototype
- 每个函数都有一个原型属性中的prototype
第一点中的prototype是一个概念,一种机制,而不是具体的什么东西。
第二点中的prototype是说每个对象都有自己的原型对象(父对象),下面我们用[[Prototype]]来指代这个原型对象。
第三点和第二点很容易混淆,每个函数都有一个原型属性,我们用prototype来指代。
es5带来了查看对象原型的方法——Object.getPrototypeOf,该方法返回指定对象的原型(也就是该对象内部属性[[Prototype]]的值)。
console.log(Object.getPrototypeOf({}))
>>> Object.prototype
es6带来了另一种查看对象原型的方法——Object.prototype.__proto__,一个对象的proto 属性和自己的内部属性[[Prototype]]指向一个相同的值 (通常称这个值为原型),原型的值可以是一个对象值也可以是null(比如说Object.prototype.proto的值就是null)。
({}).__proto__
>>> Object.prototype
下面举个例子来说说原型与原型链,以及访问对象属性的时候会发生的行为:
// a ---> b 代表b是a的原型
修改原型的方式
在js中创建和修改原型的方法有很多,下面一一列举出来。
在下面的例子中我们将对象a的[[Prototype]]指向b。
// a ---> b
使用普通语法创建对象
这是最容易被大家忽略的方法,在js中你是绕不过原型的,不经意间就创建了原型
var o = {a: 1};
// o ---> Object.prototype ---> null
var a = [];
// a ---> Array.prototype ---> Object.prototype ---> null
function f(){}
// f ---> Function.prototype ---> Object.prototype ---> null
这种方法无法让a的[[Prototype]]指向b。
使用构造器创建对象
构造函数就是一个普通的函数,只不过这次不是直接调用函数,而是在函数前加上new关键字。
每个函数都有一个prototype属性,通过new关键字新建的对象的原型会指向构造函数的prototype属性,所以我们可以修改构造函数的prototype属性从而达到操作对象原型的目的。
为了让b继承a,需要有一个构造函数A
var b = {};
function A() {};
A.prototype = b;
var a = new A();
Object.getPrototypeOf(a) === b;
// true
// a ---> A.prototype === b
使用 Object.create 创建对象
ES5带来了Object.create接口,可以让我们直接设置一个对象原型
var b = {};
var a = Object.create(b);
Object.getPrototypeOf(a) === b;
// true
// a ---> b
Object.setPrototypeOf
ES6带来了另一个接口,可以绕过创建对象的过程,直接操作原型
var a = {};
var b = {};
Object.setPrototypeOf(a, b);
Object.getPrototypeOf(a) === b;
// true
// a ---> b
proto
ES6还带来了一个属性,通过这个属性也可以直接操作原型
var a = {};
var b = {};
a.__proto__ = b;
Object.getPrototypeOf(a) === b;
// true
// a ---> b
注意这个属性在ES6规范的附录中,也就意味着不是所有的环境都会有这个属性。
使用 class 关键字
ES6引入了以class语法糖,通过extends关键字我们也可以实现继承,但是无法直接操作对象的原型,而是要借助“类”,其实就是构造函数和函数的prototype属性。
class B {}
class A extends B {}
var a = new A();
Object.getPrototypeOf(a) === A.prototype;
// true
// a ---> A.prototype === B的实例
总结
详解JavaScript中的原型和继承-转自颜海镜大大的更多相关文章
- 详解JavaScript中的原型
前言 原型.原型链应该是被大多数前端er说烂的词,但是应该还有很多人不能完整的解释这两个内容,当然也包括我自己. 最早一篇原型链文章写于2019年07月,那个时候也是费了老大劲才理解到了七八成,到现在 ...
- 详解Javascript中的原型与原型链
目录 知识点 参考资料 结束语 知识点 面向对象编程 我们熟悉的Java和C#里,面向对象的两个基本概念是类class和实例instance,而ES6以前的Javascript并没有设计class. ...
- (转载)详解Javascript中prototype属性(推荐)
在典型的面向对象的语言中,如java,都存在类(class)的概念,类就是对象的模板,对象就是类的实例.但是在Javascript语言体系中,是不存在类(Class)的概念的,javascript中不 ...
- 【转】详解JavaScript中的this
ref:http://blog.jobbole.com/39305/ 来源:foocoder 详解JavaScript中的this JavaScript中的this总是让人迷惑,应该是js众所周知的坑 ...
- 详解javascript中的this对象
详解javascript中的this对象 前言 Javascript是一门基于对象的动态语言,也就是说,所有东西都是对象,一个很典型的例子就是函数也被视为普通的对象.Javascript可以通过一定的 ...
- 【转】JavaScript中的原型和继承
请在此暂时忘记之前学到的面向对象的一切知识.这里只需要考虑赛车的情况.是的,就是赛车. 最近我正在观看 24 Hours of Le Mans ,这是法国流行的一项赛事.最快的车被称为 Le Mans ...
- 详解 javascript中offsetleft属性的用法(转)
详解 javascript中offsetleft属性的用法 转载 2015-11-11 投稿:mrr 我要评论 本章节通过代码实例介绍一下offsetleft属性的用法,需要的朋友可以做一 ...
- this详解:JAVASCRIPT中的this到底是谁?
语法 this 全局对象 在全局执行上下文(函数之外),this引用的是全局对象. console.log(this.document === document); // true // In web ...
- javascript中的原型和继承
javascript一直是初学者口中的难点,甚至一些有些许工作经验的人也不太明白其中的原理,而我就是那个初学者,前段时间在阮一峰老师的博客上看了一篇文章<javascript继承机制的设计思想& ...
随机推荐
- http接口服务方结合策略模式实现总结
在项目中,我们经常会使用到http+xml的接口,而且不仅仅的是一个,可能会有多个http的接口需要实时的交互.但是http接口的接收消息的公共部分是一样的,只有每个接口的报文解析和返回报文是不同的, ...
- day02 操作系统与编程语言
目录 操作系统 操作系统是什么 操作系统做了什么 文件是什么? 为什么要有操作系统 操作系统有什么用 应用程序的启动和操作系统的启动 复盘QQ的启动 操作系统启动的流程 编程语言分类 机器语言 汇编语 ...
- Android S5PV210 fimc驱动分析 - fimc_capture.c
fimc_capture.c在FIMC系统中的位置,网上偷来的一幅图片 http://blog.csdn.net/kickxxx/article/details/7733482 43 static c ...
- 小学生都能学会的python(闭包和迭代器)
小学生都能学会的python(闭包和迭代器) 1. 函数名第一类对象 函数名其实就是变量名 1). 可以像变量一样互相赋值. 2). 可以作为函数的参数,进行传递 3). 可以作为返回值返回 4). ...
- 调整mysql数据库最大连接数
1.查看mariadb数据库最大连接数,默认为151 MariaDB [(none)]> show variables like 'max_connections'; +------------ ...
- thinkPHP的Excel插件
原文地址 http://www.thinkphp.cn/topic/14005.html 总结的注意事项 1实例化第三方类,要在类名前加\ ,不然引用地址不对. 实现步骤:一:在http://phpe ...
- 【codeforces 810B】Summer sell-off
[题目链接]:http://codeforces.com/contest/810/problem/B [题意] 每天有ki件物品,你知道每天能卖掉li件; 然后让你选f天; 这f天,可以将ki乘上2; ...
- 数字签名技术与https
1,非对称加密技术 非对称加密算法需要两个密钥,公开密钥(publickey)和私有密钥(privatekey):公钥和私钥是成对出现的. 非对称加密例子:B想把一段信息传给A,步骤:1)A把公钥传给 ...
- ASP.NET-AJAX.FORM提交附件失败
尝试了不少时间在AJAX.FORM提交附件,发现完全不行,经过下面的这个博客的介绍,使用ajax.form.js插件提交成功,记录一下该博文网址和结论: 相关网址:http://www.cnblogs ...
- [Tools] Create your own mobile emulator device by using Chrome dev tool
Using the New Device Emulation Interface The Device Emulation interface changed a bit with the newer ...