您好,欢迎来到养宠指南。
搜索
您的当前位置:首页

javascript面向对象特性代码实例_javascript技巧

2022-06-15 来源:养宠指南
摘要
能够写出可维护的面向对象JavaScript代码不仅可以节约金钱,还能让你很受欢迎。不信?有可能你自己或者其他什么人有一天会回来重用你的代码。如果能尽量让这个经历不那么痛苦,就可以节省不少时间。地球人都知道,时间就是金钱。同样的,你也会因为帮某人省去了头疼的过程而获得他的偏爱。但是,在开始探索如何编写可维护的面向对象JavaScript代码之前,我们先来快速看看什么是面向对象。如果已经了解面向对象的概念了,就可以直接跳过下一节。什么是面向对象?面向对象编程主要通过代码代表现实世界中的实质对象。要

一、基本的类的使用方法一: 代码如下:function sth(a) // 构造函数 { this.a = a; this.fun = output; // 成员函数 }

function output(a, b, c) { document.write(this.a); }

//调用var s = new sth(250); s.fun(1, 2, 3); ouput(1, 2, 3); //如果output在sth之前就是错的

方法二: 代码如下:function sth(a) { this.a = a; this.output = function() { document.write(this.a); } } var s = new sth(2); s.output(); // 输出2 二、继承方法一: 代码如下:function A(x) { this.x = x; }

function B(x, y) { // 方法1 /* this.construct = A; this.construct(x); delete this.construct; */ // 方法2 //A.call(this, x); // 方法3 A.apply(this, new Array(x)); // 亦可A.apply(this, arguments), 不过arguments参数顺序一定要对 this.y = y; this.print = function() { document.write("x = ", x, ", y = ", y); } }

var b = new B(1, 2); b.print();alert(B instanceof A); // 输出false

优点:可以实现多继承(多调用call就好)

缺点: · 必须以构造函数方式使用 · 使用instanceof运算符运算此类继承结果为false

方法二: 代码如下:function A() {

} A.prototype.x = 1; function B() {

} B.prototype = new A(); // 不能带参数! B.prototype.y = 2; B.prototype.print = function() { document.write(this.x, ", ", this.y, ""); } var b = new B(); b.print(); document.write(b instanceof A); // 输出true缺点: · 不能实现多继承 · 构造函数不带参数

Tips

通常使用混合模式,两者一起用 代码如下:function A(x) { this.x = x; } A.prototype.printx = function() // 写到A类里面this.printx = function....也是可以的,下同{ document.write(this.x, ""); } function B(x, y) { A.call(this, x); this.y = y; } B.prototype = new A(); // 不能带参数! B.prototype.printxy = function() { document.write(this.x, ", ", this.y, ""); } var b = new B(1, 2); b.printx(); // 输出1 b.printxy(); // 输出1, 2 document.write(b instanceof A); // 输出true

三、类似静态成员函数的使用 代码如下:function sth(a) { this.a = a; } sth.fun = function(s) { document.write(s.a); } var s = new sth(2); sth.fun(s); // 输出2

四、对象的释放 代码如下:var obj = new Object; // obj是引用obj = null; // 取消引用,会自动进行垃圾回收;如果需要根本释放此对象,要将它的所有引用都赋值为null

五、函数对象 代码如下:var v = new Function("arg1", "arg2", "document.write(arg1 + arg2);"); // 定义一个函数对象,参数分别是arg1,arg2 v(1, 2); // 将会输出3

六、回调函数 代码如下:function callback(func, arg) { func(arg); } function fun(arg) { document.write(arg); }//callback(func, "sb"); // 这种做法不行 var func = new Function("arg", "fun(arg);"); // 当然也可以把func(arg)换成具体的执行代码, // 但是函数代码庞大了就最好这样做了 callback(func, "sb");

七、函数的重载 代码如下:function fun() { switch (arguments.length) { case 1: document.write(arguments[0]); break; case 2: document.write(arguments[0] + arguments[1]); break; default: document.write("ERROR!"); break; } } fun(1); fun(1, 2);

八、利用函数闭包实现有“静态变量”的函数 代码如下:function fun() { var v = 1; function fun2() { ++v; document.write(v); document.write(""); return v; } return fun2; } var func = fun(); func(); // 输出2 func(); // 输出3 func(); // 输出4

小编还为您整理了以下内容,可能对您也有帮助:

怎样编写可维护的面向对象JavaScript代码

能够写出可维护的面向对象JavaScript代码不仅可以节约金钱,还能让你很受欢迎。不信?有可能你自己或者其他什么人有一天会回来重用你的代码。如果能尽量让这个经历不那么痛苦,就可以节省不少时间。地球人都知道,时间就是金钱。同样的,你也会因为帮某人省去了头疼的过程而获得他的偏爱。但是,在开始探索如何编写可维护的面向对象JavaScript代码之前,我们先来快速看看什么是面向对象。如果已经了解面向对象的概念了,就可以直接跳过下一节。

什么是面向对象?

面向对象编程主要通过代码代表现实世界中的实质对象。要创建对象,首先需要写一个“类”来定义。 类几乎可以代表所有的东西:账户,员工,导航菜单,汽车,植物,广告,饮料,等等。而每次要创建对象的时候,就从类实例化一个对象。换句话说,就是创建类的实例做为对象。事实上,通常处理一个以上的同类事物时就会使用到对象。另外,只需要简单的函数式程序就可以做的很好。对象实质上是数据的容器。因此在一个employee对象中,你可能要储存员工号,姓名,入职日期,职称,工资,资历,等等。

对象也包括处理数据的函数(也叫做“方法”)。方法被用作媒介来确保数据的完整性,以及在储存之前对数据进行转换。例如,方法可以接收任意格式的日期然后在储存之前将其转化成标准化格式。最后,类还可以继承其他的类。继承可以让你在不同类中重复使用相同代码。例如,银行账户和音像店账户都可以继承一个基本的账户类,里面包括个人信息,开户日期,分部信息,等等。然后每个都可以定义自己的交易或者借款处理等数据结构和方法。

警告:JavaScript面向对象是不一样的

在上一节中,概述了经典的面向对象编程的基本知识。说经典是因为JavaScript并不遵循这些规则。相反地,JavaScript的类是写成函数的样子,而继承则是通过原型实现的。原型继承基本上意味着使用原型属性来实现对象的继承,而不是从类继承类。

对象的实例化

以下是JavaScript中对象实例化的例子:

// 定义Employee类

function Employee(num, fname, lname) {

this.getFullName = function () {

return fname + " " + lname;

}

};

// 实例化Employee对象

var john = new Employee("4815162342", "John", "Doe");

alert("The employee's full name is " + john.getFullName());在这里,有三个重点需要注意:

1 “class”函数名的第一个字母要大写。这表明该函数的目的是被实例化而不是像一般函数一样被调用。

2 在实例化的时候使用了new操作符。如果省略掉new而仅仅调用函数则会产生很多问题。

3 因为getFullName指定给this操作符了,所以是公共可用的,但是fname和lname则不是。由Employee函数产生的闭包给了getFullName到fname和lname的入口,但同时对于其他类仍然是私有的。

原型继承

下面是JavaScript中原型继承的例子:

// 定义Human类

function Human() {

this.setName = function (fname, lname) {

this.fname = fname;

this.lname = lname;

}

this.getFullName = function () {

return this.fname + " " + this.lname;

}

}

// 定义Employee类

function Employee(num) {

this.getNum = function () {

return num;

}

};

//让Employee继承Human类

Employee.prototype = new Human();

// 实例化Employee对象

var john = new Employee("4815162342");

john.setName("John", "Doe");

alert(john.getFullName() + "'s employee number is " + john.getNum());这一次,创建的Human类包含人类的一切共有属性——我也将fname和lname放进去了,因为不仅仅是员工才有名字,所有人都有名字。然后将Human对象赋值给它的prototype属性。

通过继承实现代码重用

在前面的例子中,原来的Employee类被分解成两个部分。所有的人类通用属性被移到了Human类中,然后让Employee继承Human。这样的话,Human里面的属性就可以被其他的对象使用,例如Student(学生),Client(顾客),Citizen(公民),Visitor(游客),等等。现在你可能注意到了,这是分割和重用代码很好的方式。处理Human对象时,只需要继承Human来使用已存在的属性,而不需要对每种不同的对象都重新一一创建。除此以外,如果要添加一个“中间名字”的属性,只需要加一次,那些继承了 Human 类的就可以立马使用了。反而言之,如果我们只是想要给一个对象加“中间名字”的属性,我们就直接加在那个对象里面,而不需要在Human 类里面加。

1. Public(公有的)和Private(私有的)

接下来的主题,我想谈谈类中的公有和私有变量。根据对象中处理数据的方式不同,数据会被处理为私有的或者公有的。私有属性并不一定意味着其他人无法访问。可能只是某个方法需要用到。

只读

有时,你只是想要在创建对象的时候能有一个值。一旦创建,就不想要其他人再改变这个值。为了做到这点,可以创建一个私有变量,在实例化的时候给它赋值。

function Animal(type) {

var data = [];

data['type'] = type;

this.getType = function () {

return data['type'];

}

}

var fluffy = new Animal('dog');

fluffy.getType();

// 返回 'dog'在这个例子中,Animal类中创建了一个本地数组data。当 Animal对象被实例化时,传递了一个type的值并将该值放置在data数组中。因为它是私有的,所以该值无法被覆盖(Animal函数定义了它的范围)。一旦对象被实例化了,读取type值的唯一方式是调用getType方法。因为getType是在Animal中定义的,因此凭借Animal产生的闭包,getType可以进到data中。这样的话,虽可以读到对象的类型却无法改变。

有一点非常重要,就是当对象被继承时,“只读”技术就无法运用。在执行继承后,每个实例化的对象都会共享那些只读变量并覆盖其值。最简单的解决办法是将类中的只读变量转换成公共变量。但是你必须保持它们是私有的,你可以使用Philippe在评论中提到的技术。

Public(公有)

当然也有些时候你想要任意读写某个属性的值。要实现这一点,需要使用this操作符。

function Animal() {

this.mood = '';

}

var fluffy = new Animal();

fluffy.mood = 'happy';

fluffy.mood;

// 返回 'happy'

这次Animal类公开了一个叫mood的属性,可以被随意读写。同样地,你还可以将函数指定给公有的属性,例如之前例子中的getType函数。只是要注意不要给getType赋值,不然的话你会毁了它的。

完全私有

最后,可能你发现你需要一个完全私有化的本地变量。这样的话,你可以使用与第一个例子中一样的模式而不需要创建公有方法。

function Animal() {

var secret = "You'll never know!"

}

var fluffy = new Animal();

2. 写灵活的API

既然我们已经谈到类的创建,为了保持与产品需求变化同步,我们需要保持代码不过时。如果你已经做过某些项目或者是长期维护过某个产品,那么你就应该知道需求是变化的。这是一个不争的事实。如果你不是这么想的话,那么你的代码在还没有写之前就将注定荒废。可能你突然就需要将选项卡中的内容弄成动画形式,或是需要通过Ajax调用来获取数据。尽管准确预测未来是不大可能,但是却完全可以将代码写灵活以备将来不时之需。

Saner参数列表

在设计参数列表的时候可以让代码有前瞻性。参数列表是让别人实现你代码的主要接触点,如果没有设计好的话,是会很有问题的。你应该避免下面这样的参数列表:

function Person(employeeId, fname, lname, tel, fax, email, email2, dob) {

};

这个类十分脆弱。如果在你发布代码后想要添加一个中间名参数,因为顺序问题,你不得不在列表的最后往上加。这让工作变得尴尬。如果你没有为每个参数赋值的话,将会十分困难。例如:

var ara = new Person(1234, "Ara", "Pehlivanian", "514-555-1234", null, null, null, "1976-05-17");操作参数列表更整洁也更灵活的方式是使用这个模式:

function Person(employeeId, data) {

};有第一个参数因为这是必需的。剩下的就混在对象的里面,这样才可以灵活运用。

var ara = new Person(1234, {

fname: "Ara",

lname: "Pehlivanian",

tel: "514-555-1234",

dob: "1976-05-17"

});这个模式的漂亮之处在于它即方便阅读又高度灵活。注意到fax, email和email2完全被忽略了。不仅如此,对象是没有特定顺序的,因此哪里方便就在哪里添加一个中间名参数是非常容易的:

var ara = new Person(1234, {

fname: "Ara",

mname: "Chris",

lname: "Pehlivanian",

tel: "514-555-1234",

dob: "1976-05-17"

});类里面的代码不重要,因为里面的值可以通过索引来访问:

function Person(employeeId, data) {

this.fname = data['fname'];

};如果data['fname'] 返回一个值,那么他就被设定好了。否则的话,没被设定好,也没有什么损失。

让代码可嵌入

随着时间流逝,产品需求可能对你类的行为有更多的要求。而该行为却与你类的核心功能没有半毛钱关系。也有可能是类的唯一一种实现,好比在一个选项卡的面板获取另一个选项卡的外部数据时,将这个选项卡面板中的内容变灰。你可能想把这些功能放在类的里面,但是它们不属于那里。选项卡条的责任在于管理选项卡。动画和获取数据是完全不同的两码事,也必须与选项卡条的代码分开。唯一一个让你的选项卡条不过时而又将那些额外的功能排除在外的方法是,允许将行为嵌入到代码当中。换句话说,通过创建事件,让它们在你的代码中与关键时刻挂钩,例如onTabChange, afterTabChange, onShowPanel, afterShowPanel等等。那样的话,他们可以轻易地与你的onShowPanel事件挂钩,写一个将面板内容变灰的处理器,这样就皆大欢喜了。JavaScript库让你可以足够容易地做到这一点,但是你自己写也不那么难。下面是使用YUI 3的一个例子。

<script type="text/javascript" src="http://yui.yahooapis.com/combo?3.2.0/build/yui/yui-min.js"></script>

<script type="text/javascript">

YUI().use('event', function (Y) {

function TabStrip() {

this.showPanel = function () {

this.fire('onShowPanel');

// 展现面板的代码

this.fire('afterShowPanel');

};

};

// 让TabStrip有能力激发常用事件

Y.augment(TabStrip, Y.EventTarget);

var ts = new TabStrip();

// 给TabStrip的这个实例创建常用时间处理器

ts.on('onShowPanel', function () {

//在展示面板之前要做的事

});

ts.on('onShowPanel', function () {

//在展示面板之前要做的其他事

});

ts.on('afterShowPanel', function () {

//在展示面板之后要做的事

});

ts.showPanel();

});

</script>这个例子有一个简单的 TabStrip 类,其中有个showPanel方法。这个方法激发两个事件,onShowPanel和afterShowPanel。这个能力是通过用Y.EventTarget扩大类来实现的。一旦做成,我们就实例化了一个TabStrip对象,并将一堆处理器都分配给它。这是用来处理实例的唯一行为而又能避免混乱当前类的常用代码。

总结

如果你打算重用代码,无论是在同一网页,同一网站还是跨项目操作,考虑一下在类里面将其打包和组织起来。面向对象JavaScript很自然地帮助实现更好的代码组织以及代码重用。除此以外,有点远见的你可以确保代码具有足够的灵活性,可以在你写完代码后持续使用很长时间。编写可重用的不过时JavaScript代码可以节省你,你的团队还有你公司的时间和金钱。这绝对能让你大受欢迎。

如何用javascript面向对象编程

经常看到一些JavaScript的代码脏乱得无法理解,到处都是属性和方法,或者一个循环套着一个循环。但如果使用面向对象就能很好的理清代码,并方便理解和修改代码。如果你不希望自己的代码只有上帝理解的话,就请尽量考虑使用面向对象的模式。
译文正文:
到处都是属性、方法,代码极其难懂,天哪,我的程序员,你究竟在做什么?仔细看看这篇指南,让我们一起写出优雅的面向对象的JavaScript代码吧!
作为一个开发者,能否写出优雅的代码对于你的职业生涯至关重要。随着像Node.js这类技术的发展,你甚至可以在服务器端使用JavaScript了。同样的,你也可以使用JavaScript来控制MongoDB的持续数据存储。
文本标记
文本标记只是JavaScript里创建对象的一种方法,当然这里肯定不止这一种,但它是你在只打算创建一个对象实例时的首选方法。
var bill = {};

上面的代码并不实用,它只是一个空对象。接下来我们动态地向这个对象中添加一些属性和方法。
bill.name = "Bill E Goat"; bill.sound = function() { console.log( 'bahhh!' ); };

这里添加了属性name,并且给它分配了值"Bill E Goat"。我们并不需要先创建一个空对象,而可以把所有代码直接写在一对括号里。

var bill = { name: "Bill E Goat", sound: function() { console.log( 'bahhh!' ); }};

是不是很美观?访问它的属性和方法就像呼吸一样简单、自然。
bill.name; // "Bill E Goat" bill.sound(); // "bahhh"

如果属性名不是一个合法的标志符,我们还可以这样访问它:
bill['name']; // "Bill E Goat"

注意:我在调用方法时在其后添加了圆括号。现在,我们再重写一下当前的sound方法,并添加一个参数。
bill.sound = function(noise) { console.log(noise); }; bill.sound("brrr!"); // "brrr!" He's cold :)

很好,我们已经传入参数了,并且在方法定义中访问了它。接下来,向对象中增加一个新方法来访问name属性。
bill.sayName = function() { console.log( "Hello " + this.name ); }; bill.sayName(); // "Hello Bill E Goat"

我们可以使用this.propertyName(在本例中即this.name)在方法内访问属性。
bill.sayName; // function

怎么回事?访问sayName方法返回了一个方法定义。现在让我们再深入些。
var sound = bill.sound; sound('moo!'); // "moo!"

现在我们指定了sound方法为一个局部函数,可以调用这个函数并且传递参数。你认为在复制bill的时候会发生什么?(类比下克隆羊Dolly)
var sally = bill; sally.name; // "Bill E Goat",可它的名字是Sallysally.name = "Sally"; sally.name; // "Sally",好些了bill.name; // "Sally",问题又转移到bill身上了

上面的例子中我们新建了一个变量sally,并使它和bill相同,所以bill和sally会在内存中引用了同一个对象。这时候给改变一块它们就会同时发生改变。再看看下面这段代码:
bill.name = "Bill E Goat"; bill.sayName(); // "Hello Bill E Goat"; var sayName = bill.sayName; sayName; // function 目前为止一切顺利sayName(); // "Hello ",为什么这里又不再显示bill的名字了?

bill的name是一个本地实例变量,只对bill可得。当sayName方法被创建为全局变量时,当它碰到this.name声明时,它会在全局查找name的值。唯一的问题在于name还没有被定义。现在让我们在全局定义name,看看会发生什么:
var name = "Bearded Octo"; sayName(); // "Hello Bearded Octo"

这里我们在全局范围内定义了name变量,并且赋予了值"Bearded Octo"。当我们在调用sayHello方法时它会在全局范围内查找name变量,最终会获得值"Bearded Octo"。我们为什么不为这几个对象建立一个共同的“类”呢?
构造函数
构造函数是另一个编写面向对象JavaScript代码的方法,当你需要初始化对象的属性、方法,或者需要创建多个属性、方法各不相同的实例时,它将是你最佳的选择。同样我们先从创建一个空对象开始:
function Game() {};

这个对象包括自己的属性,你甚至可以在创建对象时传入属性,然后再对其进行修改。
var zelda = new Game(); var smb = new Game(); zelda.title = "Legend of Zelda"; smb.title = "Super Mario Brothers"; zelda.title; // "Legend of Zelda" smb.title; // "Super Mario Brothers"

现在这个对象已经有自己的方法了!新创建对象时我们甚至可以传递属性,之后再修改。
function Game(title) { this.title = typeof title !== 'undefined' ? title : ""; }; var zelda = new Game("Legend of Zelda"); zelda.title; // "Legend of Zelda" zelda.title = "Ocarina of Time"; zelda.title; // "Ocarina of Time" var blank = new Game(); blank.title; // ""

也许你没看明白第二行的内容,其实是使用了三元操作来避免单行的if else,它和下面标准的if else语句是一个意思。
if (typeof title !== 'undefined') { this.title = title; } else { this.title = ""; } // Is the same as this.title = typeof title !== 'undefined' ? title : "";

如果title变量在对象被创建时传入,title实例变量将会指定为title的值。如果没有值传入,那么title将会被初始化为默认值""。我们同样可以创建一个方法来访问这个属性:
zelda.loveTitle = function() { console.log( "I love " + this.title ); }; zelda.loveTitle(); // "I love Ocarina of Time"

这样就很整洁了,但是我们还能做得更好。我们可以在Game类中添加一个方法,这样所有Game类的实例将都能使用此方法。
Game.prototype.heartIt = function() { console.log( "I heart " + this.title ); }; zelda.heartIt(); // "I heart Ocarina of Time" smb.heartIt(); // "I heart Super Mario Brothers"

如何用javascript面向对象编程

经常看到一些JavaScript的代码脏乱得无法理解,到处都是属性和方法,或者一个循环套着一个循环。但如果使用面向对象就能很好的理清代码,并方便理解和修改代码。如果你不希望自己的代码只有上帝理解的话,就请尽量考虑使用面向对象的模式。
译文正文:
到处都是属性、方法,代码极其难懂,天哪,我的程序员,你究竟在做什么?仔细看看这篇指南,让我们一起写出优雅的面向对象的JavaScript代码吧!
作为一个开发者,能否写出优雅的代码对于你的职业生涯至关重要。随着像Node.js这类技术的发展,你甚至可以在服务器端使用JavaScript了。同样的,你也可以使用JavaScript来控制MongoDB的持续数据存储。
文本标记
文本标记只是JavaScript里创建对象的一种方法,当然这里肯定不止这一种,但它是你在只打算创建一个对象实例时的首选方法。
var bill = {};

上面的代码并不实用,它只是一个空对象。接下来我们动态地向这个对象中添加一些属性和方法。
bill.name = "Bill E Goat"; bill.sound = function() { console.log( 'bahhh!' ); };

这里添加了属性name,并且给它分配了值"Bill E Goat"。我们并不需要先创建一个空对象,而可以把所有代码直接写在一对括号里。

var bill = { name: "Bill E Goat", sound: function() { console.log( 'bahhh!' ); }};

是不是很美观?访问它的属性和方法就像呼吸一样简单、自然。
bill.name; // "Bill E Goat" bill.sound(); // "bahhh"

如果属性名不是一个合法的标志符,我们还可以这样访问它:
bill['name']; // "Bill E Goat"

注意:我在调用方法时在其后添加了圆括号。现在,我们再重写一下当前的sound方法,并添加一个参数。
bill.sound = function(noise) { console.log(noise); }; bill.sound("brrr!"); // "brrr!" He's cold :)

很好,我们已经传入参数了,并且在方法定义中访问了它。接下来,向对象中增加一个新方法来访问name属性。
bill.sayName = function() { console.log( "Hello " + this.name ); }; bill.sayName(); // "Hello Bill E Goat"

我们可以使用this.propertyName(在本例中即this.name)在方法内访问属性。
bill.sayName; // function

怎么回事?访问sayName方法返回了一个方法定义。现在让我们再深入些。
var sound = bill.sound; sound('moo!'); // "moo!"

现在我们指定了sound方法为一个局部函数,可以调用这个函数并且传递参数。你认为在复制bill的时候会发生什么?(类比下克隆羊Dolly)
var sally = bill; sally.name; // "Bill E Goat",可它的名字是Sallysally.name = "Sally"; sally.name; // "Sally",好些了bill.name; // "Sally",问题又转移到bill身上了

上面的例子中我们新建了一个变量sally,并使它和bill相同,所以bill和sally会在内存中引用了同一个对象。这时候给改变一块它们就会同时发生改变。再看看下面这段代码:
bill.name = "Bill E Goat"; bill.sayName(); // "Hello Bill E Goat"; var sayName = bill.sayName; sayName; // function 目前为止一切顺利sayName(); // "Hello ",为什么这里又不再显示bill的名字了?

bill的name是一个本地实例变量,只对bill可得。当sayName方法被创建为全局变量时,当它碰到this.name声明时,它会在全局查找name的值。唯一的问题在于name还没有被定义。现在让我们在全局定义name,看看会发生什么:
var name = "Bearded Octo"; sayName(); // "Hello Bearded Octo"

这里我们在全局范围内定义了name变量,并且赋予了值"Bearded Octo"。当我们在调用sayHello方法时它会在全局范围内查找name变量,最终会获得值"Bearded Octo"。我们为什么不为这几个对象建立一个共同的“类”呢?
构造函数
构造函数是另一个编写面向对象JavaScript代码的方法,当你需要初始化对象的属性、方法,或者需要创建多个属性、方法各不相同的实例时,它将是你最佳的选择。同样我们先从创建一个空对象开始:
function Game() {};

这个对象包括自己的属性,你甚至可以在创建对象时传入属性,然后再对其进行修改。
var zelda = new Game(); var smb = new Game(); zelda.title = "Legend of Zelda"; smb.title = "Super Mario Brothers"; zelda.title; // "Legend of Zelda" smb.title; // "Super Mario Brothers"

现在这个对象已经有自己的方法了!新创建对象时我们甚至可以传递属性,之后再修改。
function Game(title) { this.title = typeof title !== 'undefined' ? title : ""; }; var zelda = new Game("Legend of Zelda"); zelda.title; // "Legend of Zelda" zelda.title = "Ocarina of Time"; zelda.title; // "Ocarina of Time" var blank = new Game(); blank.title; // ""

也许你没看明白第二行的内容,其实是使用了三元操作来避免单行的if else,它和下面标准的if else语句是一个意思。
if (typeof title !== 'undefined') { this.title = title; } else { this.title = ""; } // Is the same as this.title = typeof title !== 'undefined' ? title : "";

如果title变量在对象被创建时传入,title实例变量将会指定为title的值。如果没有值传入,那么title将会被初始化为默认值""。我们同样可以创建一个方法来访问这个属性:
zelda.loveTitle = function() { console.log( "I love " + this.title ); }; zelda.loveTitle(); // "I love Ocarina of Time"

这样就很整洁了,但是我们还能做得更好。我们可以在Game类中添加一个方法,这样所有Game类的实例将都能使用此方法。
Game.prototype.heartIt = function() { console.log( "I heart " + this.title ); }; zelda.heartIt(); // "I heart Ocarina of Time" smb.heartIt(); // "I heart Super Mario Brothers"

JavaScript定义类或函数的几种方式小结_js面向对象

提起面向对象我们就能想到类,对象,封装,继承,多态。在《javaScript高级程序设计》(人民邮电出版社,曹力、张欣译。英文名字是:Professional JavaScript for Web Developers)这本书中描述的还算比较详细。我们看看JavaScript中定义类的各种方法。

1.工厂方式

javaScript中创建自己的类和对象,我们应该是必须掌握的,我们都知道javaScript中对象的属性可以在对象创建后动态定义,比如下面的代码:

代码如下:

//定义

var oCar = new Object();

oCar.color = "red";

oCar.doors = 4;

oCar.showColor = function() {

alert(this.color);

}

//调用

oCar.showColor(); 我们很容易使用oCar对象,但是我们创就是想创建多个Car实例。我们可以使用一个函数来封装上面的代码来实现:

代码如下:

//定义

function createCar() {

var oCar = new Object();

oCar.color = "red";

oCar.doors = 4;

oCar.showColor = function() {

alert(this.color);

}

return oCar;

}

//调用

var ocar1 = createCar();

var ocar2 = createCar();

ocar1.color = "black";

ocar1.showColor();

ocar2.showColor(); 顺便说一下,javaScript对象默认成员属性都是public 的。这种方式我们称为工厂方式,我们创造了能创建并返回特定类型的对象的工厂。

这样做有点意思了,但是在面向对象中我们经常使用创建对象的方法是:

Car car=new Car();

使用new 关键字已经深入人心,因此我们使用上面的方法去定义总感觉别扭,并且每次调用时都去创建新的属性以及函数,功能上也不实际。下来我们看看构造函数的形式定义类。

2.构造函数

这种方式看起来有点象工厂函数。具体表现如下:

代码如下:

//定义

function Car(color, doors) {

this.color = color;

this.doors = doors;

this.showColor = function() {

alert(this.color);

};

}

//调用

var car1 = new Car("red", 4);

var car2 = new Car("blue", 4);

car1.showColor();

car2.showColor(); 看起来效果很明显,有差别了吧。感觉有点意思了。在构造函数内部创造对象使用this 关键字,使用new 运算符创建对象感觉非常亲切。但是也有点问题:每次new 对象时都会创建所有的属性,包括函数的创建,也就是说多个对象完全,我们定义类的目的就是为了共享方法以及数据,但是car1对象与car2对象都是各自的属性与函数,最起码我们应该共享方法。这就是原形方式的优势所在。

3.原型方式

利用对象的prototype属性,可把它看出创建新对象所依赖的原型。方法如下:

代码如下:

//定义

function Car() {

};

Car.prototype.color = "red";

Car.prototype.doors = 4;

Car.prototype.drivers = new Array("Tom", "Jerry");

Car.prototype.showColor = function() {

alert(this.color);

}

//调用:

var car1 = new Car();

var car2 = new Car();

car1.showColor();

car2.showColor();

alert(car1.drivers);

car1.drivers.push("stephen");

alert(car1.drivers); //结果:Tom,Jerry,stephen

alert(car2.drivers); //结果:Tom,Jerry,stephen

//可以用json方式简化prototype的定义:

Car.prototype =

{

color: "red",

doors: 4,

drivers: ["Tom", "Jerry",'safdad'],

showColor: function() {

alert(this.color);

}

}

首先这段代码的构造函数,其中没有任何代码,接下来通过对象的prototype属性添加属性定义Car对象的属性。这种方法很好,但是问题是Car的对象指向的是Array指针,Car的两个对象都指向同一个Array数组,其中一个对象car1改变属性对象的引用(数组Array)时,另一个对象car2也同时改变,这是不允许的。

同时该问题也表现在原型不能带任何初始化参数,导致构造函数无法正常初始化。这需要另一种方式来解决:那就是混合的构造函数/原型模式。

4. 混合的构造函数/原型模式

联合使用构造函数和原型方式,定义类就非常方便。

代码如下:

//定义

function Car(color,doors)

{

this.color=color;

this.doors=doors;

this.drivers=new Array("Tom","Jerry");

}

Car.prototype.showColor=function(){

alert(this.color);

}

//调用:

var car1=new Car('red',4);

var car2=new Car('blue',4);

car1.showColor();

car2.showColor();

alert(car1.drivers);

car1.drivers.push("stephen");

alert(car1.drivers); //结果:Tom,Jerry,stephen

alert(car2.drivers); //结果:Tom,Jerry

alert(car1 instanceof Car); 该方法是把属性放在内部定义,把方法放在外边利用prototype进行定义。解决了第三种方法的问题。

这种方法其实应该来说非常友好了,但是比起java的语法来,应该有一些不和谐,感觉比较凌乱,对C++来说,我们就没有那么麻烦的感觉了,可是开发C++的研发人员一般情况下很少涉及javaScript,而对J2EE的研发人员来说,这种方式总有一些别扭。总感觉不是友好的封装,其实只不过是视觉上封装效果不是很好而已,要想达到视觉封装效果而又能达到这种方法的效果的也可以以,个人认为其实比较麻烦。那就是动态原型法。

5.动态原型

对于习惯使用其他语言的开发者来说,使用混合的构造函数/原型方式感觉不那么和谐。毕竟,定义类时,大多数面向对象语言都对属性和方法进行了视觉上的封装。考虑下面的C#类:

代码如下:

class Car //class

{

public string color = "red";

public int doors = 4;

public int mpg = 23;

public Car(string color, int doors, int mpg) //constructor

{

this.color = color;

this.doors = doors;

this.mpg = mpg;

}

public void showColor() //method

{

Console.WriteLine(this.color);

}

}

C#很好的打包了Car类的所有属性和方法,因此看见这段代码就知道它要实现什么功能,它定义了一个对象的信息。批评混合的构造函数/原型方式的人认为,在构造函数内存找属性,在其外部找方法的做法不合逻辑。因此,他们设计了动态原型方法,以提供更友好的编码风格。

动态原型方法的基本想法与混合的构造函数/原型方式相同,即在构造函数内定义非函数属性,而函数属性则利用原型属性定义。唯一的区别是赋予对象方法的位置。下面是用动态原型方法重写的Car类:

代码如下:

//定义

function Car() {

this.color = "red";

this.doors = 4;

this.drivers = new Array("Tom", "Jerry");

if (typeof Car._initialized == "undefined") {

Car.prototype.showColor = function() {

alert(this.color);

}

//............

}

//最后定义

Car._initialized = true;

} 直到检查typeof Car._initialized是否等于"undefined"之前,这个构造函数都未发生变化。这行代码是动态原型方法中最重要的部分。如果这个值未定义,构造函数将用原型方式继续定义对象的方法,然后把Car._initialized设置为true。如果这个值定义了(它的值为true时,typeof的值为Boolean),那么就不再创建该方法。简而言之,该方法使用标志(_initialized)来判断是否已给原型赋予了任何方法。该方法只创建并赋值一次,为取悦传统的OOP开发者,这段代码看起来更像其他语言中的类定义了。

6 混合工厂方式

这种方式通常是在不能应用前一种方式时的变通方法。它的目的是创建假构造函数,只返回另一种对象的新实例。这段代码看来与工厂函数非常相似:

代码如下:

function Car() {

var oTempCar = new Object();

oTempCar.color="red";

oTempCar.doors=4;

oTempCar.mpg=23;

oTempCar.showColor = function() {

alert(this.color);

}

return oTempCar;

}

与经典方式不同,这种方式使用new运算符,使它看起来像真正的构造函数:

var oCar = new Car();

由于在Car()构造函数内部调用了new运算符,所以将忽略第二个new运算符(位于构造函数之外)。在构造函数内部创建的对象被传递回变量var。这种方式在对象方法的内部管理方面与经典方式有着相同的问题。强烈建议:除非万不得已(请参阅第15章),还是避免使用这种方式。

总结:(采用哪种方式)

目前使用最广泛的是混合的构造函数/原型方式。此外,动态原型方法也很流行,在功能上与构造函数/原型方式等价。可以采用这两种方式中的任何一种。不过不要单独使用经典的构造函数或原型方式,因为这样会给代码引入问题。

代码如下:

//ps

//static class (1:function)

var CarCollection = new function() {

var _carCollection = new Array(); //global,private

this.Add = function(objCar) {

alert('Add');

}

this.Get = function(carid) {

alert('Get');

}

}

//static class (2:json)

var Car = {

color: 'red',

doors: 4,

showColor: function() { alert(this.color); }

}

Car.showColor();

js面向对象的几种方式

JavaScript中对象的创建有以下几种方式:

(1)使用内置对象

(2)使用JSON符号

(3)自定义对象构造

一、使用内置对象

JavaScript可用的内置对象可分为两种:

1,JavaScript语言原生对象(语言级对象),如String、Object、Function等;

2,JavaScript运行期的宿主对象(环境宿主级对象),如window、document、body等。

我们所说的使用内置对象,是指通过JavaScript语言原生对象的构造方法,实例化出一个新的对象。如:

复制代码 代码如下:

var str = new String("实例初始化String");

var str1 = "直接赋值的String";

var func = new Function("x","alert(x)");//示例初始化func

var o = new Object();//示例初始化一个Object

二、使用JSON符号

(i)何谓JSON ?

JSON (JavaScript Object

Notation)即JavaScript对象命名,是一种轻量级的数据交换格式,易于阅读和编写,同时也易于及其解析和生成。它基于

《JavaScript Programming Language, Standard ECMA-262 3rd Edition -

December 1999》的一个子集。JSON是完全于语言的文本格式,因此成为数据交换的理想格式。

JSON作为

JavaScript的一个自己,同时ActionScript、C、C#、ColdFusion、E、Java、JavaScript、ML、

ObjectiveCAML、Perl、PHP、Python、Rebol、Ruby、Lua等一系列的语言都提供支持,使得JSON成为Ajax开发的

首选方案。

JSON有两种构建方式,一种是采用简单的“键/值对”的集合,在不同的语言中被理解为对象、记录、结构、字典、哈希表、有键列表,或者关联数组等,另一种采用有序的值列表,大部分语言把它理解为数组。

常用的创建方式是第一种,即采用“键/值对”集合的形式。在这种形式下,一个对象以“{”(左括号)开始,“}”(右括号)结束。每个“名称”后跟一个“:”(冒号),“

‘键/值' 对”之间使用“,”(逗号)分隔。

JSON具有以下特点:(1)简单格式化的数据交换;(2)易于人们的读写习惯;(3)易于机器的分析和运行。

在JavaScript中,JSON被理解为对象。通过字符串形式的JSON,数据可以很方便地解析成JavaScript独享,并进行数据的读取传递。通过JSON,在一定程度上客服了JavaScript对象无法作为参数系列化传递的问题。

1,简单的JSON

{name:"刘德华",age:"25",sex:"男"}

2,JSON值的类型

JSON的值可以是简单的数据类型,例如数字、浮点、字符等,也可以是数组及对象。例如以数组作为member键值的JSON:

{member:[{name:"刘德华"},{name:"郭富城"},{name:"张学友"},{name:"黎明"}]}

{

book:[{name:"三国演义"},{name:"西游记"},{name:"水浒传"},{name:"红楼梦"}],

author:[{name:"罗贯中"},{name:"吴承恩"},{name:"施耐安",{name:"曹雪芹"}}]

}

3,在JavaScript中使用JSON

JSON是JavaScript原生格式,这意味着在JavaScript中处理JSON数据不需要任何特殊的API或者工具包,JavaScript默认将JSON当做一个对象处理。

将对象传递给一个变量,例如:

复制代码 代码如下:

var somebooks = {

book:[{name:"三国演义"},{name:"西游记"},{name:"水浒传"},{name:"红楼梦"}],

author:[{name:"罗贯中"},{name:"吴承恩"},{name:"施耐安",{name:"曹雪芹"}}]

}

JSON的每个“键”相当于对象的属性,例如访问book中的第一个条目,在JavaScript中,就可以简单地使用“somebooks.book[0].name”来获取“三国演义”这个值。

我们不但可以将一个JSON字符串转化为对象,反过来将一个对象“编译”为一个JSON字符串,以方便JavaScript中的对象的传输。例如:

复制代码 代码如下:

var Animals = new Object();

Animals.name = "dog";

Animals.sex = "Male";

Animals.age = "2";

Animals对象无法被序列化传输,将Animals对象转化为JSON字符串,也就是“{name:"dog",sex:"Male",age:"2"}”。这样,把该JSON字符串作为HTTP请求的一个参数传递,从而达到序列化传输Animals对象的目的。

(ii)JSON通过字符串形式来表达JavaScript的对象。如:

复制代码 代码如下:

var myObject = {nickname:"my girlfried",name:"big

pig"};

JSON

实际上充当了一种在JavaScript对象和字符串之间实现相互转换的协议。由于JSON的“外表”可以看成但村的字符串,因此JSON在

JavaScript的对象传输方面可以起到一定的作用。例如把对象strObject转换成字符串后进行传输,在达到目的地后通过eval方法将其还原

成对象:

复制代码 代码如下:

function test (o)

{

alert (o.name)

}

var strObject = '{nickname:"my girlfriend",name:"big pig"}';

test (eval_r("(" + strObject + ")"));

三、自定义对象构造

创建高级对象构造有两种方式:使用“this”关键字构造、使用原型prototype构造。如:

复制代码 代码如下:

//使用this关键字定义构造的上下文属性

function Girl()

{

this.name = "big pig";

this.age = 20;

this.standing;

this.bust;

this.waist;

this.hip;

}

//使用prototype

function Girl(){}

Girl.prototype.name = "big pig";

Girl.prototype.age = 20;

Girl.prototype.standing;

Girl.prototype.bust;

Girl.prototype.waist;

Girl.prototype.hip;

alert(new Girl().name);

上例中的两种定义在本质上没有区别,都是定义“Girl”对象的属性信息。“this”与“prototype”的区别主要在于属性访问的顺序。如:

复制代码 代码如下:

function Test()

{

this.text = function()

{

alert("defined by this");

}

}

Test.prototype.test = function()

{

alert("defined by prototype");

}

var _o = new Test();

_o.test();//输出“defined by this”

当访问对象的属性或者方法是,将按照搜索原型链prototype

chain的规则进行。首先查找自身的静态属性、方法,继而查找构造上下文的可访问属性、方法,最后查找构造的原型链。

“this”

与“prototype”定义的另一个不同点是属性的占用空间不同。使用“this”关键字,示例初始化时为每个实例开辟构造方法所包含的所有属性、方法

所需的空间,而使用“prototype”定义,由于“prototype”实际上是指向父级的一种引用,仅仅是个数据的副本,因此在初始化及存储上都比

“this”节约资源。

养宠指南还为您提供以下相关内容希望对您有帮助:

怎样编写可维护的面向对象JavaScript代码

尽管准确预测未来是不大可能,但是却完全可以将代码写灵活以备将来不时之需。Saner参数列表在设计参数列表的时候可以让代码有前瞻性。参数列表是让别人实现你代码的主要接触点,如果没有设计好的话,是会很有问题的。你应该避免下面这样的参...

Javascript面向对象编程

继承的实现 主要有 种方法 第一种是使用javascript本身的原型模型 通过给prototype赋值并改变其constructor属性来实现继承 第二种方法是不使用prototype 手动实现将父对象的所有属性方法深拷贝到子对象 比如A需要继承B 第一种写法...

如何用javascript面向对象编程

构造函数是另一个编写面向对象JavaScript代码的方法,当你需要初始化对象的属性、方法,或者需要创建多个属性、方法各不相同的实例时,它将是你最佳的选择。同样我们先从创建一个空对象开始:function Game() {};这个对象包括...

如何编写高质量JS代码(续)_javascript技巧

JavaScript是一门基于原型继承的语言,这意味着对象可以直接继承属性从其它的对象,该语言是无类别的。如果在一个函数前面带上new来调用,那么将得到一个隐藏连接到该函数的prototype成员的新对象,同时this也将会绑定到该新对象。new前缀也会...

求javascript仿面向对象编程实例代码(简单明了的,呵呵~)

//定义一个javascript类 function JsClass(privateParam/* */,publicParam){//构造函数 var priMember = privateParam; //私有变量 this.pubMember = publicParam; //公共变量 //定义私有方法 function priMethod(){ ret...

JavaScript定义类或函数的几种方式小结_js面向对象

我们看看JavaScript中定义类的各种方法。 1.工厂方式 javaScript中创建自己的类和对象,我们应该是必须掌握的,我们都知道javaScript中对象的属性可以在对象创建后动态定义,比如下面的代码: 代码如下: //定义 var oCar = new Object();...

js面向对象的几种方式

我们所说的使用内置对象,是指通过JavaScript语言原生对象的构造方法,实例化出一个新的对象。如:复制代码 代码如下:var str = new String("实例初始化String");var str1 = "直接赋值的String";var func = new Function...

如何理解并学习javascript中的面向对象

下面部分的代码,将是从目前十分流行的JSON数据格式以及javascript数组,来一步步像大家阐述javascript中的面向对象思想。&lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml...

...几种方式(工厂模式、构造函数模式、原型模式)_javascript技巧...

原型模式每个函数都有一个prototype属性,这个属性是一个指针,指向一个对象。而这个对象的用途是 包含可以由 特定类型 的所有 实例 共享的属性和方法。即调用构造函数所创建的那个对象的 原型对象好处是可以让所有对象的实例...

js对象的构造和继承实现代码

复制代码 代码如下: //定义js的user对象 function User(name,age){ this.name=name,this.age=age,this.getName=function(){ return this.name;},this.getAge=function(){ return this.age;} } //实例化一个对象 v...

上一篇:jquery动态加载select下拉框示例代码_jquery

下一篇:JS判断移动端访问设备并加载对应CSS样式_javascript技巧

Top