标签:发展史 增加 规范 面向对象的特征 现象 对象 模式 extend 证明
传统的JavaScript中只有对象,没有类的概念。它是基于原型的面向对象语言。原型对象特点就是将自身的属性共享给新对象。这样的写法相对于其它传统面向对象语言来讲,很有一种独树一帜的“感脚”!非常容易让人困惑!首先大家要明白,为什么要出现 class?
首先回顾我们的JavaScript编程思想的发展史。
从JS诞生之时,刚开始做的就是面向过程的编程,把一个问题给解释清楚了, 几行JS就可以搞定。随着JS的发展以及浏览器对于JS执行速度越来越高。我们对于JS实现的功能越来越多,伴随代码量也会越来越多,我们仍然使用面向过程式的编程方案,就会有问题。
我们制作打怪兽游戏:
*** function attack()
逃跑 function escape()
加血 function resume()
会关注这三个方法的具体实现,并且反复调用这些方法完成游戏。这是面向过程的思路。
当我们增加打怪兽的使用者时,单纯这几个方法不足以完成多人游戏。
我们需要更高级的思想面向对象,尽管JavaScript不具备面向对象的特征(继承, 封装,多态)。但是我们可以采用类似的这种思想的方式去改写这样的需求:
基于我们原来过程的基础之上,我们封装这样的构造函数,用于产生可以多次执行这样过程的对象。这样的话我们的打怪兽,不单纯如何打怪兽(面向过程),而是变成了谁能打怪兽(类似面向对象的思想),这里的勇者就是我们想要的对象,可以多次实例化。这也是这种思想给我们带来的好处,模块化,可扩展等好处。
在我们的日常coding中,很多大的项目当中都需要使用这种类似面向对象的思想去进行编程,在JavaScript中不存在面向对象,我们采用的类似面向对象的过程叫,基于原型编程,下面是工作中的存在的代码(音乐播放器中的两个模块):
在这里使用的基于原型编程的一个例子,将一个项目中的不同模块分解,每个模块使用这种方式进行编程。复用性更好,同时分工明确,不单单是A方法做完B方法做,而是统一的交给管理对象去执行这些方法。
对于JavaScript的函数来说,我们的函数是由很多不完善的地方,首先我们通过function声明的函数,可以声明,普通方法,构造函数,单纯是这两个函数我们是没有办法区分的,在之前我们默认采用大头峰式写法,表明构造函数,但是必须每个遵守才可以,而且容易出问题,当把构造函数当成普通函数来执行,会产生全局变量,还可能会报错。
基于上面的种种现象:我们需要类似的面向对象的思想进行编程。
我们的原始的function声明的构造函数,约束性,安全性不够,不足以支撑这种思想。
所以在新的语法规范当中ECMAScript6中引入了class,基于原有function的方式的语法糖,让我们使用起来,更方便,更安全,目的性更强。
而在ES6中引入了Class(类)这个概念,通过class关键字可以定义类。该关键字的出现使得其在对象写法上更加清晰,更像是一种面向对象的语言。ES6的写法就会是这个样子:
但是要注意的是:
1.在类中声明方法的时候,千万不要给该方法加上function关键字
2.方法之间不要用逗号分隔,否则会报错
通过以下代码可以看出类实质上就是一个函数。类自身指向的就是构造函数。所以可以认为ES6中的类其实就是构造函数的另外一种写法!
以下代码说明构造函数的prototype 属性,在ES6 的类中依然存在着。
console.log(Person.prototype);//输出的结果是一个对象
实际上类的所有方法都定义在类的prototype 属性上。一起来证明一下:
当然也可以通过prototype属性对类添加方法。如下:
还可以通过Object.assign方法来为对象动态增加方法
constructor方法是类的构造函数的默认方法,通过new命令生成对象实例时,自动调用该方法。
constructor方法如果没有显式定义,会隐式生成一个constructor方法。所以即使你没有添加构造函数,构造函数也是存在的。constructor方法默认返回实例对象this,但是也可以指定constructor方法返回一个全新的对象,让返回的实例对象不是该类的实例。
constructor 中定义的属性可以称为实例属性(即定义在this 对象上),constructor外声明的属性都是定义在原型上的,可以称为原型属性(即定义在class 上)。
hasOwnProperty()函数用于判断属性是否是实例属性。其结果是一个布尔值,true说明是实例属性,false说明不是实例属性。in操作符会在通过对象能够访问给定属性时返回true,无论该属性存在于实例中还是原型中。
类的所有实例共享一个原型对象,它们的原型都是Person.prototype,所以proto属性是相等的
由此,也可以通过proto 来为类增加方法。使用实例的proto 属性改写原型,会改变Class的原始定义,影响到所有实例,所以不推荐使用!
class不存在变量提升,所以需要先定义再使用。因为ES6不会把类的声明提升到代码头部,但是ES5就不一样,ES5存在变量提升,可以先使用,然后再定义。
这是我们对 ES6中class(类)的概念的了解,既然提出了类,这个类又是怎么实现的呢?在这首先要了解一下类的继承:有三种属性,公有属性,私有属性,静态属性(Es7)/静态类(Es6)
继承公有属性:
Child.prototype = Parent.prototype;//这个不叫继承
//因为这样如果改变Child.prototype 加属性,Parent.prototype的实例也会有这个属性,,此时这两者属于兄弟关系。
继承公有属性和私有属性Child.prototype = new Parent()
之前的继承都是原型链的继承,圣杯模式,在Class 中的继承,有什么不一样了呢,在 ES5中真正的继承应该是什么样呢?
这里有两点,要注意的地方,首先是:
1.父类构造函数为什么要 call;
2.原型需要重写。
在 class中继承就变的简单了许多,同比上面的例子通过class 来实现
在这里实现之后,多了两个大家不认识的次,extends super extends 后面跟的就是我们要继承的内容
super有些注意点
子类也叫派生类,必须在constructor中调用super函数,要不无法使用this,准确的说子类是没有this的。就算是继承之后什么也不写,默认的也会填上去。
在调用super 之前不可以使用this回报错,super可以作为对象使用,指向的是父类的原型;super调用父类方法时会绑定子类的this。
类的编译
类只能new
//类可以继承公有,私有和静态
//父类的构造函数中返回类一个引用类型,会把这个引用类型作为子类的this
我们首先写一个创建类的函数:
//检测实例是不是new出来的
这样我们的类就创建完成了。
标签:发展史 增加 规范 面向对象的特征 现象 对象 模式 extend 证明
原文地址:https://blog.51cto.com/13409950/2469602