技术头条 - 一个快速在微博传播文章的方式     搜索本站
您现在的位置首页 --> JavaScript --> JavaScript中级笔记

JavaScript中级笔记

浏览:3474次  出处信息

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. 高性能web服务器-读书笔记    (阅读:6931)
  2. Unix高级环境编程系列笔记    (阅读:4558)
  3. MySQL 应用小笔记    (阅读:3512)
  4. Unix高级环境编程系列笔记    (阅读:3474)
  5. 《精通CSS+DIV》学习笔记    (阅读:3148)
  6. 读书笔记-交互设计精髓[1]    (阅读:2911)
  7. 《高性能网站建设指南》笔记    (阅读:2627)
  8. 读《Web 表单设计》    (阅读:2344)
  9. 《瞬间之美》读书笔记    (阅读:2104)
  10. 读书:《SEO实战密码》    (阅读:1884)
QQ技术交流群:445447336,欢迎加入!
扫一扫订阅我的微信号:IT技术博客大学习
© 2009 - 2024 by blogread.cn 微博:@IT技术博客大学习

京ICP备15002552号-1