Javascript中的对象、函数和继承
<!--[if !supportLists]-->1、 <!--[endif]-->Javascript中的对象
JavaScript可以说是一个基于对象的编程语言,为什么说是基于对象而不是面向对象,因为JavaScript自身只实现了封装,而没有实现继承和多态。既然他是基于对象的,那么我们就来说说js中的对象。有人说js中所有的都是对象,这句话不完全正确。正确的一方是他强调了对象在js中的重要性,对象在js中无处不在,包括可以构造对象的函数本身也是对象。但是另一方面,js中也有一些简单的数据类型,包括数字、字符串和布尔值、null值和undefined值,而这些不是对象。那为什么这些类型的值不是对象呢,毕竟他们也有方法。那让我们来看一下,JavaScript中对于对象的定义,有两种定义。
(1)JavaScript中的对象是可变的键控集合(keyed collections) (此定义来自老道的那本书的第三章)
(2)JavaScript中的对象是无序(unordered)的属性集合,这些属性可以含有简单的数据类型、对象、函数;保存在一个对象属性中的函数也被称为这个对象的方法。
(来自ECMA-262 的4.3.3)(注:这里所说的属性是可以在js脚本中创建和访问的(我们称之为显性属性),不包括系统为对象自动分配的内部属性)
那为什么那个简单的数据类型不是对象呢,主要是因为这些数据类型的值中拥有的方法是不可变的,而一个对象的属性是应当可以被改变的。
<!--[if !supportLists]-->2、 <!--[endif]-->对象中的原型链[[proto]]
JavaScript中的每个对象创建的时候系统都会自动为其分配一个原型属性[[proto]],用来连接到他的原型对象。在JavaScript中就是通过每个对象中的[[proto]]来实现对象的继承关系的。但是对象的[[proto]]属性在JavaScript是不能访问和修改的,他是作为一个内部的属性存在的,而且是在对象被创建的同时由系统自动设定的。
当访问一个对象的某一属性,如果这个属性在此对象中不存在,就在他的[[proto]]所指的原型对象的属性中寻找,如果找到则返回,否则继续沿着[[proto]]链一直找下去,直到[[proto]]的连接为null的时候停止。
<!--[if !supportLists]-->3、 <!--[endif]-->函数也是对象
JavaScript中的函数本身就是一个对象(所以我们经常称之为函数对象),而且可以说他是js中最重要的对象。之所以称之为最重要的对象,一方面他可以扮演像其他语言中的函数同样的角色,可以被调用,可以被传入参数;另一方面他还被作为对象的构造器(constructor)来使用,可以结合new操作符来创建对象。
既然函数就是对象,所以必然含有对象拥有的全部性质,包括对象在创建时设定的原型链[[proto]]属性。
让我们来看看函数对象和普通对象有什么区别。我们前面说过,对象就是无序的属性集合,那么函数的属性和普通对象的属性有什么不同呢。根据ECMA-262中的13.2节所述,在函数对象创建时,系统会默认为其创建两个属性[[call]]和[[constructor]],当函数对象被当做一个普通函数调用的时候(例如myFunc()),“()”操作符指明函数对象的[[call]]属性就被执行,当他被当做一个构造器被调用的时候(例如new
myConst()),他的[[constructor]]属性就被执行,[[cosntructor]]的执行过程我们将在下一节中介绍。除此之外,当一个函数被创建时,系统会默认的再为其创建一个显示属性prototype,并为其赋值为
this.prototype
= {constructor:this}
具体内容可以参加老道的那本书的第五章。这个函数对象的prototype属性也是为了js把函数当做构造器来实现继承是准备的,但是这个属性是可以在js脚本中访问和修改的。在这里要强调的一点是,大家一定要区分对象中的[[proto]]属性和函数对象中的prototype属性,我在刚开始学习的时候就是因为没有很好的区分这两个东西,走了很多的弯路:(
<!--[if !supportLists]-->4、 <!--[endif]-->对象的创建
在js中有两种创建对象的方法,一种是通过字面量来实现,如
var Person = {
“first_name”:’liang’,
‘last_name’:’yang’
}
另一种方法是通过构造器来创建
var my = new Person(‘liang’,’yang’);
其实第一种方式的创建过程相当于调用Object构造器来实现,如下。
var Person = new Object();
Person.first_name = ‘liang’;
Person.last_name = ‘yang’;
所以我们可以把js中所有对象的创建都合并到使用构造器来实现,下面我么来详细说明构造器创建对象的过程:
第一步,先创建一个空的对象(既没有任何属性),并将这个对象的[[proto]]指向这个构造器函数的prototype属性对象
第二步,将这个空的对象作为this指针传给构造器函数并执行
第三步,如果上面的函数返回一个对象,则返回这个对象,否则返回第一步创建的对象
第四步,把函数当做一个类来使用
由上面的步骤我们可以看出,一般来说函数对象的prototype指向的是一个普通对象,而不是一个函数对象,这个普通对象中的属在由此函数构造器创建的对象中也可以访问。由此可以如此设计我们的代码,假设一个函数就可以代表一个类,这个构造器函数生成的对象就是这个类的实例对象,那么实例对象中应有的属性和方法应该放在这个构造器函数的prototype中,这个类的静态方法就可以直接放到这个函数作为对象的属性中,最后这个函数体就是我们平时在面向对象语言中所说的构造函数(在这里我们要区分连个词“构造函数”和“构造器函数”,所谓构造函数是指普通的面向对象语言中的类的构造函数,而构造器函数是指javascript中的一个函数被当做构造器使用)。
在第3节我们说过每个函数的prototype对象中总是含有一个constructor属性,这个属性就是连接到我们的这个函数本身。再加之,有这个函数生成的每个对象的[[proto]]属性都是指向构造器函数的prototype对象,所以通过[[proto]]链,每个由构造器函数生成的对象,都有一个constructor属性,指向生成他的构造器函数,因此我们可以通过这个属性来判断这个对象是有哪个构造器函数生成的。
<!--[if !supportLists]-->5、
<!--[endif]-->函数继承(类继承)
说了这么多,终于到了我们可以在javascript中讨论继承的时候了,我们先来考虑一下要实现类的继承我们都要做些什么,假设我们要从superClass继承到子类subClass
为了使得由subClass生成的对象中能够访问superClass生成的对象中的属性,那么可以使subClass.prototype为一个superClass构造函数生成的对象。
subclass.prototye = new superClass();
但是问题来了,根据我们在第4节说的new superClass()不仅复制了superClass.prototype中的所有方法,而且还运行了superClass()这个函数,这个函数起到的作用是类中的构造函数。我们知道应该在子类的构造函数中调用父类的构造函数来实现初始化。为此我们可以创建一个构造函数为空的,但是原型和superClass原型一致的函数,并使subClass.prototype指向这个函数生成的对象。
var F = function() {};
F.prototype = superClass.prototype;
subClass.protptype = new F();
这样我们就可以再不调用构造函数的同时完成属性复制的工作。但是还有一个问题,那就是我们修改了subClass的prototype属性,从而也就删除了其中的constructor属性,这样我们就无法知道他是哪个构造器函数生成的对象了。我们可以再次给他赋值
subClass.prototype.constructor = subClass;
这样复制属性的问题就迎刃而解了。但是新的问题又出现了,在subClass中我们无法知道他的父类是哪个构造器函数,所以就无法在构造函数中调用父类的构造函数,为此我们可以为subClass添加一个属性,指明他的父类
subClass.superClass =
superClass.prototype;
这样我么就可以在子类的构造函数中使用subClass.superClass.constructor来访问父类的构造函数了。最后我们把以上的思路写成一个函数
myPro.extend = function (subClass,superClass) {
var F = function() {};
F.prototype = superClass.prototype;
subClass.protptype = new F();
subClass.prototype.constructor = subClass;
subClass.superClass = superClass.prototype;
superClass.prototype.constructor = superClass;
}
分享到:
相关推荐
借用构造函数继承又被称为伪造对象继承或经典继承。这种方法在子类型构造函数的内部调用超类型构造函数。通过使用apply()和call()方法,可以在将来新创建的对象上执行构造函数,从而实现继承。 优点: - 可以向超...
文档《面向对象的JavaScript_张行.doc》可能更深入地探讨了JavaScript中的面向对象编程,包括类的模拟、继承策略、封装和多态性等方面。通过阅读这份文档,开发者可以进一步巩固和深化对JavaScript中函数对象调用...
2. **对象和原型**:深入理解原型链,掌握构造函数、原型对象以及对象字面量的用法,了解如何创建和继承对象。 3. **数组和集合**:学习JavaScript中的数组操作,如map、filter、reduce等高阶函数的运用,以及Set和...
在JavaScript中,类(Class)、对象(Object)和构造函数(Constructor)是面向对象编程的基础。这篇文章将深入探讨这三个概念,以及如何实现类的继承。 首先,让我们理解什么是JavaScript中的对象。在JavaScript中...
这使得 JavaScript 中的对象可以继承原型对象的方法和属性,从而实现代码的重用和简洁。 四、原型链 在 JavaScript 中,原型对象可以形成一个链式结构,即一个对象的原型对象可以有自己的原型对象,以此类推。这...
3. **函数构造器与继承**:使用函数构造器结合`new`关键字可以创建新对象,并可以继承构造器函数的`prototype`属性上定义的方法和属性。通过这种方式,不同的对象实例可以共享同样的方法,避免了方法重复定义的冗余...
在JavaScript中,常见的继承模式有原型链继承、构造函数继承、组合继承、寄生继承、原型式继承、委托继承等。这里提到的"工具函数二"可能是介绍了一种或多种继承模式的实现方式。下面我们将详细讨论这些概念: 1. *...
当需要继承一个对象的属性和方法时,可以通过`Object.create()`或`Ext.extend()`(在某些库如ExtJS中)这样的函数来创建新对象,新对象的[[proto]]将指向父对象。 此外,了解JavaScript的设计模式也是提升编程能力...
每个JavaScript对象都有一个内部的[[Prototype]]属性,通常可以通过`__proto__`或`Object.getPrototypeOf`访问。当试图访问对象的一个属性时,如果该属性不存在于当前对象,JavaScript会向上搜索原型链,直到找到该...
使用`zInherit`这种方式进行对象继承的好处在于,它可以保持对象的实例属性,避免了构造函数继承中的属性复制问题。同时,由于直接操作原型,它能够有效地利用原型链实现属性的查找和继承。 然而,`zInherit`也存在...
在提供的资源中,《代码之美》PDF文件可能包含了关于编程实践和代码风格的指导,而《Javascript面向对象编程》PPT可能更具体地阐述了JavaScript OOP的细节和示例。学习这些材料将有助于深入理解JavaScript的面向对象...
当使用new关键字调用构造函数时,JavaScript引擎会创建一个新的空对象,并且按照构造函数中定义的属性和方法来初始化这个新对象。 3. prototype:在JavaScript中,每个函数都有一个prototype属性,这个属性指向一个...
JavaScript中的继承机制是其面向对象编程的一个核心特性。在JavaScript中,可以使用多种方式来实现继承,其中之一就是通过函数来模拟继承。本文将详细介绍如何利用函数实现JavaScript的继承,并结合属性特性和描述符...
本文将深入探讨 JavaScript 中创建对象及对象继承的各种有效策略,特别是如何利用构造函数模式、原型模式以及寄生组合式继承等技术来构建灵活、高效的应用程序。 #### 二、JavaScript 对象与原型 在 JavaScript 中...
- 这里的回调函数用于处理JavaScript函数的异步返回结果,如果需要同步获取结果,可以使用`QWebEngineScript`来注册一个全局JavaScript对象,然后通过该对象调用JavaScript函数。 2. **JavaScript调用QT函数**: ...
本文将主要围绕JavaScript中的函数、面向对象编程以及多态性来展开。 1. **函数**: 在JavaScript中,函数是可重复使用的代码块,可以接收参数并返回值。它们是第一类对象,这意味着函数可以作为变量赋值、作为参数...
JavaScript是一种广泛...通过深入学习这本《JavaScript面向对象编程指南(第2版)》,开发者不仅能掌握JavaScript的面向对象编程基础,还能了解到实际项目中如何有效地运用这些知识,提升编程技巧和解决问题的能力。
- **第三章:JavaScript中的类和对象**:详细介绍如何使用JavaScript创建类和对象。 - **第四章:继承**:探讨JavaScript中实现继承的不同方式。 - **第五章:封装和私有性**:讲解如何在JavaScript中实现封装以及...