前言:
Javascript中的OOP,其实不止Javascript中有OOP,面向对象思想在很多语言中都有体现。
先看一下面向对象的定义:
面向对象程序设计,是一种程序设计范型,同时也是一种程序开发的方法。对象指的是类的实例。它将对象作为程序的基本单元,将程序和数据封装其中,以提高软件的重用性,灵活性和扩展性。
面向对象的几个重点思想:
- 继承
- 封装
- 多态
- 抽象
这些思想在Javascript中都可以体现。
继承
基于原型的继承
根据一个构造函数生成的对象会继承这个构造函数原型链上的内容。
🌰:
1 | function Foo() { |
那么我们此时来关注一下Foo.prototype这个东西。
当我们写出一个空函数的时候,这个函数自动拥有一个prototype属性,并且默认拥有两个属性:
- constructor
- __proto__
如何使一个class继承另一个class?
🌰:
1 | function Person(name, age) { |
唔。。。。感觉好像没有什么可以用语言描述的,我认为有必要记住这个套路。
原型链
原型和原型之间组成的链条就是原型链,原型链是由__proto__这个属性决定的。
我们在研究原型链的时候,是不断地查找每个prototype中的__proto__来找出它的上一个原型~~
当我们使用instanecof这个运算符来判断一个实例属于哪个类的时候,我们用的也是原型链,即__proto__组成的那个链条。
楼上那段代码,我们在调用hi的时候,发生了啥?
它首先看这个对象上有没有hi方法,没有,于是它查找__proto__,根据这个属性找到了构造函数的原型,发现原型上有,于是调用这个。
类似地,ARMS_NUM,LEGS_NUM,也都是这种套路。
找到原型的方法
对于一个对象来说,我们有以下方法找到它的原型:
用__proto__属性来查找
1 | var obj = {x:1}; |
用Object.getPrototypeOf来查找
1 | var obj = {x:1}; |
并不是所有的对象原型链上都有Object.prototype
🌰:
1 | var obj2 = Object.create(null); |
这个对象是没有原型的。
并不是所有的函数都有prototype属性
🌰:
1 | function abc() { |
prototype属性更进一步
注意,当我们修改prototype的属性值的时候,会影响已经创建的实例。
如果直接改动prototype这个东西,也就是重新给prototype赋值,是不会影响已经创建的实例的。
🌰(接第一段长代码):
1 | Student.prototype.x = 101; |
Object.prototype是原型链的末端,它的\_proto__指向null。
基于原型链的instanceof运算符
instanceof左边是一个对象,右边是一个构造器,它会判断右边的prototype属性是否出现在左边的原型链上。
🌰(接在第一大段代码后面):
1 | wanzi instanceof Person; //true |
这些true,true,true就是因为左边的原型链上有右边的prototype。
实现继承的方式
用代码来说明:
1 | function Person() { |
第一种方法是不行的,改变了Student.prototype的同时也会改变Person,这样是不行的。
方法2存在一个问题是你如果给Person传了参数就会很奇怪。
方法3相对来说是比较合适的。
不过注意,Object.create方法是ES5之后才有,对于ES5之前,我写过另一篇文章来模拟一个类似的方法实现继承的,在这里:实现一个正确的长长的原型链。
总结
这篇文章写完,感觉自己的脑袋清醒了很多。
原型链继承这一块,我是先看了廖雪峰老师的教程,然后看的书,觉得它们之间配合起来,对我的理解很有帮助。
总之,很开心,嘿嘿嘿~~