javascript面向对象创建高级 Web 应用程序
目录JavaScript 函数是最棒的
构造函数而不是类
原型
静态属性和方法
闭包
模拟私有属性
从类继承
模拟命名空间
应当这样编写 JavaScript 代码吗?
展望
var userObject = new Object();
userObject.lastLoginTime = new Date();
alert(userObject.lastLoginTime);
的功能与下面的代码段完全相同:
var userObject = {}; // equivalent to new Object()
userObject[“lastLoginTime”] = new Date();
alert(userObject[“lastLoginTime”]);
我们还可以直接在 userObject 的定义中定义 lastLoginTime 属性,如下所示:
var userObject = { “lastLoginTime”: new Date() };
alert(userObject.lastLoginTime);
function func(x) {
alert(x);
}
func(“blah”);
这就是通常在 JavaScript 中定义函数的方法。但是,还可以按以下方法定义该函数,您在此创建匿名函数对象,并将它赋给变量 func
var func = function(x) {
alert(x);
};
func(“blah2”);
甚至也可以像下面这样,使用 Function 构造函数:
var func = new Function(“x”, “alert(x);”);
func(“blah3”);
function sayHi(x) {
alert(“Hi, “ + x + “!”);
}
sayHi.text = “Hello World!”;
sayHi[“text2”] = “Hello World... again.”;
alert(sayHi[“text”]); // displays “Hello World!”
alert(sayHi.text2); // displays “Hello World... again.”
Figure 1 JavaScript 中的函数是最棒的// assign an anonymous function to a variable
var greet = function(x) {
alert(“Hello, “ + x);
};
greet(“MSDN readers”); // passing a function as an argument to another
function square(x) {
return x * x;
}
function operateOn(num, func) {
return func(num);
}
// displays 256
alert(operateOn(16, square)); // functions as return values
function makeIncrementer() {
return function(x) { return x + 1; };
}
var inc = makeIncrementer();
// displays 8
alert(inc(7)); // functions stored as array elements
var arr = [];
arr[0] = function(x) { return x * x; };
arr[1] = arr[0](2);
arr[2] = arr[0](arr[1]);
arr[3] = arr[0](arr[2]);
// displays 256
alert(arr[3]); // functions as object properties
var obj = { “toString” : function() { return “This is an object.”; } };
// calls obj.toString()
alert(obj);
var myDog = {
“name” : “Spot”,
“bark” : function() { alert(“Woof!”); },
“displayFullName” : function() {
alert(this.name + “ The Alpha Dog”);
},
“chaseMrPostman” : function() {
// implementation beyond the scope of this article
}
};
myDog.displayFullName();
myDog.bark(); // Woof!
Figure 2 “this”随对象更改而更改function displayQuote() {
// the value of “this” will change; depends on
// which object it is called through
alert(this.memorableQuote);
}
var williamShakespeare = {
“memorableQuote”: “It is a wise father that knows his own child.”,
“sayIt” : displayQuote
};
var markTwain = {
“memorableQuote”: “Golf is a good walk spoiled.”,
“sayIt” : displayQuote
};
var oscarWilde = {
“memorableQuote”: “True friends stab you in the front.”
// we can call the function displayQuote
// as a method of oscarWilde without assigning it
// as oscarWilde’s method.
//”sayIt” : displayQuote
};
williamShakespeare.sayIt(); // true, true
markTwain.sayIt(); // he didn’t know where to play golf
// watch this, each function has a method call()
// that allows the function to be called as a
// method of the object passed to call() as an
// argument.
// this line below is equivalent to assigning
// displayQuote to sayIt, and calling oscarWilde.sayIt().
displayQuote.call(oscarWilde); // ouch!
alert(“NaN is NaN: “ + isNaN(NaN));
function x() {
this.isNaN = function() {
return “not anymore!”;
};
}
// alert!!! trampling the Global object!!!
x();
alert(“NaN is NaN: “ + isNaN(NaN));
Dog spot = new Dog();
将返回一个对象,该对象是 Dog 类的实例。但在 JavaScript 中,本来就没有类。与访问类最近似的方法是定义构造函数,如下所示:
function DogConstructor(name) {
this.name = name;
this.respondTo = function(name) {
if(this.name == name) {
alert(“Woof”);
}
};
}
var spot = new DogConstructor(“Spot”);
spot.respondTo(“Rover”); // nope
spot.respondTo(“Spot”); // yeah!
那么,结果会怎样呢?暂时忽略 DogConstructor 函数定义,看一看这一行:
var spot = new DogConstructor(“Spot”);
// create an empty object
var spot = {};
// call the function as a method of the empty object
DogConstructor.call(spot, “Spot”);
正如在 DogConstructor 主体中看到的那样,调用此函数将初始化对象,在调用期间关键字“this”将引用此对象。这样,就可以为对象创建模板!只要需要创建类似的对象,就可以与构造函数一起调用“new”,返回的结果将是一个完全初始化的对象。这与类非常相似,不是吗?实际上,在 JavaScript 中构造函数的名称通常就是所模拟的类的名称,因此在上面的示例中,可以直接命名构造函数 Dog:
// Think of this as class Dog
function Dog(name) {
// instance variable
this.name = name;
// instance method? Hmmm...
this.respondTo = function(name) {
if(this.name == name) {
alert(“Woof”);
}
};
} var spot = new Dog(“Spot”);
function respondTo() {
// respondTo definition
}
function Dog(name) {
this.name = name;
// attached this function as a method of the object
this.respondTo = respondTo;
}
var buddy = new Dog(“Buddy“);
buddy 所引用的对象将从它的原型继承属性和方法,尽管仅从这一行可能无法明确判断原型来自哪里。对象 buddy 的原型来自构造函数(在这里是函数 Dog)的属性。
Figure 4 对象具有其原型的属性var spot = new Dog(“Spot”); // Dog.prototype is the prototype of spot
alert(Dog.prototype.isPrototypeOf(spot)); // spot inherits the constructor property
// from Dog.prototype
alert(spot.constructor == Dog.prototype.constructor);
alert(spot.constructor == Dog); // But constructor property doesn’t belong
// to spot. The line below displays “false”
alert(spot.hasOwnProperty(“constructor”)); // The constructor property belongs to Dog.prototype
// The line below displays “true”
alert(Dog.prototype.hasOwnProperty(“constructor”));
Dog.prototype = new Object();
- 继承原型对象的对象上可以立即呈现对原型所做的更改,即使是在创建这些对象之后。
- 如果在对象中定义了属性/方法 X,则该对象的原型中将隐藏同名的属性/方法。例如,通过在 Dog.prototype 中定义 toString 方法,可以改写 Object.prototype 的 toString 方法。
- 更改只沿一个方向传递,即从原型到它的派生对象,但不能沿相反方向传递。
Figure 7 继承原型function GreatDane() { }
var rover = new GreatDane();
var spot = new GreatDane();
GreatDane.prototype.getBreed = function() {
return “Great Dane”;
};
// Works, even though at this point
// rover and spot are already created.
alert(rover.getBreed());
// this hides getBreed() in GreatDane.prototype
spot.getBreed = function() {
return “Little Great Dane”;
};
alert(spot.getBreed());
// but of course, the change to getBreed
// doesn’t propagate back to GreatDane.prototype
// and other objects inheriting from it,
// it only happens in the spot object
alert(rover.getBreed());
function DateTime() { }
// set static method now()
DateTime.now = function() {
return new Date();
};
alert(DateTime.now());
Figure 8 根据谓词筛选元素function filter(pred, arr) {
var len = arr.length;
var filtered = []; // shorter version of new Array();
// iterate through every element in the array...
for(var i = 0; i < len; i++) {
var val = arr[i];
// if the element satisfies the predicate let it through
if(pred(val)) {
filtered.push(val);
}
}
return filtered;
}
var someRandomNumbers = [12, 32, 1, 3, 2, 2, 234, 236, 632,7, 8];
var numbersGreaterThan100 = filter(
function(x) { return (x > 100) ? true : false; },
someRandomNumbers);
// displays 234, 236, 632
alert(numbersGreaterThan100);
var greaterThan300 = filter(
function(x) { return (x > 300) ? true : false; },
someRandomNumbers);
function makeGreaterThanPredicate(lowerBound) {
return function(numberToCheck) {
return (numberToCheck > lowerBound) ? true : false;
};
}
这样,您就可以编写以下代码:
var greaterThan10 = makeGreaterThanPredicate(10);
var greaterThan100 = makeGreaterThanPredicate(100);
alert(filter(greaterThan10, someRandomNumbers));
alert(filter(greaterThan100, someRandomNumbers));
function Person(name, age) {
this.getName = function() { return name; };
this.setName = function(newName) { name = newName; };
this.getAge = function() { return age; };
this.setAge = function(newAge) { age = newAge; };
}
var ray = new Person(“Ray”, 31);
alert(ray.getName());
alert(ray.getAge());
ray.setName(“Younger Ray”);
// Instant rejuvenation!
ray.setAge(22);
alert(ray.getName() + “ is now “ + ray.getAge() +
“ years old.”);
function Person(name, age) {
var occupation;
this.getOccupation = function() { return occupation; };
this.setOccupation = function(newOcc) { occupation =
newOcc; };
// accessors for name and age
}
注意,这些私有成员与我们期望从 C# 中产生的私有成员略有不同。在 C# 中,类的公用方法可以访问它的私有成员。但在 JavaScript 中,只能通过在其闭包内拥有这些私有成员的方法来访问私有成员(由于这些方法不同于普通的公用方法,它们通常被称为特权方法)。因此,在 Person 的公用方法中,仍然必须通过私有成员的特权访问器方法才能访问私有成员:
Person.prototype.somePublicMethod = function() {
// doesn’t work!
// alert(this.name);
// this one below works
alert(this.getName());
};
// class Pet
function Pet(name) {
this.getName = function() { return name; };
this.setName = function(newName) { name = newName; };
} Pet.prototype.toString = function() {
return “This pet’s name is: “ + this.getName();
};
// end of class Pet var parrotty = new Pet(“Parrotty the Parrot”);
alert(parrotty);
Figure 10 从 Pet 类派生// class Dog : Pet
// public Dog(string name, string breed)
function Dog(name, breed) {
// think Dog : base(name)
Pet.call(this, name);
this.getBreed = function() { return breed; };
// Breed doesn’t change, obviously! It’s read only.
// this.setBreed = function(newBreed) { name = newName; };
} // this makes Dog.prototype inherits
// from Pet.prototype
Dog.prototype = new Pet(); // remember that Pet.prototype.constructor
// points to Pet. We want our Dog instances’
// constructor to point to Dog.
Dog.prototype.constructor = Dog; // Now we override Pet.prototype.toString
Dog.prototype.toString = function() {
return “This dog’s name is: “ + this.getName() +
“, and its breed is: “ + this.getBreed();
};
// end of class Dog var dog = new Dog(“Buddy”, “Great Dane”);
// test the new toString()
alert(dog); // Testing instanceof (similar to the is operator)
// (dog is Dog)? yes
alert(dog instanceof Dog);
// (dog is Pet)? yes
alert(dog instanceof Pet);
// (dog is Object)? yes
alert(dog instanceof Object);
var MSDNMagNS = {};
MSDNMagNS.Pet = function(name) { // code here };
MSDNMagNS.Pet.prototype.toString = function() { // code };
var pet = new MSDNMagNS.Pet(“Yammer”);
var MSDNMagNS = {};
// nested namespace “Examples”
MSDNMagNS.Examples = {};
MSDNMagNS.Examples.Pet = function(name) { // code };
MSDNMagNS.Examples.Pet.prototype.toString = function() { // code };
var pet = new MSDNMagNS.Examples.Pet(“Yammer”);
可以想象,键入这些冗长的嵌套命名空间会让人很累。 幸运的是,库用户可以很容易地为命名空间指定更短的别名:
// MSDNMagNS.Examples and Pet definition... // think “using Eg = MSDNMagNS.Examples;”
var Eg = MSDNMagNS.Examples;
var pet = new Eg.Pet(“Yammer”);
alert(pet);
function object(o) {
function F() {}
F.prototype = o;
return new F();
}
然后,由于 JavaScript 中的对象是可延展的,因此可以方便地在创建对象之后,根据需要用新字段和新方法增大对象。
MyNamespace.MyClass = function() {
MyNamespace.MyClass.initializeBase(this);
this._myProperty = null;
}
Then, you need to define the class members itself in its prototype:
MyNamespace.MyClass.prototype = {
get_myProperty: function() { return this._myProperty;},
set_myProperty: function(value) { this._myProperty = value; },
doSomething: function() {
MyNamespace.MyClass.callBaseMethod(this, “doSomething”);
/* do something more */
}
}
最终注册类:
MyNamespace.MyClass.registerClass(
“MyNamespace.MyClass “, MyNamespace.BaseClass);
此处不需要管理构造函数和原型层次结构,因为这由 registerClass 函数自动完成的。
javascript面向对象创建高级 Web 应用程序的更多相关文章
- 使用面向对象技术创建高级 Web 应用程序
作者: 出处: 使用面向对象技术创建高级 Web 应用程序 来源:开源中国社区 作者:oschina 最近,我面试了一位具有5年Web应用开发经验的软件开发人员.她有4年半的JavaScript编程经 ...
- 【JavaScript】使用面向对象的技术创建高级 Web 应用程序
本文讨论: JavaScript 是基于原型的语言 用 JavaScript 进行面向对象的编程 JavaScript 编码技巧 JavaScript 的未来 本文使用了以下技术: JavaScrip ...
- Jmeter(五) - 从入门到精通 - 创建网络计划实战和创建高级Web测试计划(详解教程)
1.简介 上一篇中宏哥已经将其的理论知识介绍了一下,这一篇宏哥就带着大家一步一步的把上一篇介绍的理论知识实践一下,然后再说一下如何创建高级web测试计划. 2.网络计划实战 通过上一篇的学习,宏哥将其 ...
- jQuery Mobile 是创建移动 web 应用程序的框架。
jQuery Mobile jQuery Mobile 是创建移动 web 应用程序的框架. jQuery Mobile 适用于所有流行的智能手机和平板电脑. jQuery Mobile 使用 HTM ...
- 002.Create a web API with ASP.NET Core MVC and Visual Studio for Windows -- 【在windows上用vs与asp.net core mvc 创建一个 web api 程序】
Create a web API with ASP.NET Core MVC and Visual Studio for Windows 在windows上用vs与asp.net core mvc 创 ...
- IDEA 2017.3 新版本中创建 JSF Web 应用程序缺少 web.xml 的解决办法
IDEA 2017.3 新版本中默认创建一个 Web 应用程序很可能不会自动创建 web.xml 文件.虽然说从 JavaEE 6.0 开始 Servlet 3.0 规范中就新增了一些注解可以免去传统 ...
- IIS首次发布VS2012创建的web应用程序时注册.net4.0
最近用VS2012创建的web应用程序,.net环境设置成了4.0,在用IIS发布的时候发现需要注册下.net4.0才能配置应用程序. 首先确保配置的电脑上已经安装了.net4,找到.net4所在文件 ...
- JavaScript 面向对象(三) —— 高级篇
JavaScript 面向对象(一) —— 基础篇 JavaScript 面向对象(二) —— 案例篇 一.json方式的面向对象 首先要知道,js中出现的东西都能够放到json中.关于json数据格 ...
- 用JavaScript 来创建 mac os x 程序这样是否好
在网上看到的文章: 用 JavaScript 编写 OS X 应用 (Tyler Gaw) 这个文章的内容是不错的. 可是思路呢? 我们假设想学一种方法或工具,这样做好吗? 我看了上面的代码.假设 ...
随机推荐
- PHP PDO select语句结果行数计算
PDO有一个函数PDOStatement::rowCount返回上一个SQL语句影响的行数. rowCount函数对于DELETE, INSERT, 或者UPDATE语句的结果是正确的,但对于sele ...
- linux(ubuntu) 遇到的问题 --1
1.使用sudo提示用户不在sudoers文件中的解决方法 切换到root用户 su root 查看/etc/sudoers文件权限,如果只读权限,修改为可写权限 [root@localhost ~] ...
- SubLime2 win + mac keygen
参考 http://www.cnblogs.com/snandy/archive/2013/05/08/3068059.html http://www.freebuf.com/tools/6434.h ...
- MVC-06 安装部署
部署网站往往是一件麻烦事,因为在安装部署的过程中,经常有许多步骤要运行,对于许多不太熟悉IIS/SQL的新手来说,部署网站编程一件非常困难且危险的事.Visual Studio 2012在ASP.NE ...
- XMLTProcessor根据XSLT样式规则将节点转换为document对象
最近使用Firefox进行网页的调试,发现有些javascript XSLT处理xml的语句仅仅支持IE浏览器.而网络中的一些介绍Javascript XSLT 处理XML的文章基本上都是依据Ajax ...
- hdoj 2896 病毒侵袭(AC自动机)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2896 思路分析:题目为模式匹配问题,对于一个给定的字符串,判断能匹配多少个模式:该问题需要静态建树,另 ...
- installation - How to install Synaptic Package Manager? - Ask Ubuntu
installation - How to install Synaptic Package Manager? - Ask Ubuntu How to install Synaptic Package ...
- 如何判断一个变量是数组Array类型
在很多时候,我们都需要对一个变量进行数组类型的判断.JavaScript中如何判断一个变量是数组Array类型呢?我最近研究了一下,并分享给大家,希望能对大家有所帮助. JavaScript中检测对象 ...
- C++ Primer的课后规划问题的第八章
1.写通常需要一个参数(字符串的地址).字符串和打印功能. 只要.假设提供了第二个参数(int种类),而这个参数不0,的次数的函数打印串数量为该功能将被称为(意,字符串的打印次数不等于第二个參数的值. ...
- [译]Stairway to Integration Services Level 14 - 项目转换(SSIS 2008 ~ SSIS 2012)
介绍 本文中我们会用SSDT把第一个SSIS项目转换为 SSIS 2012, 为什么要升级到2012? 你可能想使用SSIS 2012新的特性. 又或者想使用 SSIS 2012 Catalog. 想 ...