源自www.cnblogs.com/ljchow/archive/2010/06/08/1753526.html
原型和闭包是Js语言的难点,此文主要讲原型及原型实现的继承,在(二)中会讲下闭包,希望对大家有所帮助。若有疑问或不正之处,欢迎提出指正和讨论。
一. 原型与构造函数
Js所有的函数都有一个prototype属性,这个属性引用了一个对象,即原型对象,也简称原型。这个函数包括构造函数和普通函数,我们讲的更多是构造函数的原型,但是也不能否定普通函数也有原型。譬如普通函数:
;
}
alert(F.prototype instanceof Object) //true
构造函数,也即构造对象。首先了解下通过构造函数实例化对象的过程。
this.x=x;
}
var obj=new A(1);
实例化obj对象有三步:
1. 创建obj对象:obj=new Object();
2. 将obj的内部__proto__指向构造他的函数A的prototype,同时,obj.constructor===A.prototype.constructor(这个是永远成立的,即使A.prototype不再指向原来的A原型,也就是说:类的实例对象的constructor属性永远指向"构造函数"的prototype.constructor), 从而使得obj.constructor.prototype指向 A.prototype(obj.constructor.prototype===A.prototype,当A.prototype改变时则不成立, 下文有遇到)。obj.constructor.prototype与的内部_proto_是两码事,实例化对象时用的是_proto_,obj是没有 prototype属性的,但是有内部的__proto__,通过__proto__来取得原型链上的原型属性和原型方法,FireFox公开了 __proto__,可以在FireFox中alert(obj.__proto__);
3. 将obj作为this去调用构造函数A,从而设置成员(即对象属性和对象方法)并初始化。
当这3步完成,这个obj对象就与构造函数A再无联系,这个时候即使构造函数A再加任何成员,都不再影响已经实例化的obj对象了。此时,obj对象具有了x属性,同时具有了构造函数A的原型对象的所有成员,当然,此时该原型对象是没有成员的。
原型对象初始是空的,也就是没有一个成员(即原型属性和原型方法)。可以通过如下方法验证原型对象具有多少成员。
for(o in A.prototype) {
alert(o);//alert出原型属性名字
num++;
}
alert("member: "+ num);//alert出原型所有成员个数。
但是,一旦定义了原型属性或原型方法,则所有通过该构造函数实例化出来的所有对象,都继承了这些原型属性和原型方法,这是通过内部的_proto_链来实现的。
譬如
A.prototype.say=function(){alert("Hi")};
那所有的A的对象都具有了say方法,这个原型对象的say方法是唯一的副本给大家共享的,而不是每一个对象都有关于say方法的一个副本。
二. 原型与继承
首先,看个简单的继承实现。
2 this.x=x;
3 }
5 this.tmpObj=A;
6 this.tmpObj(x);
7 deletethis.tmpObj;
8 this.y=y;
9 }
第5、6、7行:创建临时属性tmpObj引用构造函数A,然后在B内部执行,执行完后删除。当在B内部执行了this.x=x后(这里的 this是B的对象),B当然就拥有了x属性,当然B的x属性和A的x属性两者是独立,所以并不能算严格的继承。第5、6、7行有更简单的实现,就是通过 call(apply)方法:A.call(this,x);
这两种方法都有将this传递到A的执行里,this指向的是B的对象,这就是为什么不直接A(x)的原因。这种继承方式即是类继承(js没有类, 这里只是指构造函数),虽然继承了A构造对象的所有属性方法,但是不能继承A的原型对象的成员。而要实现这个目的,就是在此基础上再添加原型继承。
通过下面的例子,就能很深入地了解原型,以及原型参与实现的完美继承。(本文核心在此^_^)
2 this.x = x;
3 }
4 A.prototype.a ="a";
5 function B(x,y){
6 this.y = y;
7 A.call(this,x);
8 }
9 B.prototype.b1 =function(){
10 alert("b1");
11 }
12 B.prototype =new A();
13 B.prototype.b2 =function(){
14 alert("b2");
15 }
16 B.prototype.constructor = B;
17 var obj =new B(1,3);
这个例子讲的就是B继承A。第7行类继承:A.call(this.x);上面已讲过。实现原型继承的是第12行:B.prototype =new A();
就是说把B的原型指向 了A的1个实例对象,这个实例对象具有x属性,为undefined,还具有a属性,值为"a"。所以B原型也具有了这2个属性(或者说,B和A建立了原 型链,B是A的下级)。而因为方才的类继承,B的实例对象也具有了x属性,也就是说obj对象有2个同名的x属性,此时原型属性x要让位于实例对象属性 x,所以obj.x是1,而非undefined。第13行又定义了原型方法b2,所以B原型也具有了b2。虽然第9~11行设置了原型方法b1,但是你 会发现第12行执行后,B原型不再具有b1方法,也就是obj.b1是undefined。因为第12行使得B原型指向改变,原来具有b1的原型对象被抛 弃,自然就没有b1了。
第12行执行完后,B原型(B.prototype)指向了A的实例对象,而A的实例对象的构造器是构造函数A,所以B.prototype.constructor就是构造对象A了(换句话说,A构造了B的原型)。
alert(B.prototype.constructor) 出来后就是"function A(x){...}" 。同样地,obj.constructor也是A构造对象,alert(obj.constructor)出来后就是"function A(x){...}" ,也就是说B.prototype.constructor===obj.constructor(true),但是 B.prototype===obj.constructor.prototype(false),因为前者是B的原型,具有成员:x,a,b2,后者是 A的原型,具有成员:a。如何修正这个问题呢,就在第16行,将B原型的构造器重新指向了B构造函数,那么 B.prototype===obj.constructor.prototype(true),都具有成员:x,a,b2。
如果没有第16行,那 是不是obj = new B(1,3)会去调用A构造函数实例化呢?答案是否定的,你会发现obj.y=3,所以仍然是调用的B构造函数实例化的。虽然 obj.constructor===A(true),但是对于new B()的行为来说,执行了上面所说的通过构造函数创建实例对象的3个步骤,第一步,创建空对象;第二步,obj.__proto__ === B.prototype,B.prototype是具有x,a,b2成员的,obj.constructor指向了 B.prototype.constructor,即构造函数A;第三步,调用的构造函数B去设置和初始化成员,具有了属性x,y。虽然不加16行不影响 obj的属性,但如上一段说,却影响obj.constructor和obj.constructor.prototype。所以在使用了原型继承后,要 进行修正的操作。
关于第12、16行,总言之,第12行使得B原型继承了A的原型对象的所有成员,但是也使得B的实例对象的构造器的原型指向了A原型,所以要通过第16行修正这个缺陷。
相关推荐
在JavaScript中,原型和继承是理解面向对象编程的关键概念,特别是在前端开发中。本文将深入探讨这两个主题,以便前端开发者能够更好地掌握JavaScript的核心机制。 ### 一、原型与构造函数 **1. 原型对象...
JavaScript是基于原型的面向对象语言,你需要了解构造函数、原型链、对象属性与方法、继承机制(原型链继承、借用构造函数、组合继承、寄生组合继承、原型式继承、ES6的类)。此外,还要掌握闭包和作用域,这是...
JavaScript作为Web开发的核心语言之一,是前端开发人员的必备技能。本教程的“JavaScript前端开发程序设计教程(微课版)”旨在为学习者提供一套系统且深入的JavaScript学习资源,帮助他们掌握JavaScript编程基础...
JavaScript,简称JS,是一种广泛应用于现代Web开发的轻量级、解释型编程语言,它以其易学易用性,灵活性和强大的功能深受开发者喜爱。在前端开发领域,JavaScript扮演着至关重要的角色,使得网页不仅限于静态展示,...
这个名为"js+vue前端开发资料"的压缩包包含了一系列关于这两种技术的详细学习材料,旨在帮助开发者全面掌握JavaScript和Vue.js的基础以及进阶知识。以下是这些知识点的详细说明: **JavaScript:** JavaScript是一...
* 熟练掌握 HTML、CSS、JavaScript、DOM、BOM、原型继承等前端开发技术 * 熟悉 Less 预编译语言、Flex 布局、Rem 布局、Ajax 技术、模板引擎、Vue 框架、Element-UI 等 * 熟练使用 Git 进行代码管理、npm 进行包管理...
JavaScript,作为全球最广泛使用的编程语言之一,是前端开发的核心技术。这本“前端开发 JavaScript 权威指南 完整版”深入浅出地讲解了JavaScript的各个方面,旨在帮助开发者全面掌握这一强大的脚本语言。 ...
JavaScript(JS)是一种广泛用于网页和网络应用的脚本语言,尤其在前端开发中起着核心作用。在JS中,对象的继承是实现代码复用和构建复杂应用程序的关键机制。继承允许一个对象(子对象)从另一个对象(父对象或基...
在前端开发领域,JavaScript 是一个不可或缺的编程语言,它为网页和应用程序提供了动态交互性。本资源提供的"前端开发实用技术教程代码实例"是针对一本专门讲述前端开发实用技术的书籍,非常适合初学者进行学习和...
JavaScript是Web开发中不可或缺的一部分,尤其在前端领域,它提供了丰富的功能来创建动态和交互性的网页。在JavaScript中,对象继承是实现面向对象编程(OOP)的关键特性之一。对象继承允许一个对象(子对象)从另一...
简单的原型链继承代码,适合初学者看
JavaScript是一种广泛应用于网页和网络应用的脚本语言,尤其在前端开发中占据核心地位。控件开发是JavaScript应用中的重要部分,它涉及到UI组件的创建和功能实现。在这个主题中,“javascript控件开发之继承关系”...
`prototype.js`文件可能包含了对JavaScript原型链和继承的进一步封装和扩展。通常,这样的库可能会提供更方便的方式来创建类和实现继承,比如使用类语法糖,以及提供一些额外的功能,如方法重载、私有属性等。 例如...
原型是JavaScript实现继承的方式,通过原型链,一个对象可以继承另一个对象的属性和方法。 **ES6及后续版本的新特性** JavaScript的ECMAScript(ES)标准不断更新,引入了许多新特性。例如,ES6(也称为ES2015)...
在"头歌教学实践平台"的Web前端开发课程中,JavaScript学习手册一:JS简介,旨在引导初学者入门这一强大的编程语言。 JS是一种解释型、弱类型、基于原型的语言,它的特点包括动态类型、函数作为一等公民以及事件...
内容概要:本文档是一份全面介绍JavaScript语言的教程,从基础语法讲起,深入探讨了函数和闭包、对象和原型、DOM操作、事件处理、AJAX和Fetch API等内容,最后涵盖了ES6+的新特性和流行的前端框架(如React、Vue、...
JavaScript(简称JS)是Web开发中的重要组成部分,尤其在前端领域,它扮演着不可或缺的角色。这个"个人收藏的JS前端开发脚本上百例"集合,无疑是开发者们学习和提升技能的宝贵资源。以下是对这些脚本案例中可能涵盖...
了解并掌握这些知识点,将有助于你理解和使用这个JavaScript原型验证框架,从而提升你的前端开发技能。同时,深入学习CSS布局(如CSS+DIV)也是必不可少的,它可以帮助你更好地定制验证错误提示的样式。