发布于 2017-04-01 05:28:58 | 5 次阅读 | 评论: 0 | 来源: 网友投递
Javascript 是一种由 Netscape 的 LiveScript 发展而来的原型化继承的基于对象的动态类型的区分大小写的客户端脚本语言,主要目的是为了解决服务器端语言,比如 Perl,遗留的速度问题,为客户提供更流畅的浏览效果。 下面小编就为大家带来一篇玩转 JavaScript OOP - 类的实现详解。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧概述
当我们在谈论面向对象编程时,我们在谈论什么?
我们首先谈论的是一些概念:对象、类、封装、继承、多态。
对象和类是面向对象的基础,封装、继承和多态是面向对象编程的三大特性。
JavaScript 提供了对象却缺乏类,它不能像 C# 一样能显式地定义一个类。
但是 JavaScript 的函数功能非常灵活,其中之一就是构造函数,结合构造函数和原型对象可以实现 "类"。
对象和类的概念
对象
"对象" 是面向对象编程中非常重要的一个概念,一个对象是一个 "东西"(某个人或某件事)的描述。
人和事都来源于现实生活,我们对现实世界的认知就是对人和事的认知。
在编程的领域,代码对于常人来说是抽象的,代码构成的应用是为了更好地解决现实世界的问题。
在分析和设计阶段,使用 "对象" 的概念能够更好地反应现实世界的问题。
反过来说,代码是包含一些逻辑的,这些逻辑用于描述业务,业务是包含一些业务知识的,业务知识是通过对现实世界的理解和分析总结出来的,这些问题是由现实世界的 "对象" 构成的。
对象包含特征和行为,用 OOP 的术语来说,特征是对象的属性,行为是对象的方法。
类
在现实世界中,相似的对象可以按照一定的标准来分组。例如 "蜂鸟" 和 "老鹰" 都被划分到鸟类,鸟类不是一个具体的对象,它是人们根据 "蜂鸟"、"老鹰" 等那些具体的鸟分析出相似的特征和行为后,归纳出来的一个概念。类相当于一个模板,我们可以基于这个模板创建不同的具体的对象。
在 C# 中,我们可以定义一个鸟类。
- /// <summary>
- /// 鸟类
- /// </summary>
- public class Bird
- {
- public void Fly()
- {
- Console.WriteLine("I can fly!");
- }
- }
虽然 JavaScript 是一门面向对象编程语言,但它没有提供 class 的语法支持。
在 JavaScript 中,一切都是基于对象的,即使后面要讲的 "原型" 也都是对象,JavaScript 的继承和重用也都是通过原型来实现的。
但是结合构造函数和原型对象可以实现 JavaScript 的 "类"。
构造函数
之前我们使用 new Array() 创建一个数组,使用 new Object() 创建一个对象,Array() 和 Object() 是 JavaScript 内置的两个构造函数,尽管 JavaScript 没有提供类,但我们可以将 Array 和 Object 理解为 "类" 的概念。
需要注意的是,JavaScript 的 "类" 是由构造函数实现的。
定义构造函数
构造函数也是函数,定义构造函数和其他函数并没有语法上的区别。
唯一的区别是构造函数的首字母应该大写,这也是 JavaScript 的编程规范。
以下定义了一个 Person() 构造函数,我们可以将它理解为 Person 类。
- function Person(){
- console.log('I am keepfool.');
- }
JavaScript 的 "类" 和构造函数是同时被定义的,在 JavaScript 中定义 "类" 时,就同时定义了构造器。
使用构造函数
JavaScript 使用类的方式和 C# 一样,new 关键字后面跟着构造函数。
- var p = new Person();
定义属性和方法
现在我们已经定义好了 Person 类,可以为 Person 类添加一些属性和方法。
定义属性
在讲 JavaScript 对象时,我们讲了对象的属性设置和访问。
这段代码展示了定义对象属性的两种方式:
- var cat = {
- color: 'black'
- };
- cat.name = 'Tom';
- console.log(cat.color);
- console.log(cat.name);
使用 this 定义属性
JavaScript 类的属性定义方式则有些不同,在构造函数中使用 this 关键字定义属性:
- function Person(name){
- this.name = name;
- }
• 第一行代码,定义了 Person 类,并定义了构造函数。
• 第二行代码,定义了 name 属性。
创建并使用对象
以下 2 行代码创建了两个 Person 类的对象
- var p1 = new Person('James');
- var p2 = new Person('Cury');
在 Chrome 控制台中输出 p1.name 和 p2.name
p1 和 p2 是两个不同的对象,修改 p1.name 不会影响 p2.name。
- p1.name = 'Lebron James';
定义方法
首先,我们区分一下术语 "函数" 和 "方法","函数" 是独立的单元,而 "方法" 是依赖于类这个主体存在的。
使用 this 定义方法
在 JavaScript 中,类的方法是定义在构造函数中的函数,在构造函数中使用 this 关键字定义方法:
- function Person(name) {
- // 定义属性
- this.name = name;
- // 定义方法
- this.sayHello = function() {
- return 'Hello, I am ' + this.name;
- }
- }
使用方法
在 Chrome 控制台分别调用 p1 和 p2 对象的 sayHello() 方法
constructor 属性
当创建一个对象时,一个特殊的属性被 JavaScript 自动地分配给对象了,这个属性就是 constructor 属性。
在 chrome 控制台输入
,可以看到 p1 对象的 constructor 属性指向一个函数。
- p1.constructor
瞧瞧这个函数的内容,这不正是 Person() 构造函数吗?
这表示我们也可以通过 p1.constructor 属性创建对象,
- var p3 = new p1.constructor('Steve Nash');
这行代码阐述了一句话:"我不关心 p1 对象是怎么创建的,但我想让另一个对象如 p1 一样创建!"
在 Chrome 控制台使用 instanceof 操作符,可以看到 p1、p2、p3 都是 Person 类的实例
另外,当我们以
方式创建对象时,实际上也调用了 Object() 构造函数。
- {}
- var o = {};
这行代码声明了一个对象,尽管我们没有设置任何属性和方法,但 JavaScript 引擎默认给它设置了 constructor 属性。
指向的是 Object() 构造函数,
- o.constructor
显示了 Object() 是 JavaScript 内置的函数。
- [native code]
原型对象
在 JavaScript 中,定义一个函数时,函数就会拥有 prototype 属性,构造函数也不例外。
下图说明了 Person() 构造函数的 prototype 属性是一个对象,它是属于函数的,我们称这个属性为原型对象。
从 Person 类的角度出发,我们也可理解为 prototype 属性是属于 Person 类的。
同时 Person 类的实例是没有 prototype 属性的,上图的 p1.prototype 是 undefined,这说明 prototype 属性是共享的,这有点像 C# 中的静态属性。
设置 prototype
既然 prototype 是一个对象,那就可以为它添加属性和方法。
在函数的 protpotype 属性上定义属性和方法,与设置普通对象的属性和方法没什么区别。
下面的代码为 Person.prototype 定义了属性和方法。
- function Person(name){
- this.name = name;
- this.sayHello = function() {
- return 'Hello, I am ' + this.name;
- }
- }
- // 在构造函数的prototype对象上定义属性和方法
- Person.prototype.height = 176;
- Person.prototype.run = function(){
- return 'I am ' + this.name + ', I am running!';
- }
- var p1 = new Person('James');
使用 prototype
在 Person.prototype 中定义的属性和方法,可以直接被 Person 类的实例使用,仍然是以
的方式使用。
- object.property
需要特别注意的是,
和
- name
是属于 Person 类的实例,而
- sayHello()
和
- height
是不属于 Person 类的实例。
- run()
小技巧:通过 hasOwnProperty 方法可以查看对象是否包含某个属性或方法。
自有属性 vs. prototype 的属性
Person 类的实例既可以使用 Person 类中的属性,又可以使用 Person.prototype 中的属性。
那么 Person 类的属性和 Person.prototype 的属性有什么差别呢?
首先,我们可以将 Person 类中的属性和方法理解为 "实例属性"。
由于 prototype 是共享的,我们可以将 prototype 中的属性和方法理解为 "共享属性"。
"实例属性" 和 "共享属性" 的差别主要体现在性能上。
每创建一个 Person 的实例,就会产生一个 name 属性和 sayHello() 方法的副本,而 height 属性和 run() 方法则是所有实例共享一个副本。
既然如此,这意味着 sayHello() 方法可以提到 prototype 中。
另外,不同的 Person 实例 height 可能会不一样,应将它放到 Person 类中更合理。
- function Person(name,height){
- this.name = name;
- this.height = height;
- }
- Person.prototype.sayHello = function(){
- return 'Hello, I am ' + this.name + ', my height is ' + this.height + 'cm.';
- }
- Person.prototype.run = function(){
- return 'I am ' + this.name + ', I am running!';
- }
- var p1 = new Person('James',203);
- var p2 = new Person('Cury',190);
类的实现总结
JavaScript 没有类,但构造函数可以实现 "类"。
按照 JavaScript 编程规范,构造函数的首字母应该大写。
"类" 的属性和方法是用 this.property 方式定义在构造函数中的。
在对象创建时 JavaScript 分配了 constructor 属性给对象,constructor 属性是对象构造函数的一个引用。
函数在定义时就已经有了 prototype 属性,prototype 属性也是一个对象。
prototype 是共享的,定义在 prototype 上的属性和方法可以被 "类" 的实例使用。
如果属性或方法能够定义在 prototype 上,就不要定义在构造函数上,使用 prototype 可以减少内存开销。
以上这篇玩转 JavaScript OOP - 类的实现详解就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持 phperz。
来源: http://www.phperz.com/article/17/0401/265054.html