iLeichun

当前位置:首页JavaScript

再谈javascript面向对象编程

分类:JavaScript  来源:网络  时间:2012-4-11 21:28:00

虽有陈皓《Javascript 面向对象编程》珠玉在前,但是我还是忍不住再画蛇添足的补上一篇文章,主要是因为javascript这门语言魅力。

吐槽Javascript

初次接触Javascript,这门语言的确会让很多正规军感到诸多的不适,这种不适来自于Javascript的语法的简练和不严谨,这种不适也来自Javascript这个悲催的名称,我在想网景公司的Javascript设计者在给他起名称那天一定是脑壳进水了,让Javascript这么多年来受了这么多不白之冤,人们都认为他是Java的附属物,一个WEB玩具语言。因此才会有些人会对Javascript不屑,认为Javascript不是一门真正的语言,但是这此他们真的错了。Javascript不仅是一门语言,是一门真真正正的语言,而且他还是一门里程碑式的语言,他独创多种新的编程模式原型继承,闭包(作者注:闭包不是JS首创,应该Scheme首创,prototypal inheritance 和 dynamic objects 是self语言首创,Javascript的首创并不精彩,谢谢网友的指正。),对后来的动态语言产生了巨大的影响。做为当今最流行的语言(没有之一),看看git上提交的最多的语言类型就能明白。随着HTML5的登场,浏览器将在个人电脑上将大显身手,完全有替换OS的趋势的时候,Javascript做为浏览器上的一门唯一真真的语言,如同C之于 unix/linux,java之于JVM,Cobol之于MainFrame,我们也需要来重新的认真地认识和审视这门语言。另外Javascript的正式名称是:ECMAScript,这个名字明显比Javascript帅太多了!

言归正传,我们切入主题——Javascript的面向对象编程。要谈Javascript的面向对象编程,我们第一步要做的事情就是忘记我们所学的面向对象编程。传统C++或Java的面向对象思维来学习Javascript的面向对象会给你带来不少困惑,让我们先忘记我们所学的,从新开始学习这门特殊的面向对象编程。既然是OO编程,要如何来理解OO编程呢,记得以前学C++,学了很久都不入门,后来有幸读了《Inside The C++ Object Model》这本大作,顿时豁然开朗,因此本文也将以对象模型的方式来探讨的Javascript的OO编程。因为Javascript 对象模型的特殊性,所以使得Javascript的继承和传统的继承非常不一样,同时也因为Javascript里面没有类,这意味着Javascript里面没有extends,implements。那么Javascript到底是如何来实现OO编程的呢?好吧,让我们开始吧,一起在Javascript的OO世界里来一次漫游

首先,我们需要先看看Javascript如何定义一个对象。下面是我们的一个对象定义:

1
var o = {};

还可以这样定义一个对象

1
2
function f() {
}

对,你们没有看错,在Javascript里面,函数也是对象。
当然还可以

1
var array1= [ 1,2,3];

数组也是一个对象。
其他关于对象的基本的概念的描述,还是请各位亲们参见陈皓《Javascript 面向对象编程》文章。
对象都有了,唯一没有的就是class,因为在Javascript里面是没有class关键字的,算好还有function,function的存在让我们可以变通的定义类,在扩展这个主题前,我们还需要了解一个Javascript对象最重要的属性,__proto__成员。

__proto__成员

严格的说这个成员不应该叫这个名字,__proto__是Firefox中的称呼,__proto__只有在Firefox浏览器中才能被访问到。做为一个对象,当你访问其中的一个成员或方法的时候,如果这个对象中没有这个方法或成员,那么Javascript引擎将会访问这个对象的__proto__成员所指向的另外的一个对象,并在那个对象中查找指定的方法或成员,如果不能找到,那就会继续通过那个对象的__proto__成员指向的对象进行递归查找,直到这个链表结束
好了,让我们举一个例子。
比如上上面定义的数组对象array1。当我们创建出array1这个对象的时候,array1实际在Javascript引擎中的对象模型如下:

array1对象具有一个length属性值为3,但是我们可以通过如下的方法来为array1增加元素:

1
array1.push(4);

push这个方法来自于array1的__proto__成员指向对象的一个方法(Array.prototye.push())。正是因为所有的数组对象(通过[]来创建的)都包含有一个指向同一个具有push,reverse等方法对象(Array.prototype)的__proto__成员,才使得这些数组对象可以使用push,reverse等方法。

那么这个__proto__这个属性就相当于面向对象中的”has a”关系,这样的的话,只要我们有一个模板对象比如Array.prototype这个对象,然后把其他的对象__proto__属性指向这个对象的话就完成了一种继承的模式。不错!我们完全可以这么干。但是别高兴的太早,这个属性只在FireFox中有效,其他的浏览器虽然也有属性,但是不能通过__proto__来访问,只能通过getPrototypeOf方法进行访问,而且这个属性是只读的。看来我们要在Javascript实现继承并不是很容易的事情啊。

函数对象prototype成员

首先我们先来看一段函数prototype成员的定义,

When a function object is created, it is given a prototype member which is an object containing a constructor member which is a reference to the function object
当一个函数对象被创建时,这个函数对象就具有一个prototype成员,这个成员是一个对象,这个对象包含了一个构造子成员,这个构造子成员会指向这个函数对象。

例如:

1
2
3
function Base() {
    this.id = "base"
}

Base这个函数对象就具有一个prototype成员,关于构造子其实Base函数对象自身,为什么我们将这类函数称为构造子呢?原因是因为这类函数设计来和new 操作符一起使用的。为了和一般的函数对象有所区别,这类函数的首字母一般都大写。构造子的主要作用就是来创建一类相似的对象。

上面这段代码在Javascript引擎的对象模型是这样的

new 操作符

在有上面的基础概念的介绍之后,在加上new操作符,我们就能完成传统面向对象的class + new的方式创建对象,在Javascript中,我们将这类方式成为Pseudoclassical。
基于上面的例子,我们执行如下代码

1
var obj = new Base();

这样代码的结果是什么,我们在Javascript引擎中看到的对象模型是:

new操作符具体干了什么呢?其实很简单,就干了三件事情。

1
2
3
var obj  = {};
obj.__proto__ = Base.prototype;
Base.call(obj);

第一行,我们创建了一个空对象obj
第二行,我们将这个空对象的__proto__成员指向了Base函数对象prototype成员对象
第三行,我们将Base函数对象的this指针替换成obj,然后再调用Base函数,于是我们就给obj对象赋值了一个id成员变量,这个成员变量的值是”base”,关于call函数的用法,请参看陈皓《Javascript 面向对象编程》文章
如果我们给Base.prototype的对象添加一些函数会有什么效果呢?
例如代码如下:

1
2
3
Base.prototype.toString = function() {
    return this.id;
}

那么当我们使用new创建一个新对象的时候,根据__proto__的特性,toString这个方法也可以做新对象的方法被访问到。于是我们看到了:
构造子中,我们来设置‘类’的成员变量(例如:例子中的id),构造子对象prototype中我们来设置‘类’的公共方法。于是通过函数对象和Javascript特有的__proto__与prototype成员及new操作符,模拟出类和类实例化的效果。

Pseudoclassical 继承

我们模拟类,那么继承又该怎么做呢?其实很简单,我们只要将构造子的prototype指向父类即可。例如我们设计一个Derive 类。如下

1
2
3
4
5
6
7
8
function Derive(id) {
    this.id = id;
}
Derive.prototype = new Base();
Derive.prototype.test = function(id){
    return this.id === id;
}
var newObj = new Derive("derive");

这段代码执行后的对象模型又是怎么样的呢?根据之前的推导,应该是如下的对象模型

这样我们的newObj也继承了基类Base的toString方法,并且具有自身的成员id。关于这个对象模型是如何被推导出来的就留给各位同学了,参照前面的描述,推导这个对象模型应该不难。
Pseudoclassical继承会让学过C++/Java的同学略微的感受到一点舒服,特别是new关键字,看到都特亲切,不过两者虽然相似,但是机理完全不同。当然不关什么样继承都是不能离不开__proto__成员的。

Prototypal继承

这是Javascript的另外一种继承方式,这个继承也就是之前陈皓文章《Javascript 面向对象编程》中create函数,非常可惜的是这个是ECMAScript V5的标准,支持V5的浏览器目前看来也就是IE9,Chrome最新版本和Firefox。虽然看着多,但是做为IE6的重灾区的中国,我建议各位还是避免使用create函数。好在没有create函数之前,Javascript的使用者已经设计出了等同于这个函数的。例如:我们看看Douglas Crockford的object函数。

1
2
3
4
5
6
function object(old) {
   function F() {};
   F.prototype = old;
   return new F();
}
var newObj = object(oldObject);

例如如下代码段

1
2
3
4
5
6
7
var base ={
  id:"base",
  toString:function(){
          return this.id;
  }
};
var derive = object(base);

上面函数的执行后的对象模型是:

如何形成这样的对象模型,原理也很简单,只要把object这个函数扩展一下,就能画出这个模型,怎么画留给读者自己去画吧。
这样的继承方式被称为原型继承。相对来说要比Pseudoclassical继承来的简单方便。ECMAScript V5正是因为这原因也才增加create函数,让开发者可以快速的实现原型继承。
上述两种继承方式是Javascript中最常用的继承方式。通过本文的讲解,你应该对Javascript的OO编程有了一些‘原理’级的了解了吧

参考:

《Prototypes and Inheritance in JavaScript Prototypes and Inheritance in JavaScript》
Advance Javascript (Douglas Crockford 大神的视频,一定要看啊)

题外话:

web2.0后,web应用可谓飞速发展,如今在HTML5发布之际,浏览器的功能被大大强化,我感觉Browser远远在不是一个Browser那么简单了。记得C++之父曾经这样说过JAVA,JAVA不是跨平台,JAVA本身就是一个平台。如今的Browser也本身就是一个平台了,好在这个平台是基于标准的。如果Browser是平台,由于Browser安全沙箱的限制,个人电脑的资源被使用的很少,感觉Browser就是一个NC(Network Computer)?我们居然又回到了Sun最初提出的构想,Sun是不是太强大了些?

 

来源:http://coolshell.cn/articles/6668.html

理解Javascript的闭包

分类:JavaScript  来源:网络  时间:2012-4-11 21:18:13

Javascript中有几个非常重要的语言特性——对象、原型继承、闭包。其中闭包对于那些使用传统静态语言C/C++的程序员来说是一个新的语言特性。本文将以例子入手来介绍Javascript闭包的语言特性,并结合一点ECMAScript语言规范来使读者可以更深入的理解闭包。

注:本文是入门文章,例子素材整理于网络,如果你是高手,欢迎针对文章提出技术性建议和意见。本文讨论的是Javascript,不想做语言对比,如果您对Javascript天生不适,请自行绕道。

什么是闭包

闭包是什么?闭包是Closure,这是静态语言所不具有的一个新特性。但是闭包也不是什么复杂到不可理解的东西,简而言之,闭包就是:

  • 闭包就是函数的局部变量集合,只是这些局部变量在函数返回后会继续存在。
  • 闭包就是就是函数的“堆栈”在函数返回后并不释放,我们也可以理解为这些函数堆栈并不在栈上分配而是在堆上分配
  • 当在一个函数内定义另外一个函数就会产生闭包

上面的第二定义是第一个补充说明,抽取第一个定义的主谓宾——闭包是函数的‘局部变量’集合。只是这个局部变量是可以在函数返回后被访问。(这个不是官方定义,但是这个定义应该更有利于你理解闭包)

做为局部变量都可以被函数内的代码访问,这个和静态语言是没有差别。闭包的差别在于局部变变量可以在函数执行结束后仍然被函数外的代码访问。这意味着函数必须返回一个指向闭包的“引用”,或将这个”引用”赋值给某个外部变量,才能保证闭包中局部变量被外部代码访问。当然包含这个引用的实体应该是一个对象,因为在Javascript中除了基本类型剩下的就都是对象了。可惜的是,ECMAScript并没有提供相关的成员和方法来访问闭包中的局部变量。但是在ECMAScript中,函数对象中定义的内部函数(inner function)是可以直接访问外部函数的局部变量,通过这种机制,我们就可以以如下的方式完成对闭包的访问了。

 

function greeting(name) {
    var text = ¹Hello ¹ + name; // local variable
    // 每次调用时,产生闭包,并返回内部函数对象给调用者
    return function() { alert(text); }
}
var sayHello=greeting("Closure");
sayHello()  // 通过闭包访问到了局部变量text

上述代码的执行结果是:Hello Closure,因为sayHello()函数在greeting函数执行完毕后,仍然可以访问到了定义在其之内的局部变量text。

好了,这个就是传说中闭包的效果,闭包在Javascript中有多种应用场景和模式,比如Singleton,Power Constructor等这些Javascript模式都离不开对闭包的使用。

ECMAScript闭包模型

ECMAScript到底是如何实现闭包的呢?想深入了解的亲们可以获取ECMAScript 规范进行研究,我这里也只做一个简单的讲解,内容也是来自于网络。

在ECMAscript的脚本的函数运行时,每个函数关联都有一个执行上下文场景(Execution Context) ,这个执行上下文场景中包含三个部分

  • 文法环境(The LexicalEnvironment)
  • 变量环境(The VariableEnvironment)
  • this绑定

其中第三点this绑定与闭包无关,不在本文中讨论。文法环境中用于解析函数执行过程使用到的变量标识符。我们可以将文法环境想象成一个对象,该对象包含了两个重要组件,环境记录(Enviroment Recode),和外部引用(指针)。环境记录包含包含了函数内部声明的局部变量和参数变量,外部引用指向了外部函数对象的上下文执行场景。全局的上下文场景中此引用值为NULL。这样的数据结构就构成了一个单向的链表,每个引用都指向外层的上下文场景。

例如上面我们例子的闭包模型应该是这样,sayHello函数在最下层,上层是函数greeting,最外层是全局场景。如下图:

因此当sayHello被调用的时候,sayHello会通过上下文场景找到局部变量text的值,因此在屏幕的对话框中显示出”Hello Closure”
变量环境(The VariableEnvironment)和文法环境的作用基本相似,具体的区别请参看ECMAScript的规范文档。

闭包的样列

前面的我大致了解了Javascript闭包是什么,闭包在Javascript是怎么实现的。下面我们通过针对一些例子来帮助大家更加深入的理解闭包,下面共有5个样例,例子来自于JavaScript Closures For Dummies(镜像)。
例子1:闭包中局部变量是引用而非拷贝

function say667() {
    // Local variable that ends up within closure
    var num = 666;
    var sayAlert = function() { alert(num); }
    num++;
    return sayAlert;
}

var sayAlert = say667();
sayAlert()

因此执行结果应该弹出的667而非666。

例子2:多个函数绑定同一个闭包,因为他们定义在同一个函数内。

function setupSomeGlobals() {
    // Local variable that ends up within closure
    var num = 666;
    // Store some references to functions as global variables
    gAlertNumber = function() { alert(num); }
    gIncreaseNumber = function() { num++; }
    gSetNumber = function(x) { num = x; }
}
setupSomeGlobals(); // 为三个全局变量赋值
gAlertNumber(); //666
gIncreaseNumber();
gAlertNumber(); // 667
gSetNumber(12);//
gAlertNumber();//12

例子3:当在一个循环中赋值函数时,这些函数将绑定同样的闭包

function buildList(list) {
    var result = [];
    for (var i = 0; i < list.length; i++) {
        var item = ¹item¹ + list[i];
        result.push( function() {alert(item + ¹ ¹ + list[i])} );
    }
    return result;
}

function testList() {
    var fnlist = buildList([1,2,3]);
    // using j only to help prevent confusion - could use i
    for (var j = 0; j < fnlist.length; j++) {
        fnlist[j]();
    }
}

testList的执行结果是弹出item3 undefined窗口三次,因为这三个函数绑定了同一个闭包,而且item的值为最后计算的结果,但是当i跳出循环时i值为4,所以list[4]的结果为undefined.

例子4:外部函数所有局部变量都在闭包内,即使这个变量声明在内部函数定义之后。

function sayAlice() {
    var sayAlert = function() { alert(alice); }
    // Local variable that ends up within closure
    var alice = ¹Hello Alice¹;
    return sayAlert;
}
var helloAlice=sayAlice();
helloAlice();

执行结果是弹出”Hello Alice”的窗口。即使局部变量声明在函数sayAlert之后,局部变量仍然可以被访问到。

例子5:每次函数调用的时候创建一个新的闭包

function newClosure(someNum, someRef) {
    // Local variables that end up within closure
    var num = someNum;
    var anArray = [1,2,3];
    var ref = someRef;
    return function(x) {
        num += x;
        anArray.push(num);
        alert(¹num: ¹ + num +
        ¹
anArray ¹ + anArray.toString() +
        ¹
ref.someVar ¹ + ref.someVar);
    }
}
closure1=newClosure(40,{someVar:¹closure 1¹});
closure2=newClosure(1000,{someVar:¹closure 2¹});

closure1(5); // num:45 anArray[1,2,3,45] ref:¹someVar closure1¹
closure2(-10);// num:990 anArray[1,2,3,990] ref:¹someVar closure2¹

闭包的应用

Singleton 单件:

var singleton = function () {
    var privateVariable;
    function privateFunction(x) {
        ...privateVariable...
    }

    return {
        firstMethod: function (a, b) {
            ...privateVariable...
        },
        secondMethod: function (c) {
            ...privateFunction()...
        }
    };
}();

这个单件通过闭包来实现。通过闭包完成了私有的成员和方法的封装。匿名主函数返回一个对象。对象包含了两个方法,方法1可以方法私有变量,方法2访问内部私有函数。需要注意的地方是匿名主函数结束的地方的’()’,如果没有这个’()’就不能产生单件。因为匿名函数只能返回了唯一的对象,而且不能被其他地方调用。这个就是利用闭包产生单件的方法。

 

来源:http://coolshell.cn/articles/6731.html

JS实现图片幻灯片效果的源码

分类:JavaScript  来源:网络  时间:2012-4-2 13:19:34

 Flash的幻灯片效果可能是网站中使用频率最多的一种效果,其实用JS也可以实现这种效果,而且功能以点不差,只需要将下面这段JS的幻灯片效果代码复制到网页中就能实现,而且宽度和高度修改起来比Flash更简单,如果你不会Flash的话,那使用JS是很好的选择。

调用方法:new flashBoxCtrl("flashBox");

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="zh-cn">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312" />
<meta http-equiv="Content-Language" content="gb2312" />
<meta name="author" content="RainoXu" />
<title>flash幻灯</title>
</head>
<body>
<style  type ="text/css">
/*  <![CDATA[  */
ul,li{
padding:0;
margin:0;
list-style:none;
}
#flashBox{
width:346px;
height:186px;
border:1px solid #EEE;
position:relative;
}
#flashBox img{
/*初始不要显示*/
display:none;
/*用边框来实现空位,因为margin和paading有时会引起些麻烦*/
border:3px solid #FFF;
}
#flashBox ul{
position:absolute;
right:7px;
bottom:9px;
font:9px tahoma;
}
#flashBox ul li{
display:block;
float:left;
width:12px;
height:12px;
line-height:12px;
margin-right:3px;
border:1px solid #999;
background:#F0F0F0;
text-align:center;
cursor:pointer;
}
#flashBox ul li.hover{
border-color:red;
background:#FFE1E1;
color:red;
}
/*  ]]>  */
</style>
<script type="text/javascript">
function flashBoxCtrl(o){
this.obj=document.getElementById(o);
//这个私有方法虽然写了,但暂时没用到
function addListener(ele,eventName,functionBody){
if (ele.attachEvent){
ele.attachEvent("on"+eventName, functionBody);
}else if (ele.addEventListener){
ele.addEventListener("on"+eventName,functionBody, false);
}else{
return false;
}
}
//初始化
this.init=function(){
var objImg=this.obj.getElementsByTagName("img");
var tagLength=objImg.length;
if (tagLength>0){
var oUl=document.createElement("ul");
oUl.setAttribute("id",o+"numTag");
for (var i=0;i<tagLength;i++){
var oLi=oUl.appendChild(document.createElement("li"));
if (i==0){
oLi.setAttribute("class","hover"); //初始化时把第一个设置为高亮
oLi.setAttribute("className","hover");
}
//设置标签的数字
oLi.appendChild(document.createTextNode((i+1)));
}
this.obj.appendChild(oUl);
objImg[0].style.display="block";
//设置标签事件
var oTag=this.obj.getElementsByTagName("li");
for (var i=0;i<oTag.length;i++){
oTag[i].onmouseover=function(){
for (j=0;j<oTag.length;j++){
oTag[j].className="";
objImg[j].style.display="none";
}
this.className="hover";
objImg[this.innerHTML-1].style.display="block";
}
}
}
};
//自动滚动的方法还没写
this.imgRoll=function(){};
//生成对象时自动加载init()方法以初始化对象
this.init();
}
</script>
<div id="flashBox">
<img src="/upimg/allimg/090726/a.jpg" _fcksavedurl="/upimg/allimg/090726/a.jpg" />
<img src="/upimg/allimg/090726/b.jpg" _fcksavedurl="/upimg/allimg/090726/b.jpg" />
<img src="/upimg/allimg/090726/c.jpg" _fcksavedurl="/upimg/allimg/090726/c.jpg" />
<img src="/upimg/allimg/090726/d.jpg" _fcksavedurl="/upimg/allimg/090726/d.jpg" />
</div>
<script type="text/javascript">
//生成一个对象
new flashBoxCtrl("flashBox");
</script>
</body>
</html>

JavaScript判断是否为IE浏览器最简单的代码

分类:JavaScript  来源:网络  时间:2012-3-3 23:18:25

浏览器兼容一直让人头痛。处理兼容问题经常要判断用户浏览器类型。
以前要写一大窜代码来判断是否为IE浏览器。以后再也不用这么麻烦了。

方法1:通过IE与非IE浏览器对垂直制表符支持特性搞出的一段简短的条件:

var ie = !+”v1″;

方法2:利用了IE与标准浏览器在处理数组的toString方法的差异做成的。对于标准游览器,如果数组里面最后一个字符为逗号,JS 引擎会自动剔除它。
var ie = !-[1,];

大家可以测试一下:

var ie = !-[1,];

alert(ie);

常用Javascript代码收集

分类:JavaScript  来源:网络  时间:2012-2-27 20:52:05

禁止屏蔽类

1.禁止右键

<body oncontextmenu=return(false)>

2.禁止选择

<body onselectstart="return false">

3.禁止frame引用

<script>
 if (top != self)top.location.href = "hello.html";
</script>

4.禁止粘贴

<body onpaste="return false">

5.禁止直接访问 [必须框架内才行]

<script>
 if (top == self)top.location.href = "ok.html";
</script>

6.禁止功能键Shift,Alt,Ctrl

<script>
function key(){
 if(event.shiftKey) alert("Shift不允许使用!");
}
document.onkeydown=key;
</script>

数据取得类

1.取得分辨率
<script>document.write("宽"+screen.Width+"高"+screen.Height)</script>

2.取得地址栏

<script>document.write(self.location)</script>

3.取得地址栏后参数

<SCRIPT>
 var add = top.location;
 add = add.toString();
 document.write (add.substring(add.indexOf("?")+1,add.length));
</SCRIPT>

常用特效类

1.主页遥控器

文件一.(t1.html)
<SCRIPT language="JavaScript">
window.open("t2.html","_blank","width=250","height=210","scroll=no");
</SCRIPT>

文件二.(t2.html)
<SCRIPT language="JavaScript">
 function op(add){if (window.opener){window.opener.document.location = add;}}
</SCRIPT>
<a href=# onClick="op(¹link1.html¹)">地址1 </a><br><a href=# onClick="op(¹link2.html¹)">地址2 </a><br><a href=# onClick="op(¹http://music.jx165.com¹)">地址3 </a>

2.只弹一次的窗口

<script>
function get_cookie(Name) {
 var search = Name + "="
 var returnvalue = "";
 if (document.cookie.length > 0) {offset = document.cookie.indexOf(search)
 if (offset != -1) {offset += search.length;end = document.cookie.indexOf(";", offset);
 if (end == -1)end = document.cookie.length;returnvalue=unescape(document.cookie.substring(offset, end))}
 }
 return returnvalue;
}
function jx168(){
 if (get_cookie(¹jx165ad¹)==¹¹){
  document.cookie="jx165ad=yes"
  window.open("ad.html","_blank","width=200","height=200","scroll=no");
 }
 else {}
}
</script>
<body>
<script>
 jx168();
</script>

3.鼠标放在连接上强行点击

<script>
function click() {
 var source=event.srcElement;
 if (source.tagName=="A"){
  source.click();
  self.focus();
 }
}
document.write("<div onmouseover=mClk2();>");
</script>

JavaScript中对象、函数与继承入门讲解

分类:JavaScript  来源:网络  时间:2011-3-12 12:09:33

1、 Javascript中的对象

  JavaScript可以说是一个基于对象的编程语言,为什么说是基于对象而不是面向对象,因为JavaScript自身只实现了封装,而没有实现继承和多态。既然他是基于对象的,那么我们就来说说js中的对象。有人说js中所有的都是对象,这句话不完全正确。正确的一方是他强调了对象在js中的重要性,对象在js中无处不在,包括可以构造对象的函数本身也是对象。但是另一方面,js中也有一些简单的数据类型,包括数字、字符串和布尔值、null值和undefined值,而这些不是对象。那为什么这些类型的值不是对象呢,毕竟他们也有方法。那让我们来看一下,JavaScript中对于对象的定义,有两种定义。

  (1)JavaScript中的对象是可变的键控集合(keyed collections) (此定义来自老道的那本书的第三章)

  (2)JavaScript中的对象是无序(unordered)的属性集合,这些属性可以含有简单的数据类型、对象、函数;保存在一个对象属性中的函数也被称为这个对象的方法。 (来自ECMA-262 的4.3.3)(注:这里所说的属性是可以在js脚本中创建和访问的(我们称之为显性属性),不包括系统为对象自动分配的内部属性)

  那为什么那个简单的数据类型不是对象呢,主要是因为这些数据类型的值中拥有的方法是不可变的,而一个对象的属性是应当可以被改变的。

  2、 对象中的原型链[[proto]]

  JavaScript中的每个对象创建的时候系统都会自动为其分配一个原型属性[[proto]],用来连接到他的原型对象。在JavaScript中就是通过每个对象中的[[proto]]来实现对象的继承关系的。但是对象的[[proto]]属性在JavaScript是不能访问和修改的,他是作为一个内部的属性存在的,而且是在对象被创建的同时由系统自动设定的。

  当访问一个对象的某一属性,如果这个属性在此对象中不存在,就在他的[[proto]]所指的原型对象的属性中寻找,如果找到则返回,否则继续沿着[[proto]]链一直找下去,直到[[proto]]的连接为null的时候停止。

  3、 函数也是对象

  JavaScript中的函数本身就是一个对象(所以我们经常称之为函数对象),而且可以说他是js中最重要的对象。之所以称之为最重要的对象,一方面他可以扮演像其他语言中的函数同样的角色,可以被调用,可以被传入参数;另一方面他还被作为对象的构造器(constructor)来使用,可以结合new操作符来创建对象。

  既然函数就是对象,所以必然含有对象拥有的全部性质,包括对象在创建时设定的原型链[[proto]]属性。

  让我们来看看函数对象和普通对象有什么区别。我们前面说过,对象就是无序的属性集合,那么函数的属性和普通对象的属性有什么不同呢。根据ECMA-262中的13.2节所述,在函数对象创建时,系统会默认为其创建两个属性[[call]]和[[constructor]],当函数对象被当做一个普通函数调用的时候(例如myFunc()),“()”操作符指明函数对象的[[call]]属性就被执行,当他被当做一个构造器被调用的时候(例如new myConst()),他的[[constructor]]属性就被执行,[[cosntructor]]的执行过程我们将在下一节中介绍。除此之外,当一个函数被创建时,系统会默认的再为其创建一个显示属性prototype,并为其赋值为

  this.prototype = {constructor:this}

  具体内容可以参加老道的那本书的第五章。这个函数对象的prototype属性也是为了js把函数当做构造器来实现继承是准备的,但是这个属性是可以在js脚本中访问和修改的。在这里要强调的一点是,大家一定要区分对象中的[[proto]]属性和函数对象中的prototype属性,我在刚开始学习的时候就是因为没有很好的区分这两个东西,走了很多的弯路。

  4、 对象的创建

  在js中有两种创建对象的方法,一种是通过字面量来实现,如

  var Person = {

  “first_name”:’liang’,

  ‘last_name’:’yang’

  }

  另一种方法是通过构造器来创建

  var my = new Person(‘liang’,’yang’);

  其实第一种方式的创建过程相当于调用Object构造器来实现,如下。

  var Person = new Object();

  Person.first_name = ‘liang’;

  Person.last_name = ‘yang’

  所以我们可以把js中所有对象的创建都合并到使用构造器来实现,下面我么来详细说明构造器创建对象的过程:

  第一步,先创建一个空的对象(既没有任何属性),并将这个对象的[[proto]]指向这个构造器函数的prototype属性对象

  第二步,将这个空的对象作为this指针传给构造器函数并执行

  第三步,如果上面的函数返回一个对象,则返回这个对象,否则返回第一步创建的对象

  第四步,把函数当做一个类来使用

  由上面的步骤我们可以看出,一般来说函数对象的prototype指向的是一个普通对象,而不是一个函数对象,这个普通对象中的属在由此函数构造器创建的对象中也可以访问。由此可以如此设计我们的代码,假设一个函数就可以代表一个类,这个构造器函数生成的对象就是这个类的实例对象,那么实例对象中应有的属性和方法应该放在这个构造器函数的prototype中,这个类的静态方法就可以直接放到这个函数作为对象的属性中,最后这个函数体就是我们平时在面向对象语言中所说的构造函数(在这里我们要区分连个词“构造函数”和“构造器函数”,所谓构造函数是指普通的面向对象语言中的类的构造函数,而构造器函数是指javascript中的一个函数被当做构造器使用)。

  在第3节我们说过每个函数的prototype对象中总是含有一个constructor属性,这个属性就是连接到我们的这个函数本身。再加之,有这个函数生成的每个对象的[[proto]]属性都是指向构造器函数的prototype对象,所以通过[[proto]]链,每个由构造器函数生成的对象,都有一个constructor属性,指向生成他的构造器函数,因此我们可以通过这个属性来判断这个对象是有哪个构造器函数生成的。

  5、 函数继承(类继承)

  说了这么多,终于到了我们可以在javascript中讨论继承的时候了,我们先来考虑一下要实现类的继承我们都要做些什么,假设我们要从superClass继承到子类subClass

  为了使得由subClass生成的对象中能够访问superClass生成的对象中的属性,那么可以使subClass.prototype为一个superClass构造函数生成的对象。

  subclass.prototye = new superClass();

  但是问题来了,根据我们在第4节说的new superClass()不仅复制了superClass.prototype中的所有方法,而且还运行了superClass()这个函数,这个函数起到的作用是类中的构造函数。我们知道应该在子类的构造函数中调用父类的构造函数来实现初始化。为此我们可以创建一个构造函数为空的,但是原型和superClass原型一致的函数,并使subClass.prototype指向这个函数生成的对象。

  var F = function() {};

  F.prototype = superClass.prototype;

  subClass.protptype = new F();

  这样我们就可以再不调用构造函数的同时完成属性复制的工作。但是还有一个问题,那就是我们修改了subClass的prototype属性,从而也就删除了其中的constructor属性,这样我们就无法知道他是哪个构造器函数生成的对象了。我们可以再次给他赋值

  subClass.prototype.constructor = subClass;

  这样复制属性的问题就迎刃而解了。但是新的问题又出现了,在subClass中我们无法知道他的父类是哪个构造器函数,所以就无法在构造函数中调用父类的构造函数,为此我们可以为subClass添加一个属性,指明他的父类

  subClass.superClass = superClass.prototype;

  这样我么就可以在子类的构造函数中使用subClass.superClass.constructor来访问父类的构造函数了。最后我们把以上的思路写成一个函数

  myPro.extend = function (subClass,superClass) {

  var F = function() {};

  F.prototype = superClass.prototype;

  subClass.protptype = new F();

  subClass.prototype.constructor = subClass;

  subClass.superClass = superClass.prototype;

  superClass.prototype.constructor = superClass;

  }

javascript/js常用表单验证

分类:JavaScript  来源:网络  时间:2011-3-8 23:56:03
一、
1. 长度限制
<script>
function test() 
{
if(document.a.b.value.length>50)
{
alert("不能超过50个字符!");
document.a.b.focus();
return false;
}
}
</script>
<form name=a onsubmit="return test()">
<textarea name="b" cols="40" wrap="VIRTUAL" rows="6"></textarea>
<input type="submit" name="Submit" value="check">
</form> 
 
2. 只能是汉字 
<input onkeyup="value="/oblog/value.replace(/[^u4E00-u9FA5]/g,¹¹)">
 
3." 只能是英文
<script language=javascript>
function onlyEng()
{
if(!(event.keyCode>=65&&event.keyCode<=90))
event.returnvalue=false;
}
</script>
<input onkeydown="onlyEng();">
 
4. 只能是数字
<script language=javascript>
function onlyNum()
{
if(!((event.keyCode>=48&&event.keyCode<=57)||(event.keyCode>=96&&event.keyCode<=105)))
//考虑小键盘上的数字键
event.returnvalue=false;
}
</script>
<input onkeydown="onlyNum();">
 
5. 只能是英文字符和数字
<input onkeyup="value="/oblog/value.replace(/[W]/g,"¹¹) "onbeforepaste="clipboardData.setData(¹text¹,clipboardData.getData(¹text¹).replace(/[^d]/g,¹¹))">
 
6. 验证邮箱格式
<SCRIPT LANGUAGE=javascript RUNAT=Server>
function isEmail(strEmail) {
if (strEmail.search(/^w+((-w+)|(.w+))*@[A-Za-z0-9]+((.|-)[A-Za-z0-9]+)*.[A-Za-z0-9]+$/) != -1)
return true;
else
alert("oh");
}
</SCRIPT>
<input type=text onblur=isEmail(this.value)>
 
7. 屏蔽关键字(这里屏蔽***和****)
<script language="javascript1.2">
function test() {
if((a.b.value.indexOf ("***") == 0)||(a.b.value.indexOf ("****") == 0)){
alert(":)");
a.b.focus();
return false;}
}
</script>
<form name=a onsubmit="return test()">
<input type=text name=b>
<input type="submit" name="Submit" value="check">
</form>
 
8. 两次输入密码是否相同
<FORM METHOD=POST ACTION="">
<input type="password" id="input1">
<input type="password" id="input2">
<input type="button" value="test" onclick="check()">
</FORM>
<script>
function check()
with(document.all){
if(input1.value!=input2.value)
{
alert("false")
input1.value = "";
input2.value = "";
}
else document.forms[0].submit();
}
}
</script>
 
9.屏蔽右键
oncontextmenu="return false" ondragstart="return false" onselectstart="return false"
加在body中
 
二、
2.1 表单项不能为空
<script language="javascript">
<!--
function CheckForm()
if (document.form.name.value.length == 0) { 
alert("请输入您姓名!");
document.form.name.focus();
return false;
}
return true;
}
-->
</script>
 
2.2 比较两个表单项的值是否相同
<script language="javascript">
<!--
function CheckForm()
if (document.form.PWD.value != document.form.PWD_Again.value) { 
alert("您两次输入的密码不一样!请重新输入.");
document.ADDUser.PWD.focus();
return false;
}
return true;
}
-->
</script>
 
2.3 表单项只能为数字和"_",用于电话/银行帐号验证上,可扩展到域名注册等
<script language="javascript">
<!--
function isNumber(String)
var Letters = "1234567890-"; //可以自己增加可输入值
var i;
var c;
if(String.charAt( 0 )==¹-¹)
return false;
if( String.charAt( String.length - 1 ) == ¹-¹ )
return false;
for( i = 0; i < String.length; i ++ )
c = String.charAt( i );
if (Letters.indexOf( c ) < 0)
return false;
}
return true;
}
function CheckForm()
if(! isNumber(document.form.TEL.value)) { 
alert("您的电话号码不合法!");
document.form.TEL.focus();
return false;
}
return true;
}
-->
</script>
 
2.4 表单项输入数值/长度限定
<script language="javascript">
<!--
function CheckForm() 
if (document.form.count.value > 100 || document.form.count.value < 1)
alert("输入数值不能小于零大于100!");
document.form.count.focus();
return false;
}
if (document.form.MESSAGE.value.length<10)
alert("输入文字小于10!");
document.form.MESSAGE.focus();
return false;
}
return true;
}
//-->
</script>
 
2.5 中文/英文/数字/邮件地址合法性判断
<SCRIPT LANGUAGE="javascript">
<!--
function isEnglish(name) //英文值检测
if(name.length == 0)
return false;
for(i = 0; i < name.length; i++) { 
if(name.charCodeAt(i) > 128)
return false;
}
return true;
}
function isChinese(name) //中文值检测
if(name.length == 0)
return false;
for(i = 0; i < name.length; i++) { 
if(name.charCodeAt(i) > 128)
return true;
}
return false;
}
function isMail(name) // E-mail值检测
if(! isEnglish(name))
return false;
i = name.indexOf(" at ");
j = name dot lastIndexOf(" at ");
if(i == -1)
return false;
if(i != j)
return false;
if(i == name dot length)
return false;
return true;
}
function isNumber(name) //数值检测
if(name.length == 0)
return false;
for(i = 0; i < name.length; i++) { 
if(name.charAt(i) < "0" || name.charAt(i) > "9")
return false;
}
return true;
}
function CheckForm()
if(! isMail(form.Email.value)) { 
alert("您的电子邮件不合法!");
form.Email.focus();
return false;
}
if(! isEnglish(form.name.value)) { 
alert("英文名不合法!");
form.name.focus();
return false;
}
if(! isChinese(form.cnname.value)) { 
alert("中文名不合法!");
form.cnname.focus();
return false;
}
if(! isNumber(form.PublicZipCode.value)) { 
alert("邮政编码不合法!");
form.PublicZipCode.focus();
return false;
}
return true;
}
//-->
</SCRIPT>
 
2.6 限定表单项不能输入的字符
<script language="javascript">
<!--
function contain(str,charset)// 字符串包含测试函数
var i;
for(i=0;i<charset.length;i++)
if(str.indexOf(charset.charAt(i))>=0)
return true;
return false;
}
function CheckForm()
if ((contain(document.form.NAME.value, "%()><")) || (contain(document.form.MESSAGE.value, "%()><")))
alert("输入了非法字符");
document.form.NAME.focus();
return false;
}
return true;
}
//-->
</script> 
 
三、
1. 检查一段字符串是否全由数字组成 
<script language="Javascript"><!-- 
function checkNum(str){return str.match(/D/)==null} 
alert(checkNum("1232142141")) 
alert(checkNum("123214214a1")) 
// --></script> 
 
2. 怎么判断是否是字符 
if (/[^x00-xff]/g.test(s)) alert("含有汉字"); 
else alert("全是字符"); 
 
3. 怎么判断是否含有汉字 
if (escape(str).indexOf("%u")!=-1) alert("含有汉字"); 
else alert("全是字符"); 
 
4. 邮箱格式验证 
//函数名:chkemail 
//功能介绍:检查是否为Email Address 
//参数说明:要检查的字符串 
//返回值:0:不是 1:是 
function chkemail(a) 
{ var i=a.length; 
var temp = a.indexOf(¹@¹); 
var tempd = a.indexOf(¹.¹); 
if (temp > 1) { 
if ((i-temp) > 3){ 
if ((i-tempd)>0){ 
return 1; 
return 0; 
 
5. 数字格式验证 
//函数名:fucCheckNUM 
//功能介绍:检查是否为数字 
//参数说明:要检查的数字 
//返回值:1为是数字,0为不是数字 
function fucCheckNUM(NUM) 
var i,j,strTemp; 
strTemp="0123456789"; 
if ( NUM.length== 0) 
return 0 
for (i=0;i<NUM.length;i++) 
j=strTemp.indexOf(NUM.charAt(i)); 
if (j==-1) 
//说明有字符不是数字 
return 0; 
//说明是数字 
return 1; 
 
6. 电话号码格式验证 
//函数名:fucCheckTEL 
//功能介绍:检查是否为电话号码 
//参数说明:要检查的字符串 
//返回值:1为是合法,0为不合法 
function fucCheckTEL(TEL) 
var i,j,strTemp; 
strTemp="0123456789-()# "; 
for (i=0;i<TEL.length;i++) 
j=strTemp.indexOf(TEL.charAt(i)); 
if (j==-1) 
//说明有字符不合法 
return 0; 
//说明合法 
return 1; 
 
7. 判断输入是否为中文的函数 
function ischinese(s){ 
var ret=true; 
for(var i=0;i<s.length;i++) 
ret=ret && (s.charCodeAt(i)>=10000); 
return ret; 
 
8. 综合的判断用户输入的合法性的函数 
<script language="javascript"> 
//限制输入字符的位数开始 
//m是用户输入,n是要限制的位数 
function issmall(m,n) 
if ((m<n) && (m>0)) 
return(false); 
else 
{return(true);} 
 
9. 判断密码是否输入一致 
function issame(str1,str2) 
if (str1==str2) 
{return(true);} 
else 
{return(false);} 
 
10. 判断用户名是否为数字字母下滑线 
function notchinese(str){ 
var reg=/[^A-Za-z0-9_]/g 
if (reg.test(str)){ 
return (false); 
}else{ 
return(true); } 
 
11. form文本域的通用校验函数
作用:检测所有必须非空的input文本,比如姓名,账号,邮件地址等等。
该校验现在只针对文本域,如果要针对form里面的其他域对象,可以改变判断条件。
使用方法:在要检测的文本域中加入title文字。文字是在提示信息,你要提示给用户的该字段的中文名。比如要检测用户名
html如下<input name="txt_1" title="姓名">,当然,最好用可视化工具比如dreamweaver什么的来编辑域。
如果要检测数字类型数据的话,再把域的id统一为sz.
javascript判断日期类型比较麻烦,所以就没有做日期类型校验的程序了.高手可以补充。
程序比较草,只是提供一个思路。抛砖引玉! :)
哦,对了,函数调用方法:< form onsubmit="return dovalidate()">
function dovalidate()
{
fm=document.forms[0] //只检测一个form,如果是多个可以改变判断条件
for(i=0;i<fm.length;i++)
//检测判断条件,根据类型不同可以修改
if(fm[i].tagName.toUpperCase()=="INPUT" &&fm[i].type.toUpperCase()=="TEXT" && (fm[i].title!=""))
if(fm[i].value="/blog/="")//
{
str_warn1=fm[i].title+"不能为空!";
alert(str_warn1);
fm[i].focus();
return false; 
}
if(fm[i].id.toUpperCase()=="SZ")//数字校验
{
if(isNaN(fm[i].value))
{ str_warn2=fm[i].title+"格式不对";
alert(str_warn2);
fm[i].focus();
return false;
}
}
}
return true;
}

几个JavaScript特效

分类:JavaScript  来源:网络  时间:2011-2-24 14:52:29

禁止屏蔽类

1.禁止右键

<body oncontextmenu=return(false)>

2.禁止选择

<body onselectstart="return false">

3.禁止粘贴

<body onpaste="return false">

4.禁止直接访问 [必须框架内才行]

<script>
if (top == self)top.location.href = "page.htm";
</script>

5.禁止frame引用

<script>
if (top != self)top.location.href = "page.htm";
</script>

6.禁止功能键Shift,Alt,Ctrl

<script>function key(){
if(event.shiftKey) alert("Shift不允许使用!");} document.onkeydown=key; </script>

数据取得类

1.取得分辨率
<script>document.write("宽为"+screen.Width+"高为"+screen.Height)</script>

2.取得地址栏

<script>document.write(self.location)</script>

3.取得地址栏后参数

<SCRIPT>var add = top.location;
add = add.toString();
document.write (add.substring(add.indexOf("?")+1,add.length));
</SCRIPT>

 

 

 

 

常用特效类

1.主页遥控器

文件一.(t1.html)
<SCRIPT language="JavaScript">
window.open("t2.html","_blank","width=200","height=200","scroll=no");
</SCRIPT>
文件二.(t2.html)
<SCRIPT language="JavaScript">
function op(add){if (window.opener){window.opener.document.location = add;}}
</SCRIPT>
<a href=# onClick="op(¹link1.html¹)">地址1 </a><br><a href=# onClick="op(¹link2.html¹)">地址2 </a><br><a href=# onClick="op(¹http://music.jx165.com¹)">地址3 </a>

2.只弹一次的窗口

<script>
function get_cookie(Name) {
var search = Name + "="
var returnvalue = "";
if (document.cookie.length > 0) {offset = document.cookie.indexOf(search)
if (offset != -1) {offset += search.length;end = document.cookie.indexOf(";", offset);
if (end == -1)end = document.cookie.length;returnvalue=unescape(document.cookie.substring(offset, end))}
}
return returnvalue;
}
function jx165ad(){
if (get_cookie(¹jx165ad¹)==¹¹){
document.cookie="jx165ad=yes"
window.open("ad.html","_blank","width=200","height=200","scroll=no");
}
else {}
}
</script>
<body>
<script>
jx165ad();
</script>

3.鼠标放在连接上强行点击

<script>
function mClk2() {var source=event.srcElement;if (source.tagName=="A"){source.click();self.focus();}}
document.write("<div onmouseover=mClk2();>");
</script>

javascript中对URL字符串编码的方法

分类:JavaScript  来源:网络  时间:2010-11-20 14:43:35

javascript中存在几种对URL字符串进行编码的方法:escape(),encodeURI(),以及encodeURIComponent()。这几种编码所起的作用各不相同。
escape() 方法:

采用ISO Latin字符集对指定的字符串进行编码。所有的空格符、标点符号、特殊字符以及其他非ASCII字符都将被转化成%xx格式的字符编码(xx等于该字符在字符集表里面的编码的16进制数字)。比如,空格符对应的编码是%20。

不会被此方法编码的字符: @ * / +

encodeURI() 方法:

把URI字符串采用UTF-8编码格式转化成escape格式的字符串。

不会被此方法编码的字符:! @ # $& * ( ) = : / ; ? + ’

encodeURIComponent() 方法:

把 URI字符串采用UTF-8编码格式转化成escape格式的字符串。与encodeURI()相比,这个方法将对更多的字符进行编码,比如 / 等字符。所以如果字符串里面包含了URI的几个部分的话,不能用这个方法来进行编码,否则 / 字符被编码之后URL将显示错误。

不会被此方法编码的字符:! * ( ) ’

因 此,对于中文字符串来说,如果不希望把字符串编码格式转化成UTF-8格式的(比如原页面和目标页面的charset是一致的时候),只需要使用 escape。如果你的页面是GB2312或者其他的编码,而接受参数的页面是UTF-8编码的,就要采用encodeURI或者 encodeURIComponent。

另外,encodeURI/encodeURIComponent是在javascript1.5之后引进的,escape则在javascript1.0版本就有。

 

Js中escape(),encodeURI()和encodeURIComponent()方法比较

分类:JavaScript  来源:网络  时间:2010-11-20 14:42:35

escape(), encodeURI()和encodeURIComponent()是在Javascript中用于编码字符串的三个常用的方法,而他们之间的异同却困扰 了很多的Javascript初学者,在这里对这三个方法详细地分析与比较一下。

escape() 方法

MSDN JScript Reference中如是说:

The escape method returns a string value (in Unicode format) that contains the contents of [the argument]. All spaces, punctuation, accented characters, and any other non-ASCII characters are replaced with %xx encoding, where xx is equivalent to the hexadecimal number representing the character. For example, a space is returned as “%20.”

译:escape方法以Unicode格式返回一个包含传入参数内容的string类型的值。 Escape方法会将传入参数中所有的空格、标点符号、重音字符以及其它任何非ASCII字符替换为%xx的编码形式,其中xx与其所表示的字符的16进 制数表示形式相同。如空格字符的16进制表示形式为0×20,则此时xx应为20,即escape(‘ ’) 返回“%20”。

Mozilla Developer Core Javascript Guide中如是说:

The escape and unescape functions let you encode and decode strings. The escape function returns the hexadecimal encoding of an argument in the ISO Latin character set. The unescape function returns the ASCII string for the specified hexadecimal encoding value.

译:escape和unescape方法能够帮助你编码和解码字符串。escape方法对于ISO Latin字符集中的字符组成的参数,返回其16进制编码。相对应的,unescape方法则能将16进制编码形式的参数转化成为其ASCII码形式。

encodeURI()方法

MSDN JScript Reference中如是说:

The encodeURI method returns an encoded URI. If you pass the result to decodeURI, the original string is returned. The encodeURI method does not encode the following characters: “:”, “/”, “;”, and “?”. Use encodeURIComponent to encode these characters.

译:encodeURI方法返回一个经过编码的URI。如果将encodeURI方法的编码结果传递给decodeURI方法作参数,则能得到原始 的未编码的字符串。需要注意到是encodeURI方法不编码如下字符”:”, “/”, “;”, and “?”。如果想要编码这些字符,请使用encodeURIComponent方法。

Mozilla Developer Core Javascript Guide中如是说:

Encodes a Uniform Resource Identifier (URI) by replacing each instance of certain characters by one, two, or three escape sequences representing the UTF-8 encoding of the character.

译:通过将每个属于特定的字符集合的字符替换为一个、两个或者三个(为什么是“一个、两个或者三个”本人也没有搞懂,望高人赐教)使用UTF-8编 码来表示这个字符的escape序列来编码一个URI。如 ~!@#$%^&*(){}[]=:/,;?+”” 将被替换为 ~!@#$%25%5E&*()%7B%7D%5B%5D=:/,;?+”%22%5C

encodeURIComponent()方法

MSDN JScript Reference中如是说:

The encodeURIComponent method returns an encoded URI. If you pass the result to decodeURIComponent, the original string is returned. Because the encodeURIComponent method encodes all characters, be careful if the string represents a path such as /folder1/folder2/default.html. The slash characters will be encoded and will not be valid if sent as a request to a web server. Use the encodeURI method if the string contains more than a single URI component.

译:encodeURIComponent方法返回一个编码过的URI。如果将encodeURIComponent方法的编码结果传递给 encodeURIComponent方法作参数,则能得到原始的未编码的字符串。因为encodeURIComponent方法会编码所有的字符,所以 如果待编码的字符串是用来表示一个路径(如/dir1/dir2/index.htm)时,就一定要小心使用了。‘/’符号会被其编码之后,将不再是一个 有效的路径标识符,所以不能被web服务器正确地识别。当字符串包含一个单独的URI component(指?后面的请求参数)的时候,请使用此方法。

Mozilla Developer Core Javascript Guide中如是说:

Encodes a Uniform Resource Identifier (URI) component by replacing each instance of certain characters by one, two, or three escape sequences representing the UTF-8 encoding of the character.

译:通过将每个属于特定的字符集合的字符替换为一个、两个或者三个(为什么是“一个、两个或者三个”本人也没有搞懂,望高人赐教)使用UTF-8编 码来表示这个字符的escape序列来编码一个URIComponent。

有什么区别?何时使用?
通过上面的介绍可以看出,MS的文档明显要比Mozilla详细、易懂一些,但是它们表达的都是一个意思。但是escape(), encodeURI()和 encodeURIComponent()有什么异同,它们分别适用于那种特定的情况呢?

escape方 法并不编码字符+。而我们知道,在用户提交的表单字段中,如果有空格,则会被转化为+字符,而服务器解析的时候则会认为+号代表空格。由于这个缺 陷,escape方法并不能正确地处理所有的非ASCII字符,你应当尽量避免使用escape方法,取而代之,你最好选择 encodeURIComponent()方法。
escape()不编码的字符:@*/+

相对于使用escape方法,使用encodeURI方法会显得更专业一些。当你需要编码一整个URI的时候,你可以使用此方法,因为URI中的合 法字符都不会被编码转换。需要注意到是字符’也是URI中的合法字符,所以也不会被编码转换。
encodeURI() 不编码的字符: ~!@#$&*()=:/,;?+”

encodeURIComponent方法在编码单个URIComponent(指请求参数)应当是最常用的。需要注意到是字符’也是URI中的合 法字符,所以也不会被编码转换。
encodeURIComponent()不编码的字符: ~!*()”