23
10月

JavaScript的弱类型对象[翻译]

类归于: 做东西 Hbomb 写于 17:39

    在JavaRanch Journal看到一片不错的JavaScript的入门文章,感觉不错,十分易懂,决定把它翻译下,一来方便不懂e文的同志分享,二来可以巩固下关于JavaScript对于对象的理解。

 原文地址: http://www.javaranch.com/journal/2008/10/Journal200810.jsp

作者 Stoyan Staefanov

Java 和JavaScript是两种完全不同的语言,但是名称和都是类C的语法很容易却让人混淆。让我们来看看JavaScript不同于Java中如何创建对象的。在Java里,你得先有类,然后再有对象的,又叫做实例化,创建对象要基于那些类的。但是在JavaScript里,是没有类、对象,而是更像是哈希表中的键值对。但是在JavaScript中是如何实例化对象的呢?好,一步步的来讲。

JavaScript 对象

当你在思考关于一个JavaScript对象时,其实就是在思考一个哈希。这里所有的对象就像是一个键值对的集合,那些值则可以包括是任何的对象和函数。当一个对象的其中一个属性是函数时,你就可以称其为方法。

这个就是一个空方法:

Var  myobj = {};

 

现在你可以添加一些有意义的功能到这个对象了:

myobj,name = “My precious”;

myobj.getName = function() {return this.name};

 

这里要注意的事项:

 正如所预期的那样,内部方法是当前对象的应用
你可以添加、调整、删除属性在任何时候,不只是在创建的时候
另一种创建对象的方式是,在创建对象的同时创建属性和方法,就像这样:

Var another  = {

 name: ‘My other precious’,

 getName:function() {

     return this.name;

  }

};

 

这些语法被称之谓文字符号对象,你总之把一切都放在大括号内{},属性则通过逗号隔开。键:值对通过分号隔开。尽管这个不是唯一创建对象的方法。

 

另一种创建JavaScript对象的方法是使用构造函数的方法。这个是构造函数的例子:

Function ShinyObject(name){

    this.name = name;

    this.getName = function(){

   return this.name;

  }

}

 

现在创建一个对象就很想Java 一样了:

var my = new ShinyObject(’ring’);

Var myname = my .getName();//”ring”

 

构造函数的语法没有相对于其他任何函数有所不同,而不同是在在于用法不同。如果你以new的方式调用一个函数,那就会创建并返回一个对象,通过这个,你就有权限在它返回之前修改它。通过约定,构造函数不同于普通函数和方法,名称首字母要大写。

 

 

 

 

 

对象直接创建和构造函数创建,哪个更好呢?嗯,那就取决于你要做的特定的任务。例如,你要创建很多不同的近似的对象,选择使用类构造的方式是个不错的选择。但是如果你创建不会多于一个的单例的话,则可以使用直接对象创建就显得比较简洁了。

好,那么没有里类,是如何实现继承的呢?在讨论这个之前,这里有些小小的惊喜–在JavaScript里函数是正真的对象。

(实际上在JavaScript里大部分分所有的都是对象,除一些原始数据类型-string,boolean,number 和undefined。函数是对象,数组是对象,甚至null也是对象。此外,这些私有的数据类型也可以转化后使用作对象,就像 “string”.length 是有效的。)

 

Function 对象和prototype 属性

在JavaScript里,函数就是对象,可以赋给变量,你可以添加属性和方法等到上面。这里是一个例子:

var myfunc = function(param) {

 alert(param);

};

 

就和这一样:

function myfunc(param) {

 alertparam);

}

 

不管如何你创建的这个函数,你最终可以访问 myfunc里的属性和方法。

alert(myfunc.length);     // 提示1, 数字型的参数

alert(myfunc.toString()); // 提示函数的源代码

 

 

每一个function对象都有一个有趣的特性:都有prototype(原型)这个属性。

当你创建一个function的同时,将自动获取一个指向一个空对象的prototype属性。当然,你能修改这个空对象的属性。

 

alert(typeof myfunc.prototype); // 提示“Object

myfunc.prototype.test = 1; // 完全可以这么做

 

有个问题,prototype有什么用呢?prototype仅可以用在当你引用一个function作为构造函数方式来创建的对象上。当你这么做,这对象就自动获取一个秘密的链接到prototype的属性,然后使之成为自己的属性。真的吗?

 

让我们来看看这个实例。

 

一个新的function

function ShinyObject(name) {

 this.name = name;

}

 

给这个functionprototype属性传参数来添加一些功能:

 

ShinyObject.prototype.getName = function() {

 return this.name;

};

 

使用function像构造函数的方式来创建的对象:

var iphone = new ShinyObject(’my precious’);

iphone.getName(); // 返回”my precious”

 

就像你看到的那样,一个新的对象自动获取这个有权限的prototype属性。然后当有些“免费”获取功能,开始闻到有点像继承和reusability 代码的味道了。

 

以原型的模式继承

 

现在让我们看看你将如何prototype来实现继承。

这里是一个做为父类的构造函数:

 

function NormalObject() {

 this.name = ‘normal’;

 this.getName = function() {

    return this.name;

 };

}

 

第二个构造函数:

 

function PreciousObject(){

 this.shiny = true;

 this.round = true;

}

 

现在继承的部分:

 

PreciousObject.prototype = new NormalObject();

 

啊哈!你可以创建precious对象了,并且将获取所有Normal对象的功能:

 

var crystal_ball = new PreciousObject();

crystal_ball.name = ‘Ball, Crystal Ball.’;

alert(crystal_ball.round); // true

alert(crystal_ball.getName()); // “Ball, Crystal Ball.”

 

注意为什么我们创建一个对象要通过prototype的方式新建或赋予,因为prototype就是一个对象。它不像一个构造函数继承自其他,事实上我们继承是从一个对象的。JavaScript是没有类继承自类的说法,这里只有对象继承自对象。

如果你有一些构造函数继承自NormalObject对象,你或许每次都要new NormalObject()的,但是那是不必要的。甚至整个NormalObject结构体也是不必要的。另一种方式一样做到通过创建一个(单例)的normal object然后使用它就像使用其他的对象。

 

var normal = {

 name: ‘normal’,

 getName: function() {

    return this.name;

 }

};

 

然后PreciousObject能够像这样来继承:

 

PreciousObject.prototype =normal;

 

自从继承者将全部调用代码,已经简单复制属性通过另一种方法来实现。

 

设想你有以下的对象

var shiny = {

   shiny: true,

   round: true

};

 

var normal = {

 name: ‘name me’,

 getName: function() {

    return this.name;

 }

};

 

如何让shiny获取mormal的属性?这里是一个简单的extend()函数,用来循环迭代和复制属性:

 

function extend(parent, child) {

 for (var i in parent) {

    child[i] = parent[i];

 }

}

 

extend(normal, shiny); // 继承

shiny.getName(); // “name me”

 

现在看来这种属性拷贝有一定的开销而感觉不是很好,但是事实上,对于完成大多数任务还不错。你也可以把这个看做实现组合和多重继承的简单途径。

 

Crockford的由父级对象产生对象的方法

Douglas Crockford,是一位JavaScript的宗师和JSON的创始人,他提出了这个有趣的begetObject()方式来实现继承:

 

function begetObject(o) {

 function F() {}

 F.prototype = o;

 return new F();

}

在这里你创建一个临时的构造函数,这样以至于可以使用prototype(原型)的功能,原理是创建一个对象同时继承已存在对象的一些功能。

 

 父级对象:

 

var normal = {

 name: ‘name me’,

 getName: function() {

    return this.name;

 }

};

 

一个新创建继承自父级对象的对象:

var shiny = begetObject(normal);

 

给这个对象新增更多的功能:

 

Shiny.round = true;

 

YUIextend()

 

让我们再来看另一个实现继承的方式,这个更接近于Java,因为在这个方式下,看起来构造函数像是继承自另一个构造函数,因此有点像一个类继承自另一个类。

 

这个方式在非常流行的 YUI JavaScript libraryYahoo! User Interface)这里一个简单版本:

 

function extend(Child, Parent) {

 var F = function(){};

 F.prototype = Parent.prototype;

 Child.prototype = new F();

}

通过这个方法,你传递两个构造函数,第一个(子类)将会通过原型(prototype)属性得到第二个(父类)的所有属性和方法。

 

总结

 

让我们快速总结下关于JavaScript刚才所学习的:

 

没有类的概念

对象继承自对象

对象枚举的方式:var o ={};

构造函数提供类似Java的语法 var o = new Object();

函数和对象的概念

所有函数对象都有一个原型属性

最后,还有讲了一些实现继承的方式,你可以任意的挑选,可以说是手头的任务,个人癖好,团队偏好,或是当前的月相。

 

作者和声明

 

Stoyan Stefanov 是一位资深的Yahoo!开发者, YSlow tool的主导者,开源贡献者,博客作者和技术撰稿人,最近是Packet出版的“Object-Oriented JavaScript”一书 的作者。

 

shiny对象的例子的灵感来自于 Jim Bumgardner撰写的Theory of the Precious Object一书。

 

Douglas Crockford的 beget object - 文章点击这里

没有关联的文件。

                                 

评论暂缺 »

还没有任何评论。

这篇文章上的评论 RSS feed TrackBack URL

留下评论