JS 面向对象之神奇的prototype

JavaScript中对象的prototype属性,可以返回对象类型原型的引用。这是一个相当拗口的解释,要理解它,先要正确理解对象类型(Type)以及原型(prototype)的概念。
1 什么是prototype
JavaScript中对象的prototype属性,可以返回对象类型原型的引用。这是一个相当拗口的解释,要理解它,先要正确理解对象类型(Type)以及原型(prototype)的概念。
前面我们说,对象的类(Class)和对象实例(Instance)之间是一种“创建”关系,因此我们把“类”看作是对象特征的模型化,而对象看作是类特征的具体化,或者说,类(Class)是对象的一个类型(Type)。例如,在前面的例子中,p1和p2的类型都是Point,在JavaScript中,通过instanceof运算符可以验证这一点:
p1 instanceof Point
p2 instanceof Point
但是,Point不是p1和p2的唯一类型,因为p1和p2都是对象,所以Obejct也是它们的类型,因为Object是比Point更加泛化的类,所以我们说,Obejct和Point之间有一种衍生关系,在后面我们会知道,这种关系被叫做“继承”,它也是对象之间泛化关系的一个特例,是面向对象中不可缺少的一种基本关系。
在面向对象领域里,实例与类型不是唯一的一对可描述的抽象关系,在JavaScript中,另外一种重要的抽象关系是类型(Type)与原型(prototype)。这种关系是一种更高层次的抽象关系,它恰好和类型与实例的抽象关系构成了一个三层的链。
在现实生活中,我们常常说,某个东西是以另一个东西为原型创作的。这两个东西可以是同一个类型,也可以是不同类型。习语“依葫芦画瓢”,这里的葫芦就是原型,而瓢就是类型,用JavaScript的prototype来表示就是“瓢.prototype =某个葫芦”或者“瓢.prototype= new 葫芦()”。
要深入理解原型,可以研究关于它的一种设计模式——prototype pattern,这种模式的核心是用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。JavaScript的prototype就类似于这种方式。
关于prototype pattern的详细内容可以参考《设计模式》(《Design Patterns》)它不是本文讨论的范围。
注意,同类型与实例的关系不同的是,原型与类型的关系要求一个类型在一个时刻只能有一个原型(而一个实例在一个时刻显然可以有多个类型)。对于JavaScript来说,这个限制有两层含义,第一是每个具体的JavaScript类型有且仅有一个原型(prototype),在默认的情况下,这个原型是一个Object对象(注意不是Object类型!)。第二是,这个对象所属的类型,必须是满足原型关系的类型链。例如p1所属的类型是Point和Object,而一个Object对象是Point的原型。假如有一个对象,它所属的类型分别为ClassA、ClassB、ClassC和Object,那么必须满足这四个类构成某种完整的原型链。
有意思的是,JavaScript并没有规定一个类型的原型的类型(这又是一段非常拗口的话),因此它可以是任何类型,通常是某种对象,这样,对象-类型-原形(对象)就可能构成一个环状结构,或者其它有意思的拓扑结构,这些结构为JavaScript带来了五花八门的用法,其中的一些用法不但巧妙而且充满美感。下面的一节主要介绍prototype的用法。

2 prototype使用技巧
在了解prototype的使用技巧之前,首要先弄明白prototype的特性。首先,JavaScript为每一个类型(Type)都提供了一个prototype属性,将这个属性指向一个对象,这个对象就成为了这个类型的“原型”,这意味着由这个类型所创建的所有对象都具有这个原型的特性。另外,JavaScript的对象是动态的,原型也不例外,给prototype增加或者减少属性,将改变这个类型的原型,这种改变将直接作用到由这个原型创建的所有对象上,例如:


代码如下:

<script>
function Point(x,y)
{
this.x = x;
this.y = y;
}
var p1 = new Point(1,2);
var p2 = new Point(3,4);
Point.prototype.z = 0; //动态为Point的原型添加了属性
alert(p1.z);
alert(p2.z); //同时作用于Point类型创建的所有对象
</script>

如果给某个对象的类型的原型添加了某个名为a的属性,而这个对象本身又有一个名为a的同名属性,则在访问这个对象的属性a时,对象本身的属性“覆盖”了原型属性,但是原型属性并没有消失,当你用delete运算符将对象本身的属性a删除时,对象的原型属性就恢复了可见性。利用这个特性,可以为对象的属性设定默认值,例如:


代码如下:

<script>
function Point(x, y)
{
if(x) this.x = x;
if(y) this.y = y;
}
Point.prototype.x = 0;
Point.prototype.y = 0;
var p1 = new Point;
var p2 = new Point(1,2);
</script>

上面的例子通过prototype为Point对象设定了默认值(0,0),因此p1的值为(0,0),p2的值为(1,2),通过delete p2.x, delete p2.y; 可以将p2的值恢复为(0,0)。下面是一个更有意思的例子:


代码如下:

<script>
function classA()
{
this.a = 100;
this.b = 200;
this.c = 300;

this.reset = function()
{
for(var each in this)
{
delete this[each];
}
}
}
classA.prototype = new classA();

var a = new classA();
alert(a.a);
a.a *= 2;
a.b *= 2;
a.c *= 2;
alert(a.a);
alert(a.b);
alert(a.c);
a.reset(); //调用reset方法将a的值恢复为默认值
alert(a.a);
alert(a.b);
alert(a.c);
</script>

利用prototype还可以为对象的属性设置一个只读的getter,从而避免它被改写。下面是一个例子:


代码如下:

<script>
function Point(x, y)
{
if(x) this.x = x;
if(y) this.y = y;
}
Point.prototype.x = 0;
Point.prototype.y = 0;

function LineSegment(p1, p2)
{
//私有成员
var m_firstPoint = p1;
var m_lastPoint = p2;
var m_width = {
valueOf : function(){return Math.abs(p1.x - p2.x)},
toString : function(){return Math.abs(p1.x - p2.x)}
}
var m_height = {
valueOf : function(){return Math.abs(p1.y - p2.y)},
toString : function(){return Math.abs(p1.y - p2.y)}
}
//getter
this.getFirstPoint = function()
{
return m_firstPoint;
}
this.getLastPoint = function()
{
return m_lastPoint;
}

this.length = {
valueOf : function(){return Math.sqrt(m_width*m_width + m_height*m_height)},
toString : function(){return Math.sqrt(m_width*m_width + m_height*m_height)}
}
}
var p1 = new Point;
var p2 = new Point(2,3);
var line1 = new LineSegment(p1, p2);
var lp = line1.getFirstPoint();
lp.x = 100; //不小心改写了lp的值,破坏了lp的原始值而且不可恢复
alert(line1.getFirstPoint().x);
alert(line1.length); //就连line1.lenght都发生了改变
</script>

将this.getFirstPoint()改写为下面这个样子:


代码如下:

this.getFirstPoint = function()
{
function GETTER(){};
GETTER.prototype = m_firstPoint;
return new GETTER();
}

则可以避免这个问题,保证了m_firstPoint属性的只读性。


代码如下:

<script>
function Point(x, y)
{
if(x) this.x = x;
if(y) this.y = y;
}
Point.prototype.x = 0;
Point.prototype.y = 0;

function LineSegment(p1, p2)
{
//私有成员
var m_firstPoint = p1;
var m_lastPoint = p2;
var m_width = {
valueOf : function(){return Math.abs(p1.x - p2.x)},
toString : function(){return Math.abs(p1.x - p2.x)}
}
var m_height = {
valueOf : function(){return Math.abs(p1.y - p2.y)},
toString : function(){return Math.abs(p1.y - p2.y)}
}
//getter
this.getFirstPoint = function()
{
function GETTER(){};
GETTER.prototype = m_firstPoint;
return new GETTER();
}
this.getLastPoint = function()
{
function GETTER(){};
GETTER.prototype = m_lastPoint;
return new GETTER();
}

this.length = {
valueOf : function(){return Math.sqrt(m_width*m_width + m_height*m_height)},
toString : function(){return Math.sqrt(m_width*m_width + m_height*m_height)}
}
}
var p1 = new Point;
var p2 = new Point(2,3);
var line1 = new LineSegment(p1, p2);
var lp = line1.getFirstPoint();
lp.x = 100; //不小心改写了lp的值,但是没有破坏原始的值
alert(line1.getFirstPoint().x);
alert(line1.length); //line1.lenght不发生改变
</script>

实际上,将一个对象设置为一个类型的原型,相当于通过实例化这个类型,为对象建立只读副本,在任何时候对副本进行改变,都不会影响到原始对象,而对原始对象进行改变,则会影响到副本,除非被改变的属性已经被副本自己的同名属性覆盖。用delete操作将对象自己的同名属性删除,则可以恢复原型属性的可见性。下面再举一个例子:


代码如下:

<script>
function Polygon()
{
var m_points = [];

m_points = Array.apply(m_points, arguments);

function GETTER(){};
GETTER.prototype = m_points[0];
this.firstPoint = new GETTER();

this.length = {
valueOf : function(){return m_points.length},
toString : function(){return m_points.length}
}

this.add = function(){
m_points.push.apply(m_points, arguments);
}

this.getPoint = function(idx)
{
return m_points[idx];
}

this.setPoint = function(idx, point)
{
if(m_points[idx] == null)
{
m_points[idx] = point;
}
else
{
m_points[idx].x = point.x;
m_points[idx].y = point.y;
}
}
}
var p = new Polygon({x:1, y:2},{x:2, y:4},{x:2, y:6});
alert(p.length);
alert(p.firstPoint.x);
alert(p.firstPoint.y);
p.firstPoint.x = 100; //不小心写了它的值
alert(p.getPoint(0).x); //不会影响到实际的私有成员
delete p.firstPoint.x; //恢复
alert(p.firstPoint.x);

p.setPoint(0, {x:3,y:4}); //通过setter改写了实际的私有成员
alert(p.firstPoint.x); //getter的值发生了改变
alert(p.getPoint(0).x);
</script>

注意,以上的例子说明了用prototype可以快速创建对象的多个副本,一般情况下,利用prototype来大量的创建复杂对象,要比用其他任何方法来copy对象快得多。注意到,用一个对象为原型,来创建大量的新对象,这正是prototype pattern的本质。
下面是一个例子:


代码如下:

<script>
var p1 = new Point(1,2);
var points = [];
var PointPrototype = function(){};
PointPrototype.prototype = p1;
for(var i = 0; i < 10000; i++)
{
points[i] = new PointPrototype();
//由于PointPrototype的构造函数是空函数,因此它的构造要比直接构造//p1副本快得多。
}
</script>

除了上面所说的这些使用技巧之外,prototype因为它独特的特性,还有其它一些用途,被用作最广泛和最广为人知的可能是用它来模拟继承,关于这一点,留待下一节中去讨论。
3 prototype的实质
上面已经说了prototype的作用,现在我们来透过规律揭示prototype的实质。
我们说,prototype的行为类似于C++中的静态域,将一个属性添加为prototype的属性,这个属性将被该类型创建的所有实例所共享,但是这种共享是只读的。在任何一个实例中只能够用自己的同名属性覆盖这个属性,而不能够改变它。换句话说,对象在读取某个属性时,总是先检查自身域的属性表,如果有这个属性,则会返回这个属性,否则就去读取prototype域,返回protoype域上的属性。另外,JavaScript允许protoype域引用任何类型的对象,因此,如果对protoype域的读取依然没有找到这个属性,则JavaScript将递归地查找prototype域所指向对象的prototype域,直到这个对象的prototype域为它本身或者出现循环为止,我们可以用下面的图来描述prototype与对象实例之间的关系:
//TODO:
4 prototype的价值与局限性
从上面的分析我们理解了prototype,通过它能够以一个对象为原型,安全地创建大量的实例,这就是prototype的真正含义,也是它的价值所在。后面我们会看到,利用prototype的这个特性,可以用来模拟对象的继承,但是要知道,prototype用来模拟继承尽管也是它的一个重要价值,但是绝对不是它的核心,换句话说,JavaScript之所以支持prototype,绝对不是仅仅用来实现它的对象继承,即使没有了prototype继承,JavaScript的prototype机制依然是非常有用的。
由于prototype仅仅是以对象为原型给类型构建副本,因此它也具有很大的局限性。首先,它在类型的prototype域上并不是表现为一种值拷贝,而是一种引用拷贝,这带来了“副作用”。改变某个原型上引用类型的属性的属性值(又是一个相当拗口的解释:P),将会彻底影响到这个类型创建的每一个实例。有的时候这正是我们需要的(比如某一类所有对象的改变默认值),但有的时候这也是我们所不希望的(比如在类继承的时候),下面给出了一个例子:


代码如下:

<script>
function ClassA()
{
this.a=[];
}
function ClassB()
{
this.b=function(){};
}
ClassB.prototype=new ClassA();
var objB1=new ClassB();
var objB2=new ClassB();
objB1.a.push(1,2,3);
alert(objB2.a);
//所有b的实例中的a成员全都变了!!这并不是这个例子所希望看到的。
</script>

JavaScript实现:
在Java语言中对象都继承自java.lang.Object,而java.lang.Object就提供了Clone的方法,只要实现接口Cloneable,即表示支持Clone,否则抛出异常。在这点JavaScript是非常接近的,所有的对象都是从Object继承,不过Object并不支持Clone的方法,但是我们可以通过自己对于JavaScript通过expanddo的形式实现Clone方法,这样日后所有的对象创建都实现了Clone方法。
因为JavaScript本身没有提供Clone的方法,同时对于对象的赋值如var a=new Object();var b=a,这样的代码a,b是指向同一对象的,要创建一个对象必须通过new这个关键字来实现,因此在Clone的实现过程,我内部定义了一个构造子(constructor)CloneModel,同时指定其父对象为要进行Clone活动本身的对象,因此使用了this关键字,在我们定义的构造子CloneModel的基础上我们创建一个一个对象,因为构造子内部没有任何代码,新创建的对象实际上说所有的实现都在父对象中,也就是我们需要进行Clone的对象。到目前为止,我们已经创建了一个需要复制的对象,但是所有的值都是指向父对象的。
在 JavaScript的面向对象方式中 ,我们曾经讨论过,如果没有覆盖父对象的值,那么这个时候是直接指向父对象的,在Prototype Pattern是要求Clone之后的对象的内部值是不应该相关的,而只要赋值一次,objClone的值都会在自己的内存空间里头,而不是还指向父对象。基于如此的考虑,objClone[v]=objClone[v];语句就是实现将父对象的值通过覆盖的方式拷贝到自己的内存来。

21.2.1 什么是 prototype
JavaScript 中对象的 prototype 属性,可以返回对象类型原型的引用。这是一个相当拗口的解释,要理解它,先要正确理解对象类型(Type)以及原型(prototype)的概念。 前面我们说,对象的类(Class)和对象实例(Instance)之间是一种“创建”关系,因此我们把“类”看作是对象特征的模型化,而对象看作是类特征的具体化,或者说,类(Class)是对象的一个类型(Type)。例如,在前面的例子中,p1 和p2 的类型都是 Point,在 JavaScript 中,通过instanceof运算符可以验证这一点: p1 instanceof Point p2 instanceof Point 但是,Point 不是 p1 和 p2 的唯一类型,因为 p1 和 p2 都是对象,所以 Obejct 也是它们的类型,因为Object 是比 Point 更加泛化的类,所以我们说,Obejct和 Point之间有一种衍生关系,在后面我们会知道,这种关系被叫做“继承”,它也是对象之间泛化关系的一个特例,是面向对象中不可缺少的一种基本关系。 在面向对象领域里,实例与类型不是唯一的一对可描述的抽象关系,在 JavaScript 中,另外一种重要的抽象关系是类型(Type)与原型(prototype)。这种关系是一种更高层次的抽象关系,它恰好和类型与实例的抽象关系构成了一个三层的链,

图 21.2 描述了这种关系:
                        图 21.2 对象、类型与原型的关系
在现实生活中,我们常常说,某个东西是以另一个东西为原型创作的。这两个东西可以是同一个类型,也可以是不同类型。习语“照猫画虎”,这里的猫就是原型,而虎就是类型,用 JavaScript的 prototype 来表示就是“虎.prototype =某只猫”或者“虎.prototype= new 猫()”。 “原型”是描述自然界事物之间“归类”关系的一种,另外几种关系包括“继承”和“接口”。一般来说,“继承”描述的是事物之间固有的衍生关系,能被“继承”所描述的事物之间具有很强的关联性(血缘)。“接口”描述的是事物功用方面的共同特征。而“原型”则倾向于描述事物之间的“相似性”。从这一点来看,“原型”在描述事物关联性的方面,比继承和接口更加广义。 如果你是 Java 程序员,上面的例子从继承的角度来考虑,当然不可能用“猫”去继承“虎”,也不可能用“虎”去继承“猫”,要描述它们的关系,需要建立一个涵盖了它们共性的“抽象类”,或者你会叫它“猫科动物”。可是,如果我的系统中只需要用到“猫”和“老虎”,那么这个多余的“猫科动物”对于我来说没有任何意义,我只需要表达的是,“老虎”有点像“猫”,仅此而已。在这里,用原型帮我们成功地节省了一个没有必要建立的类型“猫科动物”。 要深入理解原型,可以研究关于它的一种设计模式——prototype pattern,这种模式的核心是用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。JavaScript 的 prototype 就类似于这种方式。 关于 prototype pattern的详细内容可以参考《设计模式》(《Design Patterns》)它不是本书讨论的范围。 注意,原型模式要求一个类型在一个时刻只能有一个原型(而一个实例在一个时刻显然可以有多个类型)。对于 JavaScript 来说,这个限制有两层含义,第一是每个具体的 JavaScript 类型有且仅有一个原型(prototype),在默认的情况下,该原型是一个 Object 对象(注意不是 Object 类型!)。第二是,这个类型的实例的所有类型,必须是满足原型关系的类型链。例如 p1 所属的类型是 Point 和 Object,而一个 Object对象是 Point 的原型。假如有一个对象,它所属的类型分别为 ClassA、ClassB、ClassC 和 Object,那么必须满足这四个类构成某种完整的原型链,例如:
例 21.4 原型关系的类型链
function ClassA()
{
……
}
ClassA.prototype = new Object(); //这个可以省略
function ClassB()
{
……
}
ClassB.prototype = new ClassA(); //ClassB以 ClassA的对象为原型
function ClassC()
{
   ……
}
ClassC.prototype = new ClassB(); //ClassC以 ClassB的对象为原型
var obj = new ClassC();
alert(obj instanceof ClassC); //true
alert(obj instanceof ClassB); //true
alert(obj instanceof ClassA); //true
alert(obj instanceof Object); //true

图 21.3 简单描述了它们之间的关系:
图 21.3 原型关系的类型链
有意思的是,JavaScript并没有规定一个类型的原型的类型(这又是一段非常拗口的话),因此它可以是任何类型,通常是某种对象,这样,对象-类型-原形(对象)就可能构成一个环状结构,或者其它有意思的拓扑结构,这些结构为 JavaScript 带来了五花八门的用法,其中的一些用法不但巧妙而且充满美感。下面的一节主要介绍 prototype 的用法。 <

(0)

相关推荐

  • JavaScript自定义数组排序方法

    本文实例讲述了JavaScript自定义数组排序方法.分享给大家供大家参考.具体分析如下: Array中有自带的排序功能,这个使用起来比较方便,我们有一点必须清楚,就是排序的依据,如果sort不传入参数的话,那就是按照字符编码(Unicode编码)的顺序排序. var a=["3","2","1"]; console.log(a[0].charCodeAt(0)); // 51 console.log(a[1].charCodeAt(0)); /

  • JavaScript prototype 使用介绍

    用过JavaScript的同学们肯定都对prototype如雷贯耳,但是这究竟是个什么东西却让初学者莫衷一是,只知道函数都会有一个prototype属性,可以为其添加函数供实例访问,其它的就不清楚了,最近看了一些 JavaScript高级程序设计,终于揭开了其神秘面纱. 每个函数都有一个prototype属性,这个属性是指向一个对象的引用,这个对象称为原型对象,原型对象包含函数实例共享的方法和属性,也就是说将函数用作构造函数调用(使用new操作符调用)的时候,新创建的对象会从原型对象上继承属性和

  • Js利用prototype自定义数组方法示例

    前言 在开始之前,先给大家介绍下js中使用使用原型(prototype)定义方法的好处 经常在前端面试或是和其他同行沟通是,在谈到构造在JS定义构造函数的方法是最好使用原型的方式:将方法定义到构造方法的prototype上,这样的好处是,通过该构造函数生成的实例所拥有的方法都是指向一个函数的索引,这样可以节省内存. 而本文主要给大家介绍了关于Js利用prototype自定义数组方法的相关内容,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧. 题目 如何实现下列代码: [1,2,3

  • 类似php的js数组的in_array函数自定义方法

    PHP的数组函数in_array()非常方便,可JS就不是了.其实我很不喜欢JS的数组~ 别说了,直接上方法 复制代码 代码如下: Array.prototype.in_array = function(e) { for(i=0;i<this.length;i++) { if(this[i] == e) return true; } return false; } 或者 复制代码 代码如下: Array.prototype.in_array = function(e) { for(i=0;i<

  • JavaScript中的prototype使用说明

    1.prototype 在JavaScript中并没有类的概念,但JavaScript中的确可以实现重载,多态,继承.这些实现其实方法都可以用JavaScript中的引用和变量作用域结合prototype来解释. 2.简单的例子 复制代码 代码如下: var Blog = function( name, url ){ this.name = name; this.url = url; }; Blog.prototype.jumpurl = ''; Blog.prototype.jump = fu

  • 深入了解javascript中的prototype与继承

    通常来说,javascript中的对象就是一个指向prototype的指针和一个自身的属性列表.javascript创建对象时采用了写时复制的理念.只有构造器才具有prototype属性,原型链继承就是创建一个新的指针,指向构造器的prototype属性.prototype属性之所以特别,是因为javascript时读取属性时的遍历机制决定的.本质上它就是一个普通的指针. 构造器包括: 1.Object2.Function3.Array4.Date5.String 下面我们来举一些例子吧 复制代

  • js中prototype用法详细介绍

    prototype 是在 IE 4 及其以后版本引入的一个针对于某一类的对象的方法,而且特殊的地方便在于:它是一个给类的对象添加方法的方法!这一点可能听起来会有点乱,别急,下面我便通过实例对这一特殊的方法作已下讲解: 首先,我们要先了解一下类的概念,JavaScript 本身是一种面向对象的语言,它所涉及的元素根据其属性的不同都依附于某一个特定的类.我们所常见的类包括:数组变量(Array).逻辑变量(Boolean).日期变量(Date).结构变量(Function).数值变量(Number)

  • Javascript remove 自定义数组删除方法

    复制代码 代码如下: <html xmlns="http://www.w3.org/1999/xhtml" > <head> <title>Javascript自定义数组删除方法remove()</title> <script type="text/javascript"> Array.prototype.remove=function(dx){ if(isNaN(dx)||dx>this.lengt

  • js中继承的几种用法总结(apply,call,prototype)

    一,js中对象继承 js中有三种继承方式 1.js原型(prototype)实现继承 复制代码 代码如下: <SPAN style="BACKGROUND-COLOR: #ffffff"><SPAN style="FONT-SIZE: 18px"><html>  <body>  <script type="text/javascript">      function Person(na

  • JS 面向对象之神奇的prototype

    JavaScript中对象的prototype属性,可以返回对象类型原型的引用.这是一个相当拗口的解释,要理解它,先要正确理解对象类型(Type)以及原型(prototype)的概念. 1 什么是prototype JavaScript中对象的prototype属性,可以返回对象类型原型的引用.这是一个相当拗口的解释,要理解它,先要正确理解对象类型(Type)以及原型(prototype)的概念. 前面我们说,对象的类(Class)和对象实例(Instance)之间是一种"创建"关系,

  • js构造函数constructor和原型prototype原理与用法实例分析

    本文实例讲述了js构造函数constructor和原型prototype原理与用法.分享给大家供大家参考,具体如下: 所有引用类型(函数,数组,对象)都拥有__proto__属性(隐式原型) 所有函数拥有prototype属性(显式原型)(仅限函数) 原型对象:拥有prototype属性的对象,在定义函数时就被创建 __proto__, prototype和constructor 下面这三个属性的定义非常重要,始终贯穿在原型中. prototype:此属性只有构造函数才有,它指向的是当前构造函数

  • 归纳下js面向对象的几种常见写法总结

    //定义Circle类,拥有成员变量r,常量PI和计算面积的成员函数area() 1.工厂方式 var Circle = function() { var obj = new Object(); obj.PI = 3.14159; obj.area = function( r ) { return this.PI * r * r; } return obj; } var c = new Circle(); alert( c.area( 1.0 ) ); 2.比较正规的写法 function Ci

  • js面向对象实现canvas制作彩虹球喷枪效果

    前段时间在研究canvas,感觉还挺好玩的,就写了一个小demo,效果如下: 第一次尝试用js面向对象的方式来写,经验不足,还请大家多多包涵. 下面开始简单介绍代码: canvas画布: 复制代码 代码如下: <canvas id='canvas' width='1050' height='500' style='background:#333;overflow: hidden;'></canvas> 彩虹球的随机颜色是通过下面两个方法来实现的,在<js常用方法和一些封装(2

  • JS 面向对象之继承---多种组合继承详解

    这一次要讲 组合.原型式.寄生式.寄生组合式继承方式. 1. 组合继承:又叫伪经典继承,是指将原型链和借用构造函数技术组合在一块的一种继承方式. 下面来看一个例子: function SuperType(name) { this.name = name; this.colors = ["red", "blue", "green"]; } SuperType.prototype.sayName = function() { alert(this.n

  • js面向对象之常见创建对象的几种方式(工厂模式、构造函数模式、原型模式)

    在上篇文章给大家介绍了javascript面向对象基础,本篇文章继续深入学习javascript面向对象,JS的语法非常灵活,简单的对象创建就有好几种不同的方法.这些过于灵活的地方有时候确实很让人迷惑,那么今天我们就来梳理一下JS中常用的创建对象的几种方法吧. 前言 虽然使用 Object构造函数 或者使用 对象字面量 可以很方便的用来创建一个对象,但这种方式有一个明显的缺点:使用一个接口创建多个对象会产生很多冗余的代码.因此为了解决这个问题,人们开始使用以下几种方式来常见对象. 工厂模式 该模

  • JS面向对象(3)之Object类,静态属性,闭包,私有属性, call和apply的使用,继承的三种实现方法

    1.Object类 在JS中,Object是所有类的基类,使用Object类来创建自定义对象时,可以无需定义构造函数(constructor,prototype,hasOwnProperty(property)) var per = new Object(); per.name = 'zhangsan'; per.age = ; alert(per.name + per.age); 我们想在程序中得到一个对象变量,只要能存储大量数据即可,这个时候,我们可以考虑使用Object类.Object类避

  • js面向对象之公有、私有、静态属性和方法详解

    现下,javascript大行其道,对于网站开发人员来说,javascript是必需掌据的一门语言,但随着jquery等框架的流行和使用,许多人对于原生javascript缺乏深入的理解,习惯了函数式的编辑风格,对于闭包.原型总是说不清道不明.对于js面向对象蹩脚的用着,而要了解js面向对象,就必需先了解js中什么是公有方法.特权方法.静态方法 方法/步骤 1.公有属性和公有方法 function User(name,age){ this.name = name;//公有属性 this.age

  • jquery方法+js一般方法+js面向对象方法实现拖拽效果

    复制代码 代码如下: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv=&qu

  • js面向对象的写法

    本文归纳了js面向对象的几种常见写法,分享给大家供大家参考,具体内容如下 1.工厂方式 var Circle = function() { var obj = new Object(); obj.PI = 3.14159; obj.area = function( r ) { return this.PI * r * r; } return obj; } var c = new Circle(); alert( c.area( 1.0 ) ); 2.比较正规的写法 function Circle

随机推荐