IT技术博客大学习 共学习 共进步
全部 移动开发 后端 数据库 AI 算法 安全 DevOps 前端 设计 开发者

JavaScript中级笔记

Codyy技术团队 2009-10-20 22:45:54 累计浏览 4,587 次
本机暂存
JavaScript中级笔记(1)
忙了一段时间,不知道大家对我的JavaScript初级笔记评价怎么样。从今天开始,一起来学习JavaScript的高级部分。在 初级笔记中,我讲了一些JavaScript中常用的概念,把JavaScript最重要的DOM操作也讲解了。在中级笔记中,你将学习到 JavaScript的其它重要内容,比如说命名空间,闭包,面向对象,上下文,通用的JavaScript,分离代码等,这些都是很少有书籍提及到的内 容。大家对这块的只是都是一知半解,很模糊。相信大家都很期待,下面就开始JavaScript的中级之旅吧。
一,回顾
首先先来回顾下DOM和事件。
1,DOM
DOM在JavaScript中是应用最广泛的,大部分Web开发的编程语言都提供了相关的实现。给了开发者一个统一的接口。
看下面的例子:

<html>
<head>
<title>demo</title>
<meta http-equiv=”Content-Type” content=”text/html; charset=utf-8″ />
<script type=”text/javascript”>
/*
示例操作DOM元素
*/
window.onload = function(){
//给Dom元素添加颜色
var li = document.getElementsByTagName(”li”);
for(var i=0;i<li.length;i++){
li[i].style.color = “red”;
}
}
</script>
</head>
<body>
<ul>
<li>李老师-英语</li>
<li>张老师-数学</li>
<li>刘老师-物理</li>
</ul>
</body>
</html>

等待页面所有内容加载完毕后,通过getElementsByTagName()方法获取页面中的li元素,然后循环改变li元素颜色为红色。
再看第二个DOM例子,例子将把第二个li元素从页面中删除。

<html>
<head>
<title>demo</title>
<meta http-equiv=”Content-Type” content=”text/html; charset=utf-8″ />
<script type=”text/javascript”>
/*
示例操作DOM元素
*/
window.onload = function(){
//给Dom元素添加颜色
var li = document.getElementsByTagName(”li”);
for(var i=0;i<li.length;i++){
li[i].style.color = “red”;
}

//删除第二个li元素
var ul = document.getElementsByTagName(”ul”)[0]; //索引从0开始
ul.removeChild( li[1] ); //索引从0开始

}
</script>
</head>
<body>
<ul>
<li>李老师-英语</li>
<li>张老师-数学</li>
<li>刘老师-物理</li>
</ul>
</body>
</html>

现获取到li元素的父节点ul元素,然后使用removeChild() 方法删除ul元素下 指定的li元素。
当然也可以直接使用 parentNode来直接获取li元素的父节点。代码如下:

window.onload = function(){
//给Dom元素添加颜色
var li = document.getElementsByTagName(”li”);
for(var i=0;i<li.length;i++){
li[i].style.color = “red”;
}

//删除第二个li元素
//var ul = document.getElementsByTagName(”ul”)[0]; //索引从0开始
//ul.removeChild( li[1] ); //索引从0开始
li[1].parentNode.removeChild( li[1] ); //索引从0开始,直接使用parentNode来获取li元素的父节点
}

2,事件
事件是黏合应用程序中所有用户交互的胶水。DOM和事件的是JavaScript中的黄金搭档(呵呵,来句广告词),它们决定着现代Web应用程序形态的根本所在。
看下面的例子:

<html>
<head>
<title>demo</title>
<meta http-equiv=”Content-Type” content=”text/html; charset=utf-8″ />
<script type=”text/javascript”>
/*
示例操作DOM元素
*/
window.onload = function(){
//给Dom元素添加颜色
var li = document.getElementsByTagName(”li”);
for(var i=0;i<li.length;i++){
li[i].style.color = “red”;
li[i].onmouseover = function(){
this.style.color = “blue”;
}
li[i].onmouseout = function(){
this.style.color = “red”;
}

}
}
</script>
</head>
<body>
<ul>
<li>李老师-英语</li>
<li>张老师-数学</li>
<li>刘老师-物理</li>
</ul>
</body>
</html>

本例中,获取的li元素后,然后循环给元素添加事件,添加了onmouseover和onmouseout事件。当滑入时,改变颜色,滑出时,恢复颜色。
事件是复杂多变的,上例是一个最简单的例子,所以基本上没遇到问题。在以后,我们将遇到 比如 事件冒泡,事件传递 ,取消事件等问题。
3,DOM和事件
在DOM和事件交互的基础上产生了DHTML,它的实质就是JavaScript事件和DOM元素上CSS属性之间的交互。DHTML存在的意思就是组合这两个技术,然后做它的事情。
二,简单的面向对象开发
我们先来感受一下JavaScript面向对象是怎么一个写法。下面代码展示了学校中的课程名和老师的信息。

<script type=”text/javascript”>
/*
示例用一个对象组合表示学校中的课程
‘Lecture’类
用name和teacher作为参数
*/
function Lecture(name,teacher){
this.name=name;
this.teacher=teacher;
}
//‘Lecture’类的一个方法,用于生成一条信息
Lecture.prototype.display=function(){
return this.name + ” 是教 “+this.teacher +” 的。” ;
}
//下面用new来构造一个新的函数,然后调用display方法
var L = new Lecture(”李老师”,”英语”);
var L_msg = L.display();
alert(L_msg);
</script>

最终结果会输出“李老师 是教 英语 的。”
在此例子的基础上,我们再定义个函数,用来输出所有的课程信息。代码如下所示:

<script type=”text/javascript”>
/*
示例用一个对象组合表示学校中的课程
‘Lecture’类
用name和teacher作为参数
*/
function Lecture(name,teacher){
this.name=name;
this.teacher=teacher;
}
//‘Lecture’类的一个方法,用于生成一条信息
Lecture.prototype.display=function(){
return this.name + ” 是教 “+this.teacher +” 的。” ;
}
//下面用new来构造一个新的函数,然后调用display方法
var L = new Lecture(”李老师”,”英语”);
var L_msg = L.display();
//alert(L_msg);

//新定义一个’AllLecture’类
//用’lec’作为参数,lec是一个数组
function AllLecture( lec ){
this.lec = lec;
}
//‘AllLecture’类的一个方法,用于生成所有的课程信息
//需要循环输出‘lec’
AllLecture.prototype.display=function(){
var str = “”;
for(var i=0;i<this.lec.length;i++){
str += this.lec[i] + “\n”;
}
return str;
}
//下面使用new来够造一个新的函数,用于生成所有的信息
//函数的参数是数组。
//使用’Lecture’类来生成数组的值。
var B = new AllLecture( [ new Lecture("李老师","英语").display() , new Lecture("张老师","数学").display() , new Lecture("刘老师","物理").display() ] );
var B_str = B.display();
alert(B_str);
</script>

最终结果会输出:

原图已失效

本例中, 数组的值都调用了 display()方法。

改进如下:

AllLecture.prototype.display=function(){
var str = “”;
for(var i=0;i<this.lec.length;i++){
str += this.lec[i] + “\n”;
}
return str;
}

中的this.lec[i] 处,统一调用display()方法。然后去掉数组的值调用display()。修改后的代码如下:

<script type=”text/javascript”>
/*
示例用一个对象组合表示学校中的课程
‘Lecture’类
用name和teacher作为参数
*/
function Lecture(name,teacher){
this.name=name;
this.teacher=teacher;
}
//‘Lecture’类的一个方法,用于生成一条信息
Lecture.prototype.display=function(){
return this.name + ” 是教 “+this.teacher +” 的。” ;
}
//下面用new来构造一个新的函数,然后调用display方法
var L = new Lecture(”李老师”,”英语”);
var L_msg = L.display();
//alert(L_msg);

//新定义一个’AllLecture’类
//用’lec’作为参数,lec是一个数组
function AllLecture( lec ){
this.lec = lec;
}
//‘AllLecture’类的一个方法,用于生成所有的课程信息
//需要循环输出‘lec’
AllLecture.prototype.display=function(){
var str = “”;
for(var i=0;i<this.lec.length;i++){
//str += this.lec[i] + “\n”;
str += this.lec[i].display() + “\n”; //把display()放到这里调用

}
return str;
}
//下面使用new来够造一个新的函数,用于生成所有的信息
//函数的参数是数组。
//使用’Lecture’类来生成数组的值。
//var B = new AllLecture( [ new Lecture("李老师","英语").display() , new Lecture("张老师","数学").display() , new Lecture("刘老师","物理").display() ] );
var B = new AllLecture( [ new Lecture("李老师","英语") , new Lecture("张老师","数学") , new Lecture("刘老师","物理") ] );

var B_str = B.display();
alert(B_str);
</script>

同样也可以输出跟上例一样的结果。

这是一个简单的面向对象开发的例子,随着JavaScript逐渐被程序员所接受,设计良好的面向对象代码也日益普及。在后面的笔记中,你将会看到更多的面向对象程序代码。
三,小结
本章回顾了DOM和事件,然后通过例子简单的讲解了面向对象的开发。
JavaScript中级笔记(2)
对象是组成JavaScript的基本单元。本章将从JavaScript语言中最重要的几个部分开始介绍:引用,函数重载,作用域,闭包和上下文。有了这些知识后,面向对象开发就将变得简单。
1,引用
引用是一个指向对象实际位置的指针。看下面的使用引用的例子:
<script type=”text/javascript”>
/*示例引用*/
var obj = new Object(); //定义一个空对象
var newObj = obj; //定义一个新对象引用。
obj.name = “rain”;//修改原对象的属性
alert( newObj.name );
alert( obj.name == newObj.name  );//由此可以证明它们是引用的同一个对象
</script>

本例中,两个对象都指向同一个对象,当修改某一个对象的属性内容时,则会影响另一个。

我们再来看一个例子,这次我们利用数组来讲解引用:

<script type=”text/javascript”>
/*示例引用*/
var arr = new Array(”a”,”b”,”c”); //定义一个数组
var newArr = arr; //定义一个新数组的引用。
arr.push(”d”);//添加一个值
alert( newArr[3] );
alert( arr.length == newArr.length  );//由此可以证明它们是引用的同一个数组对象
</script>

如果在arr被重新定义后,则引用就不是同一个对象了,如下代码所示:

<script type=”text/javascript”>
/*示例引用*/
var arr = new Array(”a”,”b”,”c”); //定义一个数组
var newArr = arr; //定义一个新数组的引用。
arr = new Array(”e”,”f”); //重新定义一个数组
//newArr和arr现在指向不同的对象了
//arr指向的是new Array(”e”,”f”);
//newArr指向的是 new Array(”a”,”b”,”c”);

alert(arr!=newArr);
</script>

接下来我们来看一个比较特殊点的例子,关于字符串的引用问题。

<script type=”text/javascript”>
/*示例引用*/
var str = “a”;
var newStr = str;
str = str + “b”;//修改str的值,注意,这将会创建一个新对象,而非修改原对象
alert(str!=newStr);
</script>

正如本例所示,在执行字符串操作时,结果总会是一个新的字符串对象,而非字符串的修改版。
不知道大家看过<<JavaScript高级程序设计>>书中的有一节讲的是 传值和传址,说白了,就是引用。有兴趣可以去看看。
JavaScript就是一门通过维护一系列对其它对象的引用的语言,通过引用,可以给程序带来极大的灵活性。
2,函数重载
函数重载的特性就是根据传入的不同数量或类型的参数,通过重载函数来发挥不同的功能。它必须依赖2件事情:一是判断传入参数的数量 ,二是判断传入参数的类型。
2-1,判断传入参数的数量
JavaScript的每个函数都带有一个仅在这个函数范围内作用的变量称为参数,它是一个包含所有传给函数的参数的伪数组,虽然有length属性。
通过arguments,我们能够获取到这个伪数组。如下所示:

<script type=”text/javascript”>
//定义一个发送信息的简单函数
//obj为发送的对象,msg为发送的信息
function sendMsg( obj , msg ){
if(arguments.length==2){
alert(obj + ” 发送:” + msg);
}else{
alert(”参数数量不对,不能发送”);
}
}

//仅用一个参数时
sendMsg(”hello”);
//用2个参数时
sendMsg(”李老师”,”hello”);
</script>

arguments是一个非常有用的东西,在看下面的一个功能函数,它能将任意数量的参数转换为数组。

<script type=”text/javascript”>
function makeArr(){
var arr = [];//定义一个临时数组
for(var i=0;i<arguments.length;i++){
arr.push( arguments[i] );//添加值
}
return arr;//返回数组
}

var a = makeArr(”a”,”b”,3,4);
alert(a.length);
</script>

2-2,判断传入参数的类型

第一种判断类型的方式:

判断类型需要用到JavaScript中另一个操作符――typeof。  它用来表达变量内容的类型,返回的是字符串。比如如果一个变量是字符串,那么typeof后,则返回( “string” )。

经常我们会用到如下判断:

if( typeof num == “string” ){

num = parseInt( num );//如果是一个字符串,则把字符串解析出整数

}

if( typeof arr== “string” ){

arr= arr.split(”,”);//如果是一个字符串,则根据逗号来分割成数组

}

例如把前面的makeArr()函数改成只能接受字符串类型的参数,代码如下:

<script type=”text/javascript”>
function makeArr(){
var arr = [];//定义一个临时数组
for(var i=0;i<arguments.length;i++){
if(typeof arguments[i] !=”string”){ continue;};
arr.push( arguments[i] );//添加值
}
return arr;//返回数组
}

var a = makeArr(”a”,”b”,3,4);
alert(a.length);
</script>

最终结果 a.length 为2,因为后面2个参数是number 类型。

第二种判断类型的方式:
此方法需要引用所有JavaScript对象都带有的一个属性,构造函数――constructor。这一属性引用的是原本用来构造该对象的那个函数。

if( num.constructor ==  String ){

num = parseInt( num );//如果是一个字符串,则把字符串解析出整数

}

if( arr.constructor ==  String ){

arr= arr.split(”,”);//如果是一个字符串,则根据逗号来分割成数组

}

if(  newArr.constructor ==  Array ){

newArr = newArr.join(”,”);//如果是一个数组,则根据逗号来组成字符串

}

执行constructor后的结果是一个对象,而执行typeof后的结果是一个字符串。看下表的对比:

变量 typeof 变量 变量.constructor
{a:”b”} “object” Object
["a","b"] “object” Array
function(){} “function” Function
“a” “string” String
66 “number” Number
true “boolean” Boolean
new User() “object” User
通过对传入参数的数量和类型的判断,那么函数重载也就简单了。
JavaScript中级笔记(3)
接着(2)来讲。笔记(2)已经讲了引用和函数重载,接下来讲解作用域。
3,作用域
所有的面向对象的语言都有某种形式的作用域,JavaScript也不例外。在JavaScript里,作用域是由函数划分的,而不是由块(while,if之类的)来划分的。
我们先来看一个简单的作用域的例子。
<script type=”text/javascript”>
var foo = “a”; //设置全局变量foo
if(true){
var foo = “b”;//在if块中,把foo的值改为b,注意:此时还在全局作用域中
}
alert(foo);
</script>

在if块中,虽然foo的值改为“b“,但还是在全局作用域中,所以输出结果是“b“。

基于浏览器的JavaScript语言有一门有趣的特性是,所有属于全局作用域的变量都是window对象的属性。
看下面代码:

<script type=”text/javascript”>
var foo = “a”; //设置全局变量foo
if(true){
var foo = “b”;//在if块中,把foo的值改为b,注意:此时还在全局作用域中
}
alert(foo);
alert(”window的属性:”+window.foo);
alert(window.foo == foo);//true,证明全局变量和window属性一致
</script>


我们再上例的基础上,再添加一个函数来修改foo的值,代码如下:

<script type=”text/javascript”>
var foo = “a”; //设置全局变量foo
if(true){
var foo = “b”;//在if块中,把foo的值改为b,注意:此时还在全局作用域中
}
alert(foo);

//创建一个会修改foo变量的函数
function change(){
var foo = “c”;//修改foo的值
alert(”函数内部的值为:”+foo); //代码①
}
change();//然后调用时,foo只在函数作用域内起作用,所以下面输出的foo还是“b”
alert(”函数外部的值为:”+foo);  //代码②
</script>

结果也许有点另你意外,不过结果肯定是正确的。代码②的结果是输出 “b”,而不是”c”。原因就是作用域有关,虽然调用change()来改变foo的值,但是此时的改变只
在函数作用域内起作用,并不会改变全局作用域内的foo的值。
如果想在change()函数内修改全局的foo的值,我们可以去掉变量的声明,例如:

<script type=”text/javascript”>
var foo = “a”; //设置全局变量foo
if(true){
var foo = “b”;//在if块中,把foo的值改为b,注意:此时还在全局作用域中
}
alert(foo);

//创建一个会修改foo变量的函数
function change(){
// var foo = “c”;
foo = “c”;//修改foo的值,去掉var声明,

alert(”函数内部的值为:”+foo);
}
change();
alert(”函数外部的值为:”+foo);
</script>

在JavaScript中,如果变量没有显式定义,它就是全局定义的。所以调用change()后,会修改全局foo的值。最终输出”c” 。

4,上下文对象
在JavaScript中,代码总是有一个上下文对象,代码处于该对象之内。上下文对象是通过this变量来体现的。这个变量永远指向当前代码所处的对象中。
全局对象其实是window对象的属性。
接下来,我们看一个上下文对象的例子。
<script type=”text/javascript”>
//定义一个对象
var obj = {
show : function(){
this.display = “show”;
} ,
hide : function(){
this.display = “hide”;
}
}
alert(obj.display);//此时为undefined
obj.show();//执行show函数后,将display属性跟obj对象联系起来了
alert(obj.display);//”show”
</script>
再此基础上,我们再看一个例子:
<script type=”text/javascript”>
//定义一个对象
var obj = {
show : function(){
this.display = “show”;
} ,
hide : function(){
this.display = “hide”;
}
}
alert(obj.display);//此时为undefined
obj.show(); //执行show函数后,将display属性跟obj对象联系起来了
alert(obj.display);//”show”
window.hide = obj.hide;//把window.hide指向obj.hide
window.hide();//执行。hide的上下文对象是window对象了,所以this将指向window对象
alert(obj.display);//”show”。obj对象的display属性值不变,因为hide的上下文已经改变为window对象了
alert(window.display);//”hide”。 window对象的display属性被更新了

</script>

本例中,我们把obj.hide变量的上下文对象变为window对象时,代码写得并不好理解。幸运的是,JavaScript提供了一套更好的方法来解决。

现在我们有请call和apply两位先生上场,通过它们也可以完成同样的功能。先看call:
<script type=”text/javascript”>
//定义一个对象
var obj = {
show : function(){
this.display = “show”;
} ,
hide : function(){
this.display = “hide”;
}
}
alert(obj.display);//此时为undefined
obj.show(); //执行show函数后,将display属性跟obj对象联系起来了
alert(obj.display);//”show”
//window.hide = obj.hide;//把window.hide指向obj.hide
//window.hide();//执行。hide的上下文对象是window对象了,所以this将指向window对象
obj.hide.call( window );

alert(obj.display);//”show”。obj对象的display属性值不变,因为hide的上下文已经改变为window对象了
alert(window.display);//”hide”。 window对象的display属性被更新了
</script>
通过obj.hide.call(window),我们将此时的上下文对象改为window对象。call方法的第一个参数就是上下文对象。
call方法也可以传递更多的参数,如下所示:
<script type=”text/javascript”>
//定义一个对象
var obj = {
show : function(){
this.display = “show”;
} ,
hide : function(msg1,msg2){
this.display = msg1+” , “+msg2;
}
}
alert(obj.display);//此时为undefined
obj.show(); //执行show函数后,将display属性跟obj对象联系起来了
alert(obj.display);//”show”
//window.hide = obj.hide;//把window.hide指向obj.hide
//window.hide();//执行。hide的上下文对象是window对象了,所以this将指向window对象
obj.hide.call( window , “a” , “b” ); //传递3个参数,第一个是上下文对象,后面的是函数的参数
alert(obj.display);//”show”。obj对象的display属性值不变,因为hide的上下文已经改变为window对象了
alert(window.display);//”hide”。 window对象的display属性被更新了
</script>
另外apply方法跟call类型,它的第一个参数也是上下文对象,不过后面的参数则是一个数组。如下所示:
<script type=”text/javascript”>
//定义一个对象
var obj = {
show : function(){
this.display = “show”;
} ,
hide : function(msg1,msg2){
this.display = msg1+” , “+msg2;
}
}
alert(obj.display);//此时为undefined
obj.show(); //执行show函数后,将display属性跟obj对象联系起来了
alert(obj.display);//”show”
//window.hide = obj.hide;//把window.hide指向obj.hide
//window.hide();//执行。hide的上下文对象是window对象了,所以this将指向window对象
obj.hide.apply( window , ["a","b"] ); //后面的参数为数组
alert(obj.display);//”show”。obj对象的display属性值不变,因为hide的上下文已经改变为window对象了
alert(window.display);//”hide”。 window对象的display属性被更新了
</script>
最后我们来看一个通过上下文,call和apply结合的例子。
<html>
<head>
<title>demo</title>
<meta http-equiv=”Content-Type” content=”text/html; charset=utf-8″ />
<script type=”text/javascript”>
function changeColor(color){
this.style.color = color;
}
function setBodyColor(){
changeColor.apply( document.body , ["blue"]);
}
window.onload = function(){
//changeColor(”red”);//在window对象中调用此函数会失败,因为window对象没有style属性
var div = document.getElementById(”abc”);
changeColor.call(div , “red”);//把上下文改为div。从而this指向的是 id为abc的元素
//changeColor.apply(div , ["red"]);//把上下文改为div。从而this指向的是 id为abc的元素
setBodyColor();
}
</script>
</head>
<body>
<div id=”abc”>CssRain</div>
TestTest
</body>
</html>

在setBodyColor函数中,apply的第二个参数是数组,而前面我们讲过,arguments 也是一个伪数组,那么它们2个能联系起来吗?

把 changeColor.apply( document.body , ["blue"]); 改为  changeColor.apply( document.body , arguments );,
然后给setBodyColor();函数传参数。如下代码所示:
<html>
<head>
<title>demo</title>
<meta http-equiv=”Content-Type” content=”text/html; charset=utf-8″ />
<script type=”text/javascript”>
function changeColor(color){
this.style.color = color;
}
function setBodyColor(){
changeColor.apply( document.body , arguments);
}
window.onload = function(){
//changeColor(”red”);//在window对象中调用此函数会失败,因为window对象没有style属性
var div = document.getElementById(”abc”);
changeColor.call(div , “red”);//把上下文改为div。从而this指向的是 id为abc的元素
//changeColor.apply(div , ["red"]);//把上下文改为div。从而this指向的是 id为abc的元素
setBodyColor(”blue”);
}
</script>
</head>
<body>
<div id=”abc”>CssRain</div>
TestTest
</body>
</html>
通过这些例子,你也许对上下文的概念比较熟悉了。上下文在面向对象的编程中非常重要。
JavaScript中级笔记(4)
前面已经讲解了 引用,函数重载,作用域和上下文,接下来,讲解JavaScript中另一个重要的知识――闭包。
5,闭包


闭包意味着内层的函数可以引用存在于包围它的函数内的变量,即使外层函数的执行已经终止。
让我们先来看一个闭包的例子。

<script type=”text/javascript”>
function add(num){
return function(toAdd){
return num+toAdd; //代码①
}
}

var addFive = add(5); //此时addFive为function(toAdd){return num+toAdd;}
var count = addFive(3); //此时count为 num+toAdd
alert(count);//8
</script>

代码①是处于函数内层,不过它可以使用外层的变量num。

闭合还能解决另一个常见的Js问题,全局变量的影响。
通过自动执行匿名函数组合闭包,便可把原本属于全局的变量隐藏起来。看下面的例子:

<script type=”text/javascript”>
(function(){
var msg = “Hello”;
window.onunload  = function(){
alert(msg);//输出Hello
}
})()

//alert(msg);//出现未定义
</script>

在使用setTimeout时,我们经常也用上了闭包。

<html>
<head>
<title>demo</title>
<meta http-equiv=”Content-Type” content=”text/html; charset=utf-8″ />
<script type=”text/javascript”>
window.onload = function(){
var obj = document.getElementById(”abc”);
obj.style.border = “1px solid #000″;
setTimeout(function(){

obj.style.color = “red”;
},1000)

function DeAlert(msg , time){
setTimeout( function(){
alert(msg);
},time)
}
DeAlert(”hello”,2000);
}
</script>
</head>
<body>
<div id=”abc”>CssRain</div>
</body>
</html>

以这种方式使用setTimeout(),可以避免一些问题。

当然使用闭包 也会带来一些问题。如下代码所示:

<html xmlns=”http://www.w3.org/1999/xhtml”>
<head>
<title>demo</title>
<meta http-equiv=”Content-Type” content=”text/html; charset=utf-8″ />
<script type=”text/javascript”>
window.onload = function(){
var ul = document.getElementById(”abc”);
var li = document.getElementsByTagName(”li”);
for(var i=0;i<li.length;i++){
li[i].onclick = function(){
alert(”你单击的是第”+i+”个li。”);
}
}
}
</script>
</head>
<body>
<ul id=”abc”>
<li>AAA</li>
<li>BBB</li>
<li>CCC</li>
</ul>
</body>
</html>

单击li弹出的序号为 3 ,并不是正确的序号,它引用的值是最后一次的赋值。
我们可以使用下面代码来解决:

<script type=”text/javascript”>
window.onload = function(){
var ul = document.getElementById(”abc”);
var li = document.getElementsByTagName(”li”);
for(var i=0;i<li.length;i++){
(function(){  //使用一个自执行的匿名函数 来激发出作用域
var b = i ;    //记住在这个作用域内的值
li[b].onclick = function(){ //使用刚才记住的值,变量b
alert(”你单击的是第”+b+”个li。”);
}
})()
}
}
</script>

通过使用闭包对作用域的控制,从而符合了我们的要求。
上面的代码可以分解为:

<script type=”text/javascript”>
window.onload = function(){
var ul = document.getElementById(”abc”);
var li = document.getElementsByTagName(”li”);
function a(){
var b = 0 ;
li[b].onclick = function(){
alert(”你单击的是第”+b+”个li。”);
}
}
function b(){
var b = 1 ;
li[b].onclick = function(){
alert(”你单击的是第”+b+”个li。”);
}
}
function c(){
var b = 2 ;
li[b].onclick = function(){
alert(”你单击的是第”+b+”个li。”);
}
}
a();
b();
c();
}
</script>

闭包的概念不容易掌握,我也是花了大量时间和精力才理解。

6,小结
笔记(2),(3),(4)讲解了 JavaScript中的几个重要的内容,包括引用,函数重载,作用域,上下文对象和闭包。

引用的关键内容:         指针,数组引用,字符串引用,区别,传值,传址。
函数重载的关键内容:    参数的数量,参数的类型,arguments,伪数组,typeof,constructor,区别-字符串和对象。
作用域的关键内容:       函数划分,全局作用域,全局对象,window对象的属性,局部作用域,显式声明,隐式声明。
上下文对象的关键内容: this变量,call,apply,参数区别,数组。
闭包的关键内容:         内层函数,外层函数,变量,setTimeout,闭包问题,最后一次的赋值,闭包和作用域。

JavaScript中级笔记(5)
一,面向对象的基础
对象是JavaScript的基础。从最基本的层次上说,对象是一系列属性的集合。
1,对象的创建

<script type=”text/javascript”>
//创建一个新的Object对象,存放在obj变量中
var obj1 = new Object();
//设置属性
obj1.value = 5;
obj1.click = function(){
alert(”Hello”);
}

//另一种方式定义一个对象,以键值(key/value)的方式定义属性
var obj2 = {
value : 5,
click : function(){
alert(”Hello”);
}
};
</script>

相信很多朋友对这些创建对象的方式接触过很多次了,都很熟悉了。
2,对象的使用
和其他面向对象语言不同的是,JavaScript没有类的概念。在JavaScript里,任何函数都可以被实例化为一个对象。

<script type=”text/javascript”>
//一个简单的函数,接受名称并将其放入当前上下文中
function User(name){
this.name = name;
}

var me = new User(”cssrain”);//指定名称来创建该函数的一个新对象
alert( me.name );//”cssrain”
alert( me.constructor == User );//true

//如果把User当作函数
User(”peter”);
alert( window.name );//因为它的this上下文对象未设定,所以默认是全局的window对象
</script>

本段代码通过new User()来创建函数的一个新的对象。创建出的新对象拥有name属性,并且construtor属性指向创建它的函数。
3,公共方法
公共方法是在对象的上下文中用户始终可以接触到的。要实现这种方法,需要用到原型属性――prototype。
对象的原型仍然是对象。给原型对象添加属性后,由该原型实例化的每个对象都可以访问这些属性,即这些属性都是公有化的。

<script type=”text/javascript”>
//一个简单的函数,接受名称并将其放入当前上下文中
function User(name){
this.name = name;
}
//将一个新的函数添加到此对象的prototype对象中
User.prototype.getName = function(){
return this.name;
}

var me = new User(”cssrain”);//指定名称来创建该函数的一个新对象
alert( me.getName() ); //”cssrain”
</script>

4,私有方法

这个还比较好理解。字面意思是只能在内部访问。

<script type=”text/javascript”>
//一个简单的函数,接受名称并将其放入当前上下文中
function User(name){
this.name = name;
function disp(){
alert(”User()函数 私有的”);
}
//只能内部调用
disp();
}

var me = new User(”cssrain”);//指定名称来创建该函数的一个新对象
//me.disp();//不能调用
//disp();//不能调用
</script>

5,特权方法

它是以公共的方式访问私有变量。

<script type=”text/javascript”>
function User(name,age){
//私有变量
var year = (new Date()).getFullYear()-age;
//创建一个特权方法,能够访问year变量,同时属于公共可访问
this.getBornYear = function(){
return year;
}
}

var me = new User(”cssrain”,22);//指定参数来创建该函数的一个新对象
alert( me.getBornYear() );//”1986″
</script>

本质上,特权方式是动态生成的。因为它们是在运行时才添加到对象中的,而不是在代码第一次编译时就已经生成。

这种动态生成代码的能力不可小视,能根据与你想那个时变量来生成代码是非常有用的。看下面动态生成方法的例子:

<script type=”text/javascript”>
function User( users ){
for(var i in users){//遍历所有的属性
(function(method){
var p = i;
method["get"+p]=function(){//创建此属性的一个读取函数
return users[p];
}
method["set"+p]=function(val){//创建此属性的一个设置函数
users[p] = val;
}
})(this);
}
}

var me = new User({name : “cssrain”, age : 22});//指定参数来创建该函数的一个新对象
alert( me.getname() );//”cssrain”
alert( me.getage() );//”22″

me.setname(”changeCssRain”);
me.setage(23);
alert( me.getname() );//”changeCssRain”
alert( me.getage() );//”23″
</script>

6,静态方法

静态方法的实质跟一般函数没有什么不同,静态方法能保证对象的命名空间的整洁。

<script type=”text/javascript”>
function User(name,age){
this.name = name;
this.age = age;
}
//添加到一个User对象的静态方法
User.cloneUser = function(user){
//创建并返回一个新的User对象
return new User( user.name , user.age );
}

var u = User.cloneUser({name:”cssrian”,age:22});
alert(u.name);//”cssrain”
alert(u.age);//22
</script>

二,小结
理解本章所描述的概念和内容是非常重要的, 这是完全掌握专业JavaScript的起点。

相关文章:

  1. JavaScript函数调用规则
  2. ajax跨域请求问题解决方案
  3. 研究ext发现ajax跨域实现
  4. jQuery插件:Sexy Page Curls

    相关文章:

  1. JAVASCRIPT函数调用规则
  2. ajax跨域请求问题解决方案
  3. 研究ext发现ajax跨域实现
  4. jQuery插件:Sexy Page Curls

同分类推荐文章

  1. translateZ() (2026-06-25 21:18:56)
  2. translateY() (2026-06-25 21:17:56)
  3. translateX() (2026-06-25 21:16:01)

查看更多 前端 文章 →

建议继续学习

  1. 为什么python里要 if __name__ == ‘__main__’: (累计阅读 8,409)
  2. PHP Extension开发基础 (累计阅读 6,644)
  3. 通过使用Chrome的开发者工具来学习JavaScript (累计阅读 5,883)
  4. for 循环为何可恨? (累计阅读 5,487)
  5. 使用PHP创建一个面向对象的博客 (累计阅读 5,462)
  6. PHP API 框架开发的学习 (累计阅读 4,808)
  7. javascript的词法作用域 (累计阅读 4,691)
  8. python十分钟入门 (累计阅读 4,232)
  9. 闭包漫谈(从抽象代数及函数式编程角度) (累计阅读 3,854)
  10. 闭包与作用域 (累计阅读 3,800)