`
xj19891016
  • 浏览: 28782 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
文章分类
社区版块
存档分类
最新评论

面向对象的JavaScript

阅读更多
先来段代码:
<script>
//用面向对象的JavaScript表示课程及其安排
//'Lecture'类的构造函数
//名称和老师作为参数
function Lecture(name, teacher){
	this.name = name;
	this.teacher = teacher;
}
//'Lecture'类的一个方法
Lecture.prototype.display = function(){
	return this.teacher + "--教--" + this.name;
}

//'Schedule'类的构造函数
//以课程(Lecture)数组作为参数
function Schedule(lectures){
	this.lectures = lectures;
}
//'Schedule'类的一个方法
Schedule.prototype.display = function(){
	var str = "";
	//遍历每个课程(Lecture)
	for(var i = 0; i < this.lectures.length; i++){
		str += this.lectures[i].display() + "  ";
	}
	return str;
}

var mySchedule = new Schedule([
         new Lecture("数学","张三"),
         new Lecture("物理","李四"),
         new Lecture("化学","王五")]);
alert(mySchedule.display());
</script>


JavaScript语言中最重要的几个概念:引用(reference)、作用域(scope)、闭包(closure)、以及上下文(context)

1、引用
“引用”是一个指向对象实际位置的指针,与java中的引用非常相似,在此不累赘了。一个简单的例子
<script>
//多个变量引用同一个对象
//将obj置为空对象
var obj = new Object();
//obj与objref指向同一个对象
var objref = obj;
//修改obj的属性
obj.one = true;
//这个改变在两个对象中都反映出来
alert(obj.one == objref.one);
</script>

2、函数重载和类型检查
    函数重载:
    尽管函数重载特性在JavaScript中没有被直接支持,也有很多办法能够实现。
    函数重载必须依赖两件事情:判断传入参数数量的能力和判断传入参数类型的能力。我们先来看看参数数量。
    JavaScript每个函数都带有一个仅在这个函数范围内作用的变量称为arguments它是一个包含所有传给函数参数的伪数组,所以它不是一个真正的数组(你不能修改它,也不能用push()给它添加元素),但可以访问其中的元素,它也有.length属性。下面是函数重载的两个例子
//第一个例子
<script>
//发送一条消息的简单函数
function sendMessage(msg, obj){
	//如果消息和对象都被提供
	if(arguments.length == 2){
		//给对象发送消息
		obj.handleMsg(msg);
	}else{
		alert(msg);
	}
}
//仅用一个参数调用这个函数
sendMessage("Hello, World!");

//将一个我们自己写好的对象传入
sendMessage("你好!",{
		handleMsg : function(msg){
			alert("函数重载," + msg);
		}
	});
</script>
//第二个例子
<script>
//一个接受任意数量参数并将其转换为数组的函数
function makeArray(){
	var arr = [];
	//遍历传入的每个参数
	for(var i = 0; i<arguments.length; i++){
		arr.push(arguments[i]);
	}
	return arr;
}

function print(){
	var arr = makeArray(1,2,'好',4);
	for(var i = 0; i<arr.length; i++){
		alert(arr[i]);
	}
}

print();
</script>

    类型检查:typeof语句
<script>
function displayerror(msg){
	//检查并确认msg是否undefined
	if(typeof msg == 'undefined'){
		msg = "An error occurred.";
	}
	alert(msg);
}
displayerror();
displayerror(1)
</script>

    JavaScript是一个动态类型(弱类型)的语言,类型检查必然是个非常有用而且重要的话题。下面讨论两种特别有用的方法。
    第一种是使用typeof操作符。这个工具提供了一个字符串名称,用于表达变量内容的类型。当变量不是object或者array类型时,这应该算是最完美的解决方法了。但是对于自定义的对象,就不能用这个方法进行类型检查,因为它只会返回object,很难跟其他的object区分开来。
<script>
function User(){}
var u = new User();
alert(typeof u == "object");  //自定义的对象
var arr = [];
alert(typeof arr == "object");//数组
alert(typeof 2 == "number");
alert(typeof "2" == "string");
</script>

    第二种检查对象类型的方法,需要应用所有JavaScript对象都带有的一个属性,称为构造函数(constructor)。这一属性引用的是原本用来构造该对象的那个函数。下面是个例子
<script>
var num = 1;
alert(num.constructor == Number);
num = "22";
alert(num.constructor == String);
function User(){}
var user = new User();
alert(user.constructor == User);
var arr = [1,2,3,4];
if(arr.constructor == Array){
	alert(arr.join('-'));
}
</script>

<script>
//用来严格维护传入函数的所有参数的类型
//用一个变量类型列表严格检查一个参数列表
function strice(types, args){
	//保证类型的数量和参数的数量相匹配
	if(types.length != args.length){
		throw "长度不匹配," + types.length + " != " + args.length;
	}
	//变量所有的参数,检查他们的类型
	for(var i = 0; i < args.length; i++){
		if(args[i].constructor != types[i]){
			throw "有类型不匹配," + args[i] + "的类型是" + 
				  args[i].constructor + ",但要求的类型是" + types[i];
		}
	}
}

function userLiset(prefis, num, users){
	//保证prefix是字符串,num是数字,users是数组
	try{
		strice([String, Number, Array], arguments);
		//遍历num个用户
		for(var i = 0; i < num; i++){
			alert(prefis+" "+users[i]);
		}
	} catch (err){
		alert(err);
	}
}

userLiset("输出", 3, ["张三","李四","王五","找六"]);
userLiset("输出", 4, ["张三2","李四2","王五2","找六2"]);
userLiset("输出", "1", ["张三3","李四3","王五3","找六3"]);
</script>

3、作用域
    在JavaScript里,作用域是由函数划分的,而不是由块划分(比如while,if和for语句中间)的。这样导致的结果是某些代码不好理解。
<script>
//设置全局变量foo,并置为test
var foo = "test";
//在if块中
if (true){
	//将foo置为new test
	//注意:现在还在全局作用域中!
	var foo = "new test";
}
alert(foo == "new test"); //结果为true
//创建一个会修改变量foo的新函数
function test(){
	var foo = "old test";
}
//然而在调用时,foo只在函数作用域内起作用
test();
alert(foo == "new test"); //结果为true
</script>

    基于浏览器的JavaScript有一个有趣的特性,所有属于全局作用域的变量其实都是window对象的属性。尽管某些早期的Opera和Safari并非如此,但还是可以大致认为浏览器都遵循此规则。
<script>
//全局变量foo
var foo = "test";
alert(window.foo == "test"); //结果为true
</script>

    最后,让我们看看当变量缺乏声明是会是什么情况,看下面的例子。对变量foo的赋值是在函数test()的作用域中进行的,然而整个例子里并没有哪个作用域实际声明了这个变量。如果变量没有显示定义,他就是全局定义的,虽然它可能只在这个函数作用域的范围内使用。
<script>
function test(){
	foo = "test";
}
test();
//发现foo现在是在全局作用域下
alert(window.foo == "test"); //结果为true
</script>

4、闭包
    闭包(closure)意味着内层的函数可以引用存在于包围它的函数内的变量,即使外层函数的执行已经终止。先来看看闭包的两个简单例子。
<html>
<body>
<div id="div_1" style="width: 100px; height: 100px; background-color: red;"></div>
</body>
</html>
<script>
var obj = document.getElementById("div_1");
setTimeout(function(){
	obj.style.backgroundColor = "#42ee00";
},1000);

function delayedAlert(msg, time){
	setTimeout(function(){
		alert(msg);
	}, time);
}
delayedAlert("背景颜色在一秒前被修改", 2000);
</script>

<script>
//数字求和函数的函数生成器
function addGenerator(num){
	//返回一个简单的函数,求两个数字的和,其中第一个数字来自生成器
	return function(toAdd){
		return num + toAdd;
	};
}
//addFive现在包含一个接受单一参数的函数,这个函数能球的5加上该参数的和
var addFive = addGenerator(5);
alert(addFive(4));
</script>

    闭包还能解决另一个常见的JavaScript编写问题。JavaScript开发新手经常会留下大量多余的全局变量。而这通常被认为是一个坏习惯,应为这些多余的变量可能会悄悄的影响其他的库,导致怪异的问题出现。通过自执行的匿名函数你可以把所有原本属于全局的变量都隐藏起来,如
<script>
//创建一个新的匿名函数,作为包装
(function(){
	//变量原本应该是全局的
	var msg = "匿名函数例子";
	//将一个新的函数绑定到全局对象
	window.onunload = function(){
		//这个函数使用了"隐藏"的msg变量
		alert(msg);
	};

	//关闭匿名函数并执行之
})();
</script>

    使用闭包时会遇到一个问题。闭包允许你引用父函数中的变量,但提供的值并非该变量创建是的值,而是在父函数范围内的最终值。
5、上下文对象
    在JavaScript中,你的代码总是有一个上下文对象(代码处在该对象内)。
    上下文对象是通过this变量体现的,这个变量永远指向当前代码所处的对象中。
<script>
//在上下文对象内使用函数并将其上下文对象切换为另一个变量
var obj = {
	yes : function(){
		//this == obj
		this.val = true;
	},
	no : function(){
		this.val = false;
	}
};
//发现obj对象没有val属性
alert(obj.val == null);
//执行也yes函数后,将val属性与obj对象关联起来
obj.yes();
alert(obj.val == true);
//现在把window.no指向obj.no并执行
window.no = obj.no;
window.no();
//结果obj对象的val不变(因为no的上下文已经变为window对象了)
alert(obj.val == true);
alert(window.val == false);
</script>


<html>
<body>
<div id="div_1" style="width: 100px; height: 100px; background-color: red;">sssssssssssss</div>
</body>
</html>
<script>
function changeColor(color){
	this.style.backgroundColor = color;
}
//在window对象中调用此函数会失败,因为window对象没有style属性
//changeColor("white");

var obj = document.getElementById("div_1");
//使用call方法将它的颜色置为黑色。call方法将
//上下文对象置为第一个参数,并将其他参数作为
//原函数的参数
changeColor.call(obj,"black");
</script>

面向对象的基础
    JavaScript这门语言就是完全面向对象的。大多数人按功能编写代码,而不考虑任何上下文或组织。要完整理解如何编写最优秀的JavaScript代码,就必须理解JavaScript对象是如何工作的。两个创建对象并设置属性的例子
<script>
//创建一个新的object对象,存放在obj变量中
var obj = new Object();
//给此对象设置一些属性
obj.val = 5;
obj.click = function(){
	alert("hello");
};
//这是一段等价代码,用{...}简写方式,结合键值对(key/value pair)来定义
var obj2 = {
	//用键值对方式来设置属性和属性值
	val : 3,
	click : function(){
		alert("word");
	}
};

alert(obj.val);
obj.click();
alert(obj2.val);
obj2.click();
</script>

    和大部分的其他面向对象语言不同的是,JavaScript并没有类的概念。其他面向对象语言中你大多需要实例化某个具体类的实例,但JavaScript里不用。JavaScript里对象本身可以用来创建新对象,而对象也可以继承自其他对象。
    不管JavaScript使用何种对象方案,首先还是应该有一种创建新对象的方法的。JavaScript的做法是,任何函数都可以被实例化为一个对象。下面是一段代码,以了解它是如何运作的。
<script>
//一个简单的函数,接受名称并将其存入当前上下文中
function User(name){
	this.name = name;
}
//指定名称来创建该函数的一个新对象
var me = new User("My Name");
//可以看到,这个对象的名称被设为自身的name属性了
alert(me.name == "My Name");
//而且这是User对象的一个实例
alert(me.constructor == User);
//现在,既然User()不过是个函数
//如果只它作为函数来使用又如何呢?
User("test");
//因为它的'this'上下文对象未曾设定,
//所以默认为全局的'window'对象,也
//就是说window.name等于提供的这个名字
alert(window.name == "test");
</script>

    知道了如何创建简单对象了,是时候添加一些让对象更有用的东西了——上下文相关方法和属性。
    1.公共方法
    公共方法在对象的上下文中是最终用户始终可以接触到的。要实现这种在对象的每个实例中都可以使用的公共方法,必须了解一个叫prototype(原型)的属性,这个属性包含了一个对象,该对象可以作为所有新副本的基引用。本质上说,所有对象原型的属性都能在该对象的每个实例中找到。
    因为对象的原型仍然是对象,和其他任何对象一样,你也可以给它们添加新的属性。给原型添加属性的结果是由该原型实例化的每个对象都会获得这些属性,也就使这些属性公有化了。下面是一个这样的例子
<script>
//创建一个新的User构造函数
function User(name, age){
	this.name = name;
	this.age = age;
}
//将一个新的函数添加到此对象的prototype对象中
User.prototype.getName = function(){
	return this.name;
};
//并再给prototype对象添加一个函数
//注意期上下文是实例化后的对象
User.prototype.getAge = function(){
	return this.age;
};
//实例化一个新的User对象
var user = new User("张三", 18);
alert(user.getName());
alert(user.getAge());
</script>

    2、私有方法
    私有方法和私有变量只允许其他私有方法、私有变量和特权方法访问。
<script>
//只能由构造函数访问的私有方法例子
//表示教室的一个对象构造函数
function Classroom(students, teacher){
	//用于显示所有班上学生的私有方法
	function disp(){
		alert(students.join(","));
	}

	this.students = students;
	this.teacher = teacher;

	disp();
}
var class1 = new Classroom(["张三","李四"], "王五");
//调用disp方法会失败,因为它不是该对象的公共属性
//classl.disp();
</script>

下面是一个综合例子
<script type="text/javascript">
var Book = (function(){
	//私有静态属性
	var num = 0;
	//私有静态方法
	function checkIsbn(isbn){
		if(isbn !== 0){
			return false;
		}
		return true;
	}
	return function(isbn){
		var bn = 1;
		if(checkIsbn(isbn)){
			bn = isbn;
		}
		this.getBn = function(){
			return bn;
		}
		num++;
		if(num > 3){
			throw "此对象实例不能超过3个";
		}
	}
})();

try{
	var book1 = new Book(0);
	alert(book1.getBn());
	var book2 = new Book(1);
	alert(book2.getBn());
	var book3 = new Book(0);
	alert(book3.getBn());
	var book4 = new Book(0);
	alert(book4.getBn());
}catch(e){
	alert(e);
}
</script>

    上面例子中,Book的构造器从原来的普通函数变成了一个内嵌函数,并且被作为包含它的函数的返回值赋给变量Book,这就创建了一个闭包,你可以把静态的私有成员声明在里面。外层函数只是用于创建一个可以用来存放静态私有成员的闭包。
分享到:
评论

相关推荐

    面向对象JavaScript精要(英文原版pdf)

    ### 面向对象JavaScript精要 #### 一、书籍概览 本书《面向对象JavaScript精要》由Nicholas C. Zakas编写,是面向对象编程领域中的权威指南之一,尤其针对JavaScript这门语言。作者深入浅出地介绍了面向对象编程的...

    面向对象JavaScript开发

    面向对象JavaScript开发是现代Web开发中不可或缺的一部分,它使得JavaScript能够构建复杂、可维护的应用程序。 面向对象编程是一种基于对象和类的编程范式,它强调数据和操作数据的方法的封装。在JavaScript中,...

    面向对象javascript

    面向对象JavaScript教程 面向对象JavaScript是一种编程范式,它将JavaScript脚本编写转换为面向对象的思想。面向对象的JavaScript开发可以极大地提高开发效率和代码健壮性。 面向对象的JavaScript的特征包括: * ...

    面向对象Javascript核心支持代码分享

    JQury框架绝对是页面开发的首选,代码短小强悍,缺点就是... Javascript做面向对象开发的时候,总是会用到很多模拟面向对象特性的方法,这些方法就构成了支撑面向对象Javascript的核心代码,以下就是部分代码,其中参考

    [JavaScript] 面向对象 JavaScript 第2版 英文版

    [Packt Publishing] 面向对象 JavaScript 第2版 英文版 [Packt Publishing] Object Oriented JavaScript 2nd Edition E Book ☆ 图书概要:☆ Think in JavaScript Make object oriented programming ...

    面向对象javascript笔记

    面向对象的JavaScript编程是JavaScript开发中的重要概念,它允许我们以类和对象的...以上就是对"面向对象javascript笔记"所涵盖知识点的详细解析。理解并掌握这些概念对于深入理解和高效地编写JavaScript代码至关重要。

    javascript面向对象编程PDF

    良好的面向对象JavaScript代码的开发不仅包括编写清晰的代码,还包括构建一个健壮的测试环境。这是因为,对于经常使用或需要他人维护的代码,进行严格的测试和调试至关重要。Firebug等工具可以用于调试和性能分析,...

    Javascript 面向对象的JavaScript进阶

    ### JavaScript面向对象进阶知识点详解 #### 8.1 面向对象编程的基本特性 在探讨面向对象的JavaScript之前,我们首先需要了解面向对象编程(Object-Oriented Programming, OOP)的基本特性:封装性、抽象性、继承...

    编写可维护面向对象的JavaScript代码[翻译]

    维护面向对象JavaScript代码的要点包括: - 保持代码的简洁性和可读性,避免过长或复杂的类和方法。 - 合理利用继承来减少重复代码,但要避免过度继承导致的复杂性。 - 使用封装来隐藏实现细节,对外提供清晰的接口...

    Javascript面向对象编程.

    面向对象编程(Object-Oriented Programming,OOP)是编程的一种重要范式,JavaScript也完全支持这一特性,尽管它并非一种传统的静态类型语言。这篇博客文章可能详细讨论了如何在JavaScript中实现面向对象编程。 在...

    如何编写可维护的面向对象JavaScript代码

    发布于2012-5-7英文原文:能够写出可维护的面向对象JavaScript代码不仅可以节约金钱,还能让你很受欢迎。不信?有可能你自己或者其他什么人有一天会回来重用你的代码。如果能尽量让这个经历不那么痛苦,就可以节省...

    JavaScript面向对象编程指南.pdf

    JavaScript作为一门浏览器语言的核心思想;面向对象编程的基础知识及其在... 《JavaScript面向对象编程指南》着重介绍JavaScript在面向对象方面的特性,展示如何构建强健的、可维护的、功能强大的应用程序及程序库

    JavaScript面向对象编程指南

    《JavaScript面向对象编程指南》内容包括:JavaScript作为一门浏览器语言的核心思想;面向对象编程的基础知识及其在JavaScript中的运用;数据类型、操作符以及流程控制语句;函数、闭包、对象和原型等概念,以代码...

    JAVASCRIPT 面向对象编程精要

    ### JavaScript面向对象编程精要 #### 一、引言 JavaScript是一种灵活且强大的脚本语言,它虽然起源于一种简单的浏览器脚本语言,但随着时间的发展,JavaScript已经成为了一种功能全面的编程语言,尤其是在Web开发...

    基于JavaScript的面向对象可维护代码编写.pdf

    本文主要探讨如何编写可维护的面向对象JavaScript代码。面向对象编程是一种编程范式,它通过定义类和对象来描述现实世界中的实体。在JavaScript中,类是通过函数来定义的,而不是像其他语言那样通过类关键字来定义的...

Global site tag (gtag.js) - Google Analytics