Archive for the ‘ javascript/jquery ’ Category

深入理解JavaScript的变量作用域[转]

晚上没事看了看《ActionScript3.0基础教程》。以前一直认为ActionScript和Javascript师出同门,应该是极为相似的,不过看了一下还是有些区别的。比如ActionScript是可以严格控制数据类型的,并且函数作用域相比Javascript来说更为明晰。限于本人是这两种语言的超级菜鸟,顺便goole了一篇很不错的关于JavaScript变量作用域的文章,备忘。

原文地址:http://www.cnblogs.com/rainman/archive/2009/04/28/1445687.html

在学习JavaScript的变量作用域之前,我们应当明确几点:

a、JavaScript的变量作用域是基于其特有的作用域链的。
b、JavaScript没有块级作用域。
c、函数中声明的变量在整个函数中都有定义。

1、JavaScript的作用域链

首先看下下面这段代码:


<script type="text/javascript" language="javascript">

var rain = 1;
function rainman(){
    var man = 2;
    function inner(){
        var innerVar = 4;
        alert(rain);
    }
    inner();    //调用inner函数
}
rainman();    //调用rainman函数

</script>

观察alert(rain);这句代码。JavaScript首先在inner函数中查找是否定义了变量rain,如果定义了则使用inner函数中的rain变量;如果inner函数中没有定义rain变量,JavaScript则会继续在rainman函数中查找是否定义了rain变量,在这段代码中rainman函数体内没有定义rain变量,则JavaScript引擎会继续向上(全局对象)查找是否定义了rain;在全局对象中我们定义了rain = 1,因此最终结果会弹出’1′。

作用域链:JavaScript需要查询一个变量x时,首先会查找作用域链的第一个对象,如果以第一个对象没有定义x变量,JavaScript会继续查找有没有定义x变量,如果第二个对象没有定义则会继续查找,以此类推。

上面的代码涉及到了三个作用域链对象,依次是:inner、rainman、window。

2、函数体内部,局部变量的优先级比同名的全局变量高。


<script type="text/javascript" language="javascript">

var rain = 1;    //定义全局变量 rain
function check(){
    var rain = 100;    //定义局部变量rain
    alert( rain );    //这里会弹出 100
}
check();
alert( rain );    //这里会弹出1

</script>

3、JavaScript没有块级作用域。

这一点也是JavaScript相比其它语言较灵活的部分。

仔细观察下面的代码,你会发现变量i、j、k作用域是相同的,他们在整个rain函数体内都是全局的。


<script type="text/javascript" language="javascript">

function rainman(){
/**
 * rainman函数体内存在三个局部变量 i j k
 */
    var i = 0;
    if( 1 ){
        var j = 0;
        for( var k = 0 ; k < 3 ; k++ ){
            alert( k );    //分别弹出 0 1 2
        }
        alert( k );    //弹出3
    }
    alert( j );    //弹出0
}

</script>

4、函数中声明的变量在整个函数中都有定义。

首先观察这段代码。


<script type="text/javascript" language="javascript">

function rain(){
    var x = 1;
    function man(){
        x = 100;
    }
    man();    //调用man
    alert( x );    //这里会弹出 100
}
rain();    //调用rain

</script>

上面得代码说明了,变量x在整个rain函数体内都可以使用,并可以重新赋值。由于这条规则,会产生“匪夷所思”的结果,观察下面的代码。


<script type="text/javascript" language="javascript">

var x = 1;
function rain(){
    alert( x );    //弹出 'undefined',而不是1
    var x = 'rain-man';
    alert( x );    //弹出 'rain-man'
}
rain()

</script>

这是由于在函数rain内局部变量x在整个函数体内都有定义( var x= ‘rain-man’,进行了声明),所以在整个rain函数体内隐藏了同名的全局变量x。这里之所以会弹出’undefined’是因为,第一个执行alert(x)时,局部变量x仍未被初始化。

所以上面的rain函数等同于下面的函数。


function rain(){
    var x;
    alert( x );
    x = 'rain-man';
    alert( x );
}

5、未使用var关键字定义的变量都是全局变量。


<script type="text/javascript" language="javascript">

function rain(){
    x = 100;    //声明了全局变量x并进行赋值
}
rain();
alert( x );    //会弹出100

</script>

这也是JavaScript新手常见的错误,无意之中留下的许多全局变量。

6、全局变量都是window对象的属性


<script type="text/javascript" language="javascript">

var x = 100 ;
alert( window.x );//弹出100
alert(x);

</script>

 
等同于下面的代码:


<script type="text/javascript" language="javascript">

window.x = 100;
alert( window.x );
alert(x);

</script>

附录:一些比较BT的有关全局变量和局部变量的测试

<script>
/*
* javascript 的全局变量与局部变量一直都是一个头疼的问题,今天在写程序的时候有出现了个问题。在ie7下,在函数里就可以访问全局变量,而在ie6
* 下面居然变量的值变成了undefined。
* 以前网上查到的资料都是在定义变量的时候不使用var就定义的是全局变量,但为什么就不行了呢?
* 我就写了下面的测试程序:
*/

/*----------------------------------------*/
 
/*
a = 1;      //A 此处为全局变量
var b = 2;  //B 此处为全局变量
function params(){
alert(a);   //程序输出为1
alert(b);   //程序输出为2
}
params();
*/
 
/*----------------------------------------*/
 
/*
a = 1;      //A 此处为全局变量
var b = 2;  //B 此处为全局变量
function params(){
var a = 11;  //C 此处为局部变量
var b = 22;  //D 此处为局部变量
alert(a);    //程序输出为11
alert(b);    //程序输出为22
}
params();
alert(a);        //程序输出为1
alert(b);         //程序输出为2
*/
 
/*----------------------------------------*/
 
/*
a = 1;      //A 此处为全局变量
var b = 2;  //B 此处为全局变量
function params(){
a = 11;     //C 修改全局变量a的值
b = 22;     //D 修改全局变量b的值
alert(a);   //程序输出为11
alert(b);   //程序输出为22
}
params();
alert(a);       //程序输出为11
alert(b);       //程序输出为22
*/
 
/*----------------------------------------*/
 
/*
a = 1;      //A 此处为全局变量
var b = 2;  //B 此处为全局变量
function params(){
var a = 11;    //C 此处为局部变量
var b = 22;    //D 此处为局部变量
alert(a);      //程序输出为11
alert(b);      //程序输出为22
alert(window.a);//程序输出为1
alert(window.b);//程序输出为2
}
params();
alert(a);           //程序输出为1
alert(b);           //程序输出为2
*/
 
/*----------------------------------------*/
 
/*
a = 1;      //A 此处为全局变量
var b = 2;  //B 此处为全局变量
function params(){
a = 11;    //C 修改全局变量a的值
b = 22;    //D 修改全局变量b的值
alert(a);      //程序输出为11
alert(b);      //程序输出为22
alert(window.a);//程序输出为11
alert(window.b);//程序输出为22
}
params();
alert(a);           //程序输出为11
alert(b);           //程序输出为22
*/

/*----------------------------------------*/
 
/**
* 从以上的测试程序,应该明白全局变量和局部变量.
* 个人觉得访问全局变量,如果只需兼容ie,最好使用 window.a 这种方式来访问.
*/
</script>

猜猜以下代码输出什么:

<SCRIPT LANGUAGE="JavaScript">  
var x='000';  
document.writeln(x);
a();
function a(){  
   var x='aaa';  
   function b(){  
     document.writeln(x); 
     var x='bbb';  
     document.writeln(x);  
     }  
   b(); 
   document.writeln(x);
   }  
</SCRIPT>

答案:000 undefined bbb aaa
改一下代码,得到 000 undefined 111 111:

<SCRIPT LANGUAGE="JavaScript">  
var x='000';  
document.writeln(x); 
a(); 
function a(){  
  function b(){  
    document.writeln(x); 
    document.writeln(x); 
  }  
  document.writeln(x);
  var x='111';  
  b();   
  }  
</SCRIPT>

猜猜以下代码会输出什么:

<SCRIPT LANGUAGE="JavaScript">  
  var x=100;  
  document.writeln(x); 
  add(x); 
  document.writeln('</br>------------------------</br>'); 
  var x=200;  
  document.writeln(x);  
  add(x); 
  function add(x){  
    document.writeln(x);
    var x=300;     
    document.writeln(x);  
    var x=400;  
    document.writeln(x);  
    }  
</SCRIPT>

估计很多人能得出正确答案:
 
100 100 300 400
————————
200 200 300 400

成功的Javascript开发者的7个习惯[2] —— 柔性减弱和不唐突的Javascript

——节选自《Javascript实战》(Practical Javascript,DOM Scripting,and Ajax Projects),作者:Frank W.Zammetti。

2.2 柔性减弱和不唐突的Javascript

不唐突的Javascript是一个最近才流行起来的术语。简单地说,它是一种趋势,网页中的Javascript以一种不影响页面的方式来写

不唐突的Javascript的基本原则非常简单,可以被归纳为以下几点:

保持Javascript独立。

通常允许柔性减弱。

从不使用浏览器嗅探脚本来判断一个浏览器的能力。

任何情况下,都不要写浏览器不兼容的代码,具体说,就是别写浏览器相关的Javascript代码。

合适的作用域变量。

★ 对于可访问性,避免需要鼠标事件触发的触发器。

但是,不唐突的Javascript术语对于不同的人也可以有不同的意思。一些人喜欢扩展规则并使其更加严格。另一些人喜欢修建规则并使其更灵活。关键是使用我们从以前的错误中学到的方法来实现 Javascript。

现在让我们来看看每一个基础规则的详细内容。

2.2.1 让Javascript保持独立

这个观点是把Javascript当作应用程序的一层来处理,并且使用定义明确的交互点,试着使它尽可能地独立。例如,总是从外部文件导入Javascript,并没有任何的Javascript嵌在HTML中。

我认为,这是一条比较灵活的规则。但是基本的观点是说:最大限度地保持脚本独立。

考虑一下CSS。你已经习惯于外部样式表了,对吗?那么用同样的方法来看待Javascript。这样做逻辑上把页面分成了几个部分,我们就可以很容易地找到自己感兴趣、想要修改的地方。同时它还给你留下一条重用的途径。外部保存的脚本有更好的机会在其他页面、其他站点以及其他项目中重用。虽然不能保证肯定能被使用,但它往往是有帮助的。

一些人甚至提倡通过脚本来添加事件处理函数。通常,这么做的原因是把脚本和标记完全分离,避免在修改函数名之后要修改代码中的很多地方。我不完全同意这个建议,主要是因为,一个事件处理函数是对于一个指定元素特定的,所以为什么不把它附近在那个元素上呢?对于我来说,如果我需要改变一个事件处理函数,直接找到那个元素要比找出哪个外部.js文件包含那段代码更加容易。不过有一个例外,如果处理函数是共享的(被多于一个的元素使用),这种情况下,我就会将它外部化。

到底什么样才是最好的,留给你自己去归纳。然而,我非常鼓励你保持事件处理函数尽可能的小,无论把它们放在哪。它们应该只是调用一些大块的代码或者执行一两行语句。如果你想方法让事件处理函数与元素在同一行内,那会是个更好的主意。

2.2.2 允许柔性减弱

离开了Javascript,页面也还应该工作,即使是在以衰减的形式。一个很好的例子是表单验证。不要只适用调用一个表单的函数的按钮,因为如果离开了Javascript,这个表单就不能提交了。比如,尝试下面代码清单2-1的代码,并观察一下禁用了Javascript会发生什么。


<html>

  <head>

    <script>

        function doSubmit(inForm){

            if(inForm.firstName.value == ""){

             alert("You must enter a first name");

             return false;

           } 

            if(inForm.lastName.value == ""){

             alert("You must enter a last name");

             return false;

           } 

           inForm.submit();

           return true;

        }

    </script>

  </head>

  <body>

    <form name="test" action="#" method="post">

        First name:<input type="test" name="firstName" />

        <br />

        Last name:<input type="test" name="lastName" />

        <br />

        <input type="button" onClick="doSubmit(this.form);" value="Submit" />

    </form>

  </body>

</html>

如果禁用Javascript后运行上面的代码,你将看到什么都没有发生,因为表单的提交依赖Javascript的执行,这显然是不好的。

取代它的办法是,在onSubmit时间的响应中进行验证。使用这种方法,如果Javascript启用,用户可以从客户端验证中受益。但是如果Javascript被禁用了,表单仍然可以被提交。代码清单2-2展示了它是如何工作的。


<html>

  <head>

    <script>

        function doSubmit(inForm){

            if(inForm.firstName.value == ""){

             alert("You must enter a first name");

             return false;

           } 

            if(inForm.lastName.value == ""){

             alert("You must enter a last name");

             return false;

           } 

           inForm.submit();

           return true;

        }

    </script>

  </head>

  <body>

    <form name="test" action="#" method="post" onSubmit="return doSubmit(this)">

        First name:<input type="test" name="firstName" />

        <br />

        Last name:<input type="test" name="lastName" />

        <br />

        <input type="submit" value="Submit" />

    </form>

  </body>

</html>

顺便说一下,一个致命的错误是:使用单纯的客户端验证,并假设从客户端来的任何数据都是好的。事实上,你的系统通常应该被设计成为认为从客户端来的数据都是坏的。在客户端做验证是完全可行的。不过,几乎没人愿意使用的系统把客户端验证作为唯一验证方法。

好,我们来谈一些观点。有人认为,我们应该在所有Web应用上附加一些不唐突的原则和一些合理的、柔性衰减的安全约束。我并不同意这种观点,甚至可以说,我认为这种观点完全是无原则的。

[...]

我们所处的时代是“RIA(Rich Internet Application,富因特网应用)”时代,RIA开始统治因特网。比如说,Google,现在就处在把一整套office软件套件放在网上给所有用户使用的早期时代(见http://docs.google.com)。你认为所有开发人员都会力图遵守所有不唐突的原则吗(除了少数最低限度的之外)?并且这么做了之后还能用?几乎可以肯定地说这不可能,因为对于这种高端应用来说,这就是不肯能的任务。让我说得更明白些:在RIA世界里,大多数这里描述的不唐突的要求仍然是可为的。只是其中的某些可能不能做到罢了。

这就是网站和Web应用之间的差距。从某种意义上来说,网站的目的是散播信息。它只有很有限度的用户交互需求,通常来说,简单的HTML表单就足够好用了。在一个网站里,所有这里描述的规则几乎都应该遵守,而且更重要的是,这些规则是可以遵守的。相对来说,Web应用则更复杂并且需要更高级的用户交互。它们就是为了替换胖客户端、应用程序等那些用户已经习惯了几十年的东西。这些用户需要功能强大同时又简洁的动态交互界面、铃声和报警声,以及一些不写代码就不能实现的特性——并且有些代码必须在客户端里组织起来。在这种场合,我的观点是:遵守这些规则就是不合理的,会导致无数项目的失败。

不过,对于任何在Web上给公众使用的东西,你都毫无疑问地应该争取优秀的可用性、合理的柔性衰减,以及所有其他不唐突的Javascript目标。对于无法实现这些目标的地方,我们应该有很清晰、和合理的原因,并且绝对可以确信:如果要实现这些目标,你的应用就无法实现。(我汗-_-|||还好语文学得好,呃呃)

所以,简而言之,我认为你应该审视一下你正在做什么,以及你的目标是什么,并决定这些指导哪些应该遵循。不要犯错误,我相信你会试着遵守全部这些规则。但是我估计那有时并不可能。再说一次,这是我个人的意见,请根据自己最好的判断形成自己的意见。

2.2.3 不要使用浏览器嗅探例程

与其使用浏览器嗅探脚本去确定一个浏览器的能力,还不如检查对象的存在和对象的能力。这个问题的补充是,只是由于开发者的懒惰而引起的Javascript错误,比如在访问一个给定对象之前没有检查它是否存在,是无理且不好的。

一个例子,看看下面的代码:


function setContent(inobj,inContent{

    inObject.innerHTML = inContent;

}

);

这里,如果对象inObj并不支持innerHTML,就会出现一个错误。可能由于innerHTML不是DOM中的一个标准的部分(虽然,实际上我不知道有哪个浏览器没实现它)。重写这部分来避免这个错误很简单:

function setContent(inobj,inContent{

   if(inObj.innerHTML){

      inObject.innerHTML = inContent;

    }

    }

);

[/javascript]

通常像这样检查是个好习惯,它实际上是确定一个浏览器是否支持一个特定的功能。这样做的一个最好的例子是基本的Ajax编程,你需要一个XMLHttpRequest对象的实例。不幸的是,不同的浏览器使用不同的方法来支持这个对象的使用。然而,你可以检查不同的对象,并基于它们的存在或不存在,来分支代码,像这样:


var xhr = null;

if(window.XMLHttpRequest){

    xhr = new XMLHttpRequest();

}

else if(window.ActiveXObject){

    xhr = new ActiveXObject(Microsoft.XMLHTTP);

}

然而,如果能写根本不需要分支的代码会更好,但是那通常不太可能。浏览器嗅探是个坏主意,因为,很多开发者多年来的体会是,你总是需要保持嗅探代码的更新,以便让它能识别新的浏览器。对象存在性的检查就没那么脆弱了,通常不需要重写代码来处理新的浏览器,所以这个技术比嗅探浏览器好得多。

jQuery性能优化指南(3)

8,尽量使用ID代替Class

前面性能优化已经说过,ID选择器的速度是最快的。所以在HTML代码中,能使用ID的尽量使用ID来代替class。
看下面的一个例子:

// 创建一个list;

var $myList = $("#myList");

var myListItems = "<ul>";

for (i = 0; i < 1000; i++) {
     myListItems += '<li class="listItem' + i + '">This is a list item</li>'; //这里使用的是class
 }

myListItems += "</ul>";

$myList.html(myListItems);

// 选择每一个 li

 for (i = 0; i < 1000; i++) {
    var selectedItem = $(".listItem" + i);
}

在代码最后,选择每个li的过程中,总共用了5066毫秒,超过5秒了。

接着我们做一个对比,用ID代替class:

// 创建一个list

var $myList = $("#myList");

var myListItems = "<ul>";

for (i = 0; i < 1000; i++) {
    myListItems += '<li id="listItem' + i + '">This is a list item</li>'; //这里使用的是id
}

myListItems += "</ul>";

$myList.html(myListItems);

 // 选择每一个 li

for (i = 0; i < 1000; i++) {
     var selectedItem = $("#listItem" + i);
}

在上段代码中,选择每个li总共只用了61毫秒,相比class的方式,将近快了100倍。

9,给选择器一个上下文

jQuery选择器中有一个这样的选择器,它能指定上下文。
jQuery( expression, context );

通过它,能缩小选择器在DOM中搜索的范围,达到节省时间,提高效率。
普通方式:

$(".myDiv")

改进方式:

$(".myDiv" , $("#listItem") )

10,慎用 .live()方法(应该说尽量不要使用)

这是jQuery1.3.1版本之后增加的方法,这个方法的功能就是为新增的DOM元素动态绑定事件。
但对于效率来说,这个方法比较占用资源。所以请尽量不要使用它。

例如有这么一段代码:

<script type="text/javascript">

$(function(){
 $("p").click(function(){
     alert( $(this).text() );
 });
$("button").click(function(){
    $("<p>this is second p</p>").appendTo(”body”);
});
})

</script>
<body>

<p>this is first p</p> <button>add</button>

</body>

运行后,你会发现新增的p元素,并没有被绑定click事件。

你可以改成.live(”click”)方式解决此问题,代码如下:

$(function(){

$("p").live("click",function(){ //改成live方式
     alert( $(this).text() );
 });
$("button").click(function(){ $("<p>this is second p</p>").appendTo("body"); });})

但我并不建议大家这么做,我想用另一种方式去解决这个问题,代码如下:

$(function(){

$("p").click(function(){

    alert( $(this).text() );

});
$("button").click(function(){

    $("<p>this is second p</p>").click(function(){  //为新增的元素重新绑定一次

            alert( $(this).text() );

    }).appendTo("body");
});
})

虽然我把绑定事件重新写了一次,代码多了点,但这种方式的效率明显高于live()方式,特别是在频繁的DOM操作中,这点非常明显。

11,子选择器和后代选择器

后代选择器经常用到,比如:

$("#list p");

后代选择器获取的是元素内部所有元素。

而有时候实际只要获取子元素,那么就不应该使用后代选择器。应该使用子选择器,代码如下:

$("#list > p");

12,使用data()方法存储临时变量

下面是一段非常简单的代码,


$(function(){

    var flag = false;

    $("button").click(function(){

        if(flag){

            $("p").text("true");

            flag=false;

        }else{

            $("p").text("false");

            flag=true;

        }

    });

})

改用data()方式后,代码如下:

$(function(){

    $("button").click(function(){

        if( $("p").data("flag") ){

            $("p").text("true");

            $("p").data("flag",false);

        }else{

             $("p").text("false");

             $("p").data("flag",true);

        }

    });

})

成功的Javascript开发者的7个习惯[1] —— 更多面向对象的Javascript

——节选自《Javascript实战》(Practical Javascript,DOM Scripting,and Ajax Projects),作者:Frank W.Zammetti。

2.1 更多面向对象的Javascript

当很多Javascript程序员开始使用Javascript的时候,他们通常并没有意识到这个语言提供了一些面向对象的概念。当然,Javascript完全不要求使用对象!(其他它隐含地会使用对象,因为Javascript在很多场合会使用内置对象,但是你的代码自身不必是面向对象的)

条条大路通罗马,同样,在Javascript中,也有不止一种的方法来创建对象。

2.1.1 简单的对象创建

可能最简单的创建对象的方法是用一个新的Object开始,然后向其中添加内容。想要创建一个新的Object,你只要这么做:


var newObject = new Object();

变量newObject现在指向一个Object的实例,Object是Javascript中所有对象的基类。要给它添加一个元素,比如说,增加一个叫firstName的元素,你要做的只是:


newObject.firstName = "Frank";

从代码中的这个位置开始,newObject.firstName就将含有一个值”Frank”,除非它在后面被修改了。你也可以很容易地添加函数:


newObject.sayName = function(){

alert(this.firstName);

}

现在newObject.sayName()调用的结果,是弹出一个”Frank”的警告信息。与大多数成熟的面向对象语言不同的是,在Javascript中,你不必为一个对象实例创建类或蓝图。你可以像这里所写的那样,在运行时创建它。在对象的整个生命周期中都可以这么做。在网页中,这就意味着你可以在任何时候给对象添加属性和方法。

事实上,Javascript实现只是把所有对象当作关联数组。然后给数组加上了一个面具,使它的语法看起来更像JAVA或C++,使用点分隔法表示。为了强调这一点,你可以像这样检索newObject中firstName字段的值:


var theFirstName = newObject["firstName"];

同样,可以这样调用sayName()函数:


newObject["sayName"]();

这个简单的东西可以算是很多强大功能的基础。比如,假如你想基于某种逻辑调用某个对象的方法又如何呢?噢,你可以这么做:


var whatFunction;

 if(whatVolume == 1){

  whatFunction = "sayName";

}

if(whatVolume == 2){

  whatFunction = "sayLoudly";

}

假设我们已经将函数sayLoudly()添加到newObject,这个函数在firstName字段中的alert()之前调用toUpperCase(),然后我们可以基于一个变量的值,来控制对象“大声”(全部大写)地或者“温柔”(如上所示,全部小写)地说出名字。

当向一个对象添加函数的时候,你可以使用已存在的函数。作为例子,让我们来继续添加那个sayLoudly()函数:


function sayLoudly(){

  alert(this.firstName.toUpperCase());

}

newObject.sayLoudly = sayLoudly;

请注意这里的this关键字的使用方法。可以说,它指向的对象将会在运行时动态计算。因此,在这个例子中,this指向的是函数sayLoudly()作为其成员的那个类——这里是newObject。有意思的是,如果sayLoudly()完全是另一个对象的一部分,关键字this就会引用另一个对象。这种运行时绑定也是Javascript面向对象实现的一个非常强大的特性,因为它允许代码的共享,本质上来说,是一种继承的形式。

2.1.2 使用JSON创建对象(参考《JSON入门指南》

由于JSON(Javascript Object Notation,Javascript对象表示法)在Ajax请求中的使用而被越来越广泛的关注,所以很多人了解了它。然而,一些人还并不知道JSON实际上是Javascript规范中的一个核心部分,而且它在Ajax登台之前就已经存在了。它的最初目的是为了快速简便地定义复杂的对象关系图,也就是那些嵌套于其他对象中的对象的实例。虽然它看上去是如此的简单,但它允许了创建对象的另外一种方式。

还记得我们曾说过,Javascript里的对象只是隐藏在面具下的关联数组吗?这就是JSON可运转的因素。让我们来看看如何使用JSON来创建前面例子中的newObject:


function sayLoudly(){ 

  alert(this.firstName.toUpperCase());

}

 

var newObject ={

firstName:"Frank",

sayName:function(){alert(this.firstName);},

sayLoudly:sayLoudly

};

使用JSON和定义一个数组非常相似,除了你需要使用花括号而不是方括号。注意函数可以是内联的,也可以引用外部函数。(看到sayLoudly可能有一些困惑,但是Javascript理解为第一个sayLoudly是对象的一个成员,而第二个sayLoudly
是对一个已存在的对象的引用。)

在JSON中,你可以随意地嵌套对象定义来创建对象的层级关系。例如,我们向newObject中添加一个名为LastName的对象:

function sayLoudly(){ 

  alert(this.firstName.toUpperCase());

}

 

var newObject ={

firstName:"Frank",

sayName:function(){alert(this.firstName);},

sayLoudly:sayLoudly,

LastName:{

  lastName:"Zammetti",

  sayName: function(){alert(this.lastName);}

  }

};

然后,你可以通过下面的调用来显示姓的部分:


newObject.LastName.sayName();

2.1.3 类的定义
在Javascript中,其实所有的东西都是一个对象。这是事实,只有一小部分例外,比如一些内置的原语。这部分讨论的最重要的一点是,函数本身就是对象。你已经了解到如何创建一个Object的实例,并向其中添加属性和方法了,但是那意味着每次创建对象的一个新实例时,你实际上都需要从零开始创建。这里肯定有更好的方法,不是吗?当然有:创建一个类。

在Javascript中,类实际上就是一个函数。这个函数同样被当作类的构造函数来提供服务。那么例如,让我们把newObject写作一个类,重命名为newClass:


function newClass(){

  alert("constructor");

  this.firstName = "Frank";

  this.sayName = function(){

    alert(this.firstName);

}

var nc = new  newClass();

nc.sayName();

}

执行这段代码时,你会先后看到两个警告信息:首先,当执行到var nc = new  newClass();这行的时候,弹出“constructor”,然后,当执行到nc.sayName();这行的时候弹出“Frank”。你想要创建多少newClass的实例就可以创建多少,而且它们将会含有同样的属性和方法。一旦创建,他们还将弹出同样的警告信息,firstName含有同样的初始值。简而言之,你为创建newClass对象创建了一个蓝图,你定义了一个类。

但是,由此引出的一个问题是:newClass的每一个实例都含有firstName的一个副本和sayName方法的一个副本,那么每个实例都占用两个更多的内存。newClass的每个副本都有各自的firstName副本,这个可能是你想要的,但是如果所有的实例都可以共享相同的sayName()副本的话,是不是更好了,能否节省些内存?很明显,在这个例子中,我们并不能有大量的内存节省,但是你可以设想一些更大的代码的情况,那些场合中,很可能差别就更大了。幸运的是,有一种方法可以这样做。

2.1.4 原型

Javascript中的每一个独立的对象都有一个与之关联的原型(prototype)属性。在我所知道的其他语言中,并没有与prototype完全相等的东西,但是它可以被看作一个简化的继承形式。基本上,它工作的方式是:当你构造一个对象的新实例时,定义在对象原型中的所有属性和方法,在运行时都会附着在那个新的实例上。

我知道,第一次看到这个概念时,可能有一些难以理解,但幸运的是,它很容易演示:


function newClass(){ 

  this.firstName = "Frank";

}

newClass.prototype.sayName = function(){

  alert(this.firstName);

}

var nc = new newClass();

nc.sayName();

执行的时候,这个代码会弹出同样的警告信息说“Frank”。与前面的例子不同的是,无论你创建了多少个newClass的实例,在内存中sayName()函数只会有一个单独的实例。这个方法实际上是附加在每个实例上,而且this关键字还是在运行时被计算的。所以this通常指向它所属的那个特定的newClass实例。例如,如果你有两个newClass的实例分别叫做nc1和nc2,然后一个对nc1.sayName()的调用将this指向nc1,一个对nc2.sayName()的调用将this指向nc2。

2.1.5 你应该使用哪种方法呢

前面所说的每个方法都有各自的优点和缺点,而且我怀疑是否存在孰好孰坏的共识。它们在功能都是相同的,所以很大程度上它取决于你更喜欢代码看起来像什么样子。也就是说,我想有一些常用的准则来帮助你。

最重要的一个可能是,如果你要创建一个类,这个类非常大,而且它可能会有复杂的实例,那么几乎可以肯定要使用原型的方法。这样可以带来最好的内存使用效率,这通常是一个重要的目标。

如果你要创建一个单独的类而且知道这个类将只有一个实例,我个人会倾向定义一个类。对我来说,这样的代码是逻辑化最强、最类似于更全面的面向对象语言的,因此可能更易于项目中的新开发人员理解。

如果(a)你的对象层级关系嵌套层次很多和/或(b)你需要在一个动态方式中定义一个对象(一段逻辑代码的输出结果),那么,JSON方法可能是一个好的选择。如果需要将对象序列化并且通过网络进行传输,JSON也几乎非常明显是首选。如果你需要重构一个从服务器传来的对象时也是如此。我怀疑做这些事情的时候,没有比JSON更简单的方法,这不是小范围的怀疑,而是因为这些事情就是设计JSON 的目的。

2.1.6 面向对象的好处

无论你选择哪种方法,将代码面向对象化都有很多好处。一个重要的好处就是,每一个对象本质上就是一个命名空间。可以用此来模拟Java和C#的包,就像在下一章中会看到的。

另一个好处是可以使用对象来隐藏数据。看看下面的代码:

 

function newClass(){

  this.firstName = "Frank";

  lastName = "Zammetti";

}

var nc = new newClass();

alert(nc.firstName);

alert(nc.lastName);

执行这段代码会有两个警告信息:第一说“Frank”,第二个说“undefined”。这是因为lastName字段在lastName的实例外是不可访问的。请注意字段定义的不同。任何使用this关键字定义的字段,比如firstName那样,都可以在类之外访问。而任何没有this关键字定义的字段,都只能在类的内部访问。这个规则对于方法也同样适用

同样,不要忘记Javascript的内置对象可以通过使用它们的原型来扩展,事实上,Javascript的名为Prototype的库就是在做这个事情,这些你将会在2.6节中看到。但是,如果不小心的话,你真的可能把事情搞糟,所以扩展内置对象时要谨慎。

你可以从其他的对象中“借”函数,并把它们添加到自己的对象中。例如,假设你想要通过输出newClass本身来显示newClass的firstName字段。为实现这个目标,你实现了一个toString()函数。再假设你还想在它上面使用String对象中的toUpperCase()函数。很简单,我们可以这样做:

 


function newClass(){

  this.firstName = "Frank";

  this.toUC = String.toUpperCase;

  this.toString = function(){

  return this.toUC(this.firstName);

  }

}

var nc = new newClass();

alert(nc);

 执行这段代码,结果是一个警告提示说“Frank”.注意调用了toString()函数,但并不是作为firstName String对象的一个方法。取而代之的,是通过指向它的一个引用调用的,这个引用是newClass的属性之一,名为toUC。这是一个很好的功能,尤其是当你创建自己的对象之后,又想创建一个新的,并使用原来的代码。那你不用复制、剪切及粘贴,只需引用其他类里的已存在的方法就可以了。

jQuery性能优化指南(2)

4,对直接的DOM操作进行限制

这里的基本思想是在内存中建立你确实想要的东西,然后更新DOM 。
这并不是一个jQuery最佳实践,但必须进行有效的JavaScript操作,直接的DOM操作速度很慢。

例如,你想动态的创建一组列表元素,千万不要这样做,如下所示:


var top_100_list = [...], // 假设这里是100个独一无二的字符串

$mylist = $("#mylist"); // jQuery 选择到 <ul> 元素

for (var i=0, l=top_100_list.length; i<l; i++){
  $mylist.append("<li>" + top_100_list[i] + "</li>");
}

我们应该将整套元素字符串在插入进dom中之前先全部创建好,如下所示:

var top_100_list = [...],$mylist = $("#mylist"), top_100_li = "";
// 这个变量将用来存储我们的列表元素

for (var i=0, l=top_100_list.length; i<l; i++){
   top_100_li += "<li>" + top_100_list[i] + "</li>";
}

$mylist.html(top_100_li);

注:记得以前还看过一朋友写过这样的代码:


for (i = 0; i < 1000; i++) {

    var $myList = $("#myList");

    $myList.append("This is list item" + i);

}

呵呵,你应该已经看出问题所在了。竟然把#mylist循环获取了1000次!!!

5,冒泡

除非在特殊情况下, 否则每一个js事件(例如:click, mouseover等.)都会冒泡到父级节点。
当我们需要给多个元素调用同个函数时这点会很有用。

代替这种效率很差的多元素事件监听的方法就是, 你只需向它们的父节点绑定一次。

比如, 我们要为一个拥有很多输入框的表单绑定这样的行为: 当输入框被选中时为它添加一个class。传统的做法是,直接选中input,然后绑定focus等,如下所示:


$("#entryform input").bind("focus", function(){
    $(this).addClass("selected");
}).bind("blur", function(){
    $(this).removeClass("selected");
});

当然上面代码能帮我们完成相应的任务,但如果你要寻求更高效的方法,请使用如下代码:


$("#entryform").bind("focus", function(e){
    var $cell = $(e.target); // e.target 捕捉到触发的目标元素
    $cell.addClass("selected");
}).bind("blur", function(e){
    var $cell = $(e.target);
    $cell.removeClass("selected");
});

通过在父级监听获取焦点和失去焦点的事件,对目标元素进行操作。
在上面代码中,父级元素扮演了一个调度员的角色, 它可以基于目标元素绑定事件。
如果你发现你给很多元素绑定了同一个事件监听, 那么现在的你肯定知道哪里做错了。

伟大啊伟大,抄书的徐小花到此一游!!!

同理,在Table操作时,我们也可以使用这种方式加以改进代码:
普通的方式:


$("#myTable td").click(function(){
    $(this).css("background", "red");
});

改进方式:


$("#myTable").click(function(e) {
     var $clicked = $(e.target);
     $clicked.css("background", "red");
});

假设有100个td,在使用普通的方式的时候,你绑定了100个事件。
在改进方式中,你只为一个元素绑定了1个事件。
至于是100个事件的效率高,还是1个事件的效率高,相信你也能自行分辨了。

6,推迟到 $(window).load

jQuery对于开发者来说有一个很诱人的东西, 可以把任何东西挂到$(document).ready下。
尽管$(document).rady 确实很有用, 它可以在页面渲染时,其它元素还没下载完成就执行。
如果你发现你的页面一直是载入中的状态,很有可能就是$(document).ready函数引起的。

你可以通过将jQuery函数绑定到$(window).load 事件的方法来减少页面载入时的CPU使用率。
它会在所有的html(包括iframe)被下载完成后执行。


$(window).load(function(){
    // 页面完全载入后才初始化的jQuery函数.
});

一些特效的功能,例如拖放, 视觉特效和动画, 预载入隐藏图像等等,都是适合这种技术的场合。

7,压缩JavaScript

压缩和最小化你的JavaScript文件。

在线压缩地址: http://dean.edwards.name/packer/
压缩之前,请保证你的代码的规范性,否则可能失败,导致Js错误。

英文原文:http://www.artzstudio.com/2009/04/jquery-performance-rules/
中文翻译:http://rlog.cn/350 & http://cssrain.cn

jQuery性能优化指南(1)

强烈推荐这一系列的文章,它们让我从根本上理解和开始思考一些以前自己未曾注意到的问题。或许对牛人来说这些问题微不足道,我却受益匪浅啊哇哈哈哈。

1、总是从ID选择器开始继承
 在jQuery中最快的选择器是ID选择器,因为它直接来自于JavaScript的getElementById()方法。
例如有一段HTML代码:

<div id="content">
<form action="#" enctype="application/x-www-form-urlencoded" method="post">
<h2>交通信号灯</h2>
<ul id="traffic_light">
 <li>
  <input class="on" name="light" type="text" value="red" /> 红色
 </li>
 <li>
  <input class="off" name="light" type="text" value="yellow" /> 黄色
 </li>
 <li>
  <input class="off" name="light" type="text" value="green" /> 绿色
 </li>
</ul>
 <input id="traffic_button" class="button" type="text" value="Go" />
</form>
</div>

如果采用下面的选择器,那么效率是低效的。


var traffic_button = $("#content .button");

因为button已经有ID了,我们可以直接使用ID选择器。如下所示:


var traffic_button = $("#traffic_button");

当然,这只是对于单一的元素来讲。如果你需要选择多个元素,这必然会涉及到 DOM遍历和循环,为了提高性能,建议从最近的ID开始继承。

如下所示:

 


var traffic_lights = $("#traffic_light input");

2,在class前使用tag(标签名)

在jQuery中第二快的选择器是tag(标签)选择器( 比如:$(”head”) )。
跟ID选择器类似,因为它来自源生的getElementsByTagName() 方法。

继续看刚才那段HTML代码:

<div id="content">
<form action="#" enctype="application/x-www-form-urlencoded" method="post">
<h2>交通信号灯</h2>
<ul id="traffic_light">
 <li>
  <input class="on" name="light" type="text" value="red" /> 红色
 </li>
 <li>
  <input class="off" name="light" type="text" value="yellow" /> 黄色
 </li>
 <li>
  <input class="off" name="light" type="text" value="green" /> 绿色
 </li>
</ul>
 <input id="traffic_button" class="button" type="text" value="Go" />
</form>
</div>

比如需要选择 红绿 单选框,
那么可以使用一个tag name来限制(修饰)class ,如下所示:

var active_light = $("input.on");

当然也可以结合 就近的ID,如下所示:

var active_light = $("#traffic_light input.on")

在使用tag来修饰class的时候,我们需要注意以下几点:

(1) 不要使用tag来修饰ID,如下所示:

var content = $("div#content");

这样一来,选择器会先遍历所有的div元素,然后匹配#content。
(好像jQuery从1.3.1开始改变了选择器核心后,不存在这个问题了。暂时无法考证。)

(2)不要画蛇添足的使用ID来修饰ID,如下所示:

var traffic_light = $("#content #traffic_light");

注:如果使用属性选择器,也请尽量使用tag来修饰,如下所示:

$('p[row="c3221"]').html();

而不是这样:

$('[row="c3221"]').html();

3,将jQuery对象缓存起来

把jQuery对象缓存起来,就是要告诉我们:要养成将jQuery对象缓存进变量的习惯

下面是一个jQuery新手写的一段代码:

$("#traffic_light input.on").bind("click", function(){ … });
$("#traffic_light input.on").css("border", "1px dashed yellow");
$("#traffic_light input.on").css("background-color", "orange");
$("#traffic_light input.on").fadeIn("slow");

但切记不要这么做。

我们应该先将对象缓存进一个变量然后再操作,如下所示:

var $active_light = $("#traffic_light input.on");
$active_light.bind("click", function(){ … });
$active_light.css("border","1px dashed yellow");
$active_light.css("background-color", "orange");
$active_light.fadeIn("slow");

记住,永远不要让相同的选择器在你的代码里出现多次.

注:(1)为了区分普通的JavaScript对象和jQuery对象,可以在变量首字母前加上 $ 符号。
(2)上面代码可以使用jQuery的链式操作加以改善。如下所示:

var $active_light = $("#traffic_light input.on");
$active_light.bind("click", function(){ … })
.css("border", "1px dashed yellow")
.css("background-color", "orange")
.fadeIn("slow");

如果你打算在其他函数中使用jQuery对象,那么你必须把它们缓存到全局环境中。
如下代码所示:

// 在全局范围定义一个对象 (例如: window对象)

window.$my = {

head : $("head"),

traffic_light : $("#traffic_light"),

traffic_button : $("#traffic_button")

};

function do_something(){

// 现在你可以引用存储的结果并操作它们

var script = document.createElement("script");

 $my.head.append(script);

// 当你在函数内部操作是, 可以继续将查询存入全局对象中去.

$my.cool_results = $("#some_ul li");

$my.other_results = $("#some_table td");

 // 将全局函数作为一个普通的jquery对象去使用.

$my.other_results.css("border-color", "red");

 $my.traffic_light.css("border-color", "green");

}

//你也可以在其他函数中使用它

转自http://www.cssrain.cn/article.asp?id=1351

YUI Grids CSS初探

网络上一直对YUI的Grids CSS赞誉有加,认为其简洁而优雅,使快速对网页进行标准化布局成为一种可能。Grids CSS的卓越特性包括:

同时支持100%流式布局和4种固定宽度的布局(分别是750px、950px、974px和自定义宽度);

对固定宽度的布局来说,自定义宽度非常简单;

能够使用户灵活地调节字体大小;

模板内各栏(columns)的排列顺序独立,也就是说在代码中,你可以随意放置你认为最重要的东西在前以利于网页可用性和SEO。——翻译的不到位,意思是明白,原文如下:

  • Template columns are source-order independent, so you can put your most important content first in the markup layer for improved accessibility and search engine optimization (SEO).

页脚会自动清除浮动,无论正文区各栏的高度是多少,页脚总保持在网页最下方。

如果布局宽度小于100%将自动进行水平居中。

4k的css文件支持>1000种页面布局。

适应所有IAB广告标准。

学习资料:

YUI官方的视频和文字教程:http://developer.yahoo.com/yui/grids/

YUI CSS Grid Builder:http://developer.yahoo.com/yui/grids/builder/

已破解可下载源码的YUI CSS Grid Builder:http://williamduff.name/YahooPages/

YUI CSS Grid 布局原理:http://hikejun.com/sharing/share_grids/slide.html 简明扼要,E文不好的童鞋通过看这个文档以及YUI官方提供的cheatsheet,自己做几个实验就基本可以学会了。

要点备忘录:

1、关于web标准:YUI Grids CSS默认使用”DOCTYPE HTML PUBLIC “-//W3C//DTD HTML 4.01//EN” “http://www.w3.org/TR/html4/strict.dtd”。

2、默认字体大小13px,需要调节时按百分比换算,基本换算的值cheatsheet上有。

3、理解YUI Grids CSS的基本结构:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
	<title>YUI Grids CSS </title>
	<!-- Source File -->
	<link rel="stylesheet" type="text/css" href="reset-fonts-grids.css">
</head>
<body>
<div id="doc">
   <div id="hd"><!-- header --></div>
   <div id="bd"><!-- body --></div>
   <div id="ft"><!-- footer --></div>
</div>
</body>
</html>

分为页头、页脚和中间内容三个div,由ID去定义它们在网页中的角色,最外面再由一个div包裹起来。

4、YUI Grids CSS里的一些基本ID和class:

  • 最外层的div 将决定页面宽度并为页面选择模板:
    id决定页面宽度,id=”doc”(750px)  id=”doc2″(950px)  id=”doc3″(100%)  id=”doc4″(”974px”)  id=”doc-custom”(自定义宽度)。
    class为页面选择模板。YUI Grids CSS认为所有页面都可以划分为”main block”和”secondary block”的左右分栏布局。有”yui-t1″至 “yui-t6″6种分栏模板可选,以此来决定页面边栏(secondary block)的位置和大小。
  • 页头、页脚和中间内容三个div的id分别为”hd”,”bd”,”fd”。
  • 既然已经选择好模板,下一步将为中间内容(id=”bd”)划分区块(class=”yui-b”),主要区块(main block)由id=”yui-mian”的div来标识。
    grids-docs-3
    以下是代码示例:

    <div id="doc" class="yui-t4"><!--定义页面宽度为750px,边栏在右侧宽度180px-->
    <div id="hd">页头</div>
    <div id="bd">
    <div id="yui-main"><!--用"yui-main"标识主要内容区块(main block)的div-->
    <div class="yui-b">主要内容区块</div>
    </div>
    <div class="yui-b">边栏区块</div>
    <!--边栏(secondary block)宽度由"yui-tx"系列class来决定--></div>
    <div id="fd">页脚</div>
    </div>

    这样一个基本的左右分栏页面布局就出来了。

  • 在区块(class=”yui-b”,b for block)内可以再进行网格分栏,这时需要用到”class=yui-g”至”class=yui-gf”的网格工具来实现。比如在主要区块(main block)再划分宽度为2:1的两栏:
    <div id="doc" class="yui-t4"><!--定义页面宽度为750px,边栏在右侧宽度180px-->
    <div id="hd">页头</div>
    <div id="bd">
    <div id="yui-main"><!--用"yui-main"标识主要内容区块的div-->
    <div class="yui-b">
    <div class="yui-gc">
    <div class="yui-u first">main block内第一个栏,宽度为2/3</div>
    <div class="yui-u">main block内第二个栏,宽度为1/3</div>
    </div>
    </div>
    </div>
    <div class="yui-b">次要内容区块</div>
    <!--宽度由"yui-tx"系列class来决定--></div>
    <div id="fd">页脚</div>
    </div>
  • 理解yui-u(u for unit)。可以将yui-u理解为放在网格(class=”yui-g”,g for grid)内的格子,它们是通用的,没有宽度,属性完全继承自网格(yui-g)。
  • first和section。first有点像目前主流CSS框架里的last,作用是标识第一个格子元素。section可理解为“段”,有清除浮动的作用。

以上为下午学习YUI Grids CSS的学习笔记。由于没有实际应用,只是简单做了几个测试demo,以上的理解可能会有偏差,欢迎指正!

ifixpng——解决IE6及以下版本不支持透明PNG图像问题的Jquery插件

一个可以使IE6及以下版本支持透明PNG图像的Jquery插件,使用起来很方便,支持透明PNG图像及背景,支持连缀,不会改动页面的任何html标签,可复原(偶尝试了下不成功哈,查看Jquery官网发现该方法被作者移除了)。

原作者文档:http://jquery.khurshid.com/ifixpng.php

Jquery官网文档:http://plugins.jquery.com/project/iFixPng2

本人demo一枚:http://blog.cargoo.net/ifixpng_below_ie6_2.html

注意事项:该插件自带一个pixel.gif的图像,是必须的,其默认路径是images/pixel.gif,你也可以更改这个路径,具体做法如:

$.ifixpng(”新路径/pixel.gif”);

JS脚本备忘更新

滑门脚本

标签卡效果脚本

网格生成器、模版和更多工具

手风琴脚本

菜单脚本

50个最新的jquery实用技术和教程合集:http://www.smashingmagazine.com/2009/08/23/50-useful-new-jquery-techniques/

常用脚本demo搜集整理

忙了好几天,以至于看到电脑有种莫名的心理障碍。明天就是伟大滴国际劳动节了,下午不太想工作,而是想整理一下这段日子接触过的一些比较有用的,常用的脚本。光知道完成任务而没有总结和积累是不行滴。因为一旦停下来,就随时有可能忘光光。

图片等比例缩放

DIV等高处理

Javascript 切换页面 CSS 样式

图片放大镜效果

1KB的JS TAB脚本 帕兰映像

图片先模糊后清楚 以前一直不知道这样做的意义所在,现在终于懂了,笨。