找回密码
 注册
搜索
热搜: 超星 读书 找书
查看: 2392|回复: 1

[【原创】] javascript的N问--经验体会

[复制链接]
发表于 2007-9-3 09:09:02 | 显示全部楼层 |阅读模式
1.javascript文件的后缀
一般将单独的javascript文件保存为*.js,但后缀名js并不是必须的。有事希望外部javascript是动态生成的,那么该文件甚至可以保存为asp或者其他文件格式,只要他能够生成需要的javascript代码就行,例如:
<script type=\"text/javascript\" src=\"xx.asp?s=test\"></script>
就是将xx.asp?s=test这个asp文件生成的javascript代码包含到html文件中。
2.<script>标记的应该放在哪里?
为了是javascript能够在页面中运行,需要把<script>标记嵌入到html代码中。html推荐将<script>标记放在<head></head>标记之间,实际上也可以放在其他地方,这取决于我们的习惯和具体程序的要求。浏览器执行html页面的过程,是自上而下的线性过程,<script>标记同样是作为这个线性执行过程的一部分,知道载入完这个标记时才会被执行。
3.浏览器怎样执行外部javascript文件?
当浏览器执行到包括src属性的<script>标记时,就会向服务器请求载入这个外部文件,同时浏览器还将继续下面的代码的解析。当外部文件载入完成后,浏览器会立即执行其中的代码,两者是一个并发执行的过程。
4.编码问题
在使用外部javascript文件时需要注意的一点是编码问题。外部文件实现的原理是:浏览器把外部文件的内容全部复制到当前的页面中执行。这个复制过程是一个二进制的复制,因此当html页面的编码和js文件的编码不一致或者不兼容时,就会产生问题--页面出现乱码或者代码完全不能执行。解决这个问题的方法之一是使两者统一编码。另一个解决办法是使用<script>标记的charset属性,这个属性指定了外部文件的编码方式,从而使外部文件和html文件可以使用不同的编码。例如:
<script type=\"text/javascript\" src=\"xx.js\" charset=\"gb2312\"></script>
5.变量声明问题
可以通过var关键字来声明一个变量,声明语句可以出现在任何地方,但一定要在使用该变量之前。在javscript中重复声明一个变量也是可行的,这并不会产生语法错误或者运行错误,但会造成之前声明变量值的丢失。
6.可选的分号?
每条语句的结尾使用英文的分号(若用中文的分号,会产生语法错误)来表示语句的结束。有时候可以省略分号,因为解释器通常能正确识别javascript语句并执行。注意我在这里的措辞!通常能正确识别不代表一定可以正确识别。所以,我的建议是给每条语句加上个分号!这可以保证程序有良好的结构而且可以避免一些不可预知的错误。(注意:当一条语句的结尾是一个表示函数体结束的右大括号的时候,省略分号)
7.或操作符的另类用途
javascript一次获取每个操作数,将他们转换为布尔变量,如果是true,则直接返回这个操作数的值,终端后面操作数的处理;否则继续下一个操作数。如果最后一个操作数对应布尔变量false,则返回这个操作数的值。下面的带面演示其执行原理:
var !![/url]<font color=#ff0000>谢绝广告帖!再发封ID!</font>\"chinazk\" || \"52chinazk\";

alert(a); //a的值是\"chinazk\"
var b=false || 0;
alert(b); //b的值是0
8.应该在那里定义函数?
函数定义的位置并没有任何限制,他可以出现在代码中的任何一个位置。即使将函数调用语句写在函数定义之前,解释器也能正确找到这个函数并调用他。
9.函数可否嵌套定义?
函数可以嵌套定义,即一个函数内部可以定义另外一个函数,但这个内部函数只能在其外部函数的范围内被调用。
10.命名冲突的处理
因为一个全局变量可以用在函数内部,而函数内部又可以定义局部变量,如果两者的变量名相同,那么javascript解释器如何处理?当命名冲突发生时,函数内部优先使用局部变量,对局部变量的操作不会影响到全局变量。
11.怎样使用多维数组?
多维数组并不是javascript中的一种内部机制,而是Aray对象性质的一种应用。这个应用基于javascript中变量的无类型性。一个数组元素可以存储任意类型的数据,当一个数组的元素是另一个数组时,就表现为了一个二维或者多维的数组(注:数组下标的计算顺序是从左到右)。下面的例子定义了一个4乘以4的二维数组,代码如下:
var arr=new Array(4);
for (var i=0;i<4;i++) {
  arr=new Array(4);
}
也可以使用数组常量的语法来定义一个多维数组,例如下面的代码定义了包括1到9的3乘以3的二维数组:
var arr=[[1,2,3],[4,5,6],[7,8,9]];
12.Array对象的length属性是可变的
Array对象的length属性是可变的,这一点需要特别注意。当length属性被设置得更大时,整个数组的元素值并不会丢失,仅仅是length属性变大;当length属性被设置得比原来小时,则原来数组中超过length的元素的值会丢失。
13.中文字符串的长度
String对象的length属性计算的是unicode字符的个数,所以一个中文单字和一个英文字母的长度都是1.
14.怎样定义类?
一个类表示了具有相似性质的一类事物的抽象,通过实例化一个类,可以获得属于属于该类的一个实例,即对象。在javascript中定义一个类的方法如下:
function class1() {
//类成员的定义及构造函数
}
这里的class1既是一个函数也是一个类。我们一般称其为类的构造函数,负责初始化工作。

15.怎样获得一个类的实例?
我们可以用new操作符来获得一个类的实例:
function class1() {
//类成员的定义及构造函数
}
var obj1=new class1();
抛开类的概念,从代码的形式上来看,class1就是一个函数。那么是不是所有的函数都可以用new来操作呢?是的,在javascript中,函数和类是一个概念。当对一个函数进行new操作时,就会返回一个对象。如果这个函数没有初始化类成员,那就会返回一个空的对象。例如:
function hello() {
alert(\"hell0\");
}
var obj=new hello();
alert(obj);
16.同一个类的成员之间怎样引用?
在一个类的成员之间相互引用,必须通过this指针来进行。在javascript中每个属性和方法都是独立的,他们通过this指针联系在一个对象上。
17.怎么给事件传递参数?
事件处理程序不能传递参数是系统内部对象的事件机制存在的问题。因为事件机制仅传递一个函数的名称,不带有任何参数的信息,所以无法传递参数进去。那怎样解决这个问题呢?我们采用反向的思维方式,不考虑怎么把参数传进去,而是考虑如何构建一个无需参数的事件处理程序,该程序是根据有参数的事件处理程序创建的,是一个外层封装。简单的说,就是将一个有参数的函数封装为一个无参数的函数。现在我们来自定义一个通用的函数来实现这种功能:
//将有参数的函数封装为无参数的函数
function createFunction(obj,strFunc) {
var args=[]; //定义args用于存储传递给事件处理程序的参数
if (!obj) obj=window; //如果是全局函数则obj=window
//得到传递给事件处理程序的参数
for (var i=2;i<arguments.length;i++) {
   args.push(arguments);
}
//用无参数函数封装事件处理程序的调用
return function() {
  obj[strFunc].apply(obj,args); //将参数传递给指定的事件处理函数
}
}
这个方法将一个有参数的函数封装为一个无参数的函数,不仅对全局函数适用,作为对象方法存在的函数同样适用。该方法首先接收两个参数:obj和strFunc,obj表示事件处理程序所在的对象;strFunc表示事件处理程序的名称。除此以外,程序中还利用arguments对象处理第二个参数以后的隐式参数,即未定义形式参数的参数,并在调用事件处理程序时利用apply方法将这些参数传递进去。最后将apply方法获得的对象返回。例如一个事件处理程序是:
someObject.eventHandler=function(_arg1,arg2) {
//事件处理代码
}
应该调用:
createFunction(someObject,\"eventHandler\",arg1,arg2);
这就返回一个无参数的函数,在返回的函数中已经包括了传递进去的参数。如果是全局函数作为事件处理程序,事实上它是window对象的一个方法,所以可以传递window对象作为obj参数。为了更清晰一点,也可以指定obj为null,createFunction函数内部会自动认为该函数是全局函数,从而自动把obj赋值为window对象。下面来看看应用的例子:
//定义类class1
function class1() {
//构造函数
}
class1.prototype={
show:function() {
  //show函数的实现
  this.onShow(); //触发onShow事件
},
onShow:function() {} //定义事件接口
}
//创建class1的实例
var obj=new class1();
//创建obj的onShow事件处理程序
function objOnShow(userName) {
  alert(\"hello,\"+userName);
}
//定义变量userName
var userName=\"chinazk.com\"
//绑定obj的onShow事件
obj.onShow=createFunction(null,\"objOnShow\",userName);
//调用obj的show方法
obj.show();
在这段代码中,就将变量username作为参数传递给了objOnShow事件处理程序。事实上,obj.onShow得到的事件处理程序并不是objOnShow,而是由createFunction返回的一个无参函数。通过createFunction封装,就可以用一种通用的方法来实现参数传递了。这不仅适用于自定义的事件,也适用于系统提供的事件,其原理是完全相同的。
18.怎样实现抽象类?
虚函数是类成员中的概念,是只做了一个声明而未实现的方法,具有虚函数的类就称之为抽象类,这些虚函数在派生类中才被实现。抽象类是不能被实例化的,因为其中的虚函数并不是一个完整的函数,不能被调用。所以抽象类一般只作为基类被派生以后再使用。和类的继承一样,javascript并没有任何机制用于支持抽象类。但是利用javascript语言本身的性质,可以实现自己的抽象类。在传统的面向对象语言中,抽象类中的虚方法必须先被声明,但可以在其他方法中被调用。而在javascript中,虚方法就可以看作该类中没有定义的方法,但已经通过this指针使用了。和传统面向对象不同的是,这里的虚方法不需经过声明,而可直接使用。这些方法将在派生类中实现。例如:
//定义一个抽象基类base,无构造函数
function base() {}
base.prototype={
initialize:function() {
   this.oninit(); //调用了一个虚方法
}
}
//定义class1
function class1() {
//构造函数
}
//让class1继承于base并实现其中的oninit方法
class1.prototype=(new base()).extend({oninit:function() {
//实现抽象基类中的oninit虚方法
//oninit函数的实现
}
});
以prototype1.5.1为例,其中定义了一个类的创建模型:
var Class = {
create: function() {
  return function() {
   this.initialize.apply(this, arguments);
  }
}
}
这里class是一个全局兑现,具有一个方法create,用于返回一个函数(类),从而声明一个类,可以用如下格式:
var class1=Class.create();
这样就是类的定义和函数的定义方式区分开来,使javascript语言能够更具备面向对象语言的特点。现在来看这个返回的函数(类):
function() {
this.initialize.apply(this, arguments);
}
这个函数也是一个类的构造函数,当new这个类时便会得到执行。他调用了一个initialize方法。从名字来看,是类的构造函数。而从类的角度来看,他是一个虚方法,是未定义的。但这个虚方法的实现并不是在派生类中实现的,而是创建一个类后,在prototype中定义的。例如prototype可以这样写:
var class1=Class.create();
class1.prototype={
initialize:function(userName) {
  alert(\"hello,\"+userName);
}
}
回复

使用道具 举报

发表于 2007-12-5 01:57:13 | 显示全部楼层
页面中有个“终端”应该是“终止”吧

“带面”应该是“代码”吧
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

Archiver|手机版|小黑屋|网上读书园地

GMT+8, 2024-6-7 10:52 , Processed in 0.353664 second(s), 6 queries , Redis On.

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表