javascript的一些小知识点

以下是我在学习过程中遇到的一些javascript的小知识点,保存下来以供参考,持续更新中。。

   1、eval函数的作用域

eval 函数会在当前作用域中执行一段 JavaScript 代码字符串。但是 eval 只在被直接调用并且调用函数就是 eval 本身时,才在当前作用域中执行。如果执行了类似于 f = eval; f(); 这样的语句,将等价于在全局作用域中调用 eval,例如下面的这段代码:

(原文来自《javascript秘密花园》:http://bonsaiden.github.com/JavaScript-Garden/zh/#core.eval

 1     var a = 0 ;
 2     var f1 = function() {
 3         var a = 1 ;
 4 
 5         eval("a = 2") ;     // 由于是直接调用eval函数,因此此时eval函数的作用域是当前作用域
 6         console.log(a) ;    // 2,在eval函数中修改了局部变量a
 7     };
 8     f1() ;
 9     console.log(a) ;        // 0,全局变量a没有被修改
10 
11     var b = 0 ;
12     var f2 = function() {
13         var b = 1 ;
14         var f3 = eval ;
15 
16         f3("b = 2") ;       // 由于这里将eval函数的引用赋值给了变量f3,并通过f3调用了eval函数,因此此时该函数的作用域是全局作用域
17         console.log(b) ;    // 1,局部变量a没有被修改
18     }
19     f2() ;
20     console.log(b) ;        // 2,在eval函数中修改了全局变量a

 

   2、querySelector和getElementById的区别

querySelector和getElementById的区别在于,querySelector的参数须是符合 css selector 的字符串,例如对于下面的这个div,用getElementById可以获取,但是querySelector就获取不到了:

(参考出处:http://www.jb51.net/article/30132.htm

1 <!DOCTYPE html>
2 <html>
3     <head>
4         <meta charset="utf-8" />
5     </head>
6     <body>
7         <div id="1"></div>
8     </body>
9 </html>

输出结果如下:

1 var div = document.getElementById("1");
2 console.log(div);
3 // =>  <div id="1"></div>
4 
5 var target = document.querySelector("#1");
6 console.log(target);
7 // => Uncaught Error: SYNTAX_ERR: DOM Exception 12

 

   3、querySelectorAll和getElementsByClassName的区别

querySelectorAll和getElementsByClassName的区别在于querySelectorAll返回的是一个叫做StaticNodeList的新类型的实例。

顾名思义,StaticNodeList有NodeList所有的属性和方法,但是它底层的实现是元素集合的一个快照,而非总是要重新的针对文档的动态查询。使用StaticNodeList消除了大部分使用NodeList对象带来的性能问题。

只要调用querySelectorAll()都会返回一个StaticNodeList对象不管匹配的元素有几个;如果没有匹配,那么StaticNodeList为空。querySelectorAll()和querySelector()一样存在与Document和Element类型上。

话不多说,上代码:(原文来自:http://www.poluoluo.com/jzxy/201204/163845.html

 1 <!DOCTYPE>
 2 <html>
 3     <head>
 4         <meta charset="utf-8" />
 5         <title>querySelectorAll和getElementsByClassName的区别</title>
 6     </head>
 7     <body>
 8         <div class="a"></div>
 9         <div class="a"></div>
10         <div class="a"></div>
11         <div class="a"></div>
12         <div class="a"></div>
13         <div class="a"></div>
14     </body>
15 </html>

对于上面的7个div,分别通过querySelectorAll和getElementsByClassName获取它们,然后改变其中一个div的class值,观察两个集合的结果有没有发生变化:

 1 var div = document.getElementsByClassName("a");
 2 console.log(div);
 3 // => [<div>, <div>, <div>, <div>, <div>, <div>]
 4 
 5 var target = document.querySelectorAll(".a");
 6 console.log(target);
 7 // => [<div>, <div>, <div>, <div>, <div>, <div>]
 8 
 9 div[3].className = "b"; //改变第四个div的class值
10 
11 console.log(div);
12 // => [<div>, <div>, <div>, <div>, <div>]
13 // 动态NodeList显示出变更后的div集合
14 
15 console.log(target);
16 // => [<div>, <div>, <div>, <div>, <div>, <div>]
17 // StaticNodeList显示的还是变更前的div集合

 

   4、使用undefined不为人知的秘密

 在jQuery的源码中,其外层沙箱和命名空间大致是这样写的:

(原文来自:http://blog.raphealguo.com/2013/01/17/jquery-src-util/

1 (function(window, undefined) {
2     ...
3 
4     window.jQuery = window.$ = jQuery;
5 
6 }(window, undefined));

这里最外层的匿名函数使用undefined作为第二个参数的原因,是因为在jQuery中有一个针对压缩的小小策略,先看以下代码:

1 (function( window, undefined ) {
2   var a = undefined;
3   if (a == undefined){blabla...}
4  
5   ....
6   if (c == undefined) return;
7 })( window );

经过压缩后,可以变成:

1 (function(w, u) {
2   var a = u;
3   if (a == u){blabla...}
4  
5   ....
6   if (c == u) return;
7 })(w);

因为这个外层函数只传了一个参数,因此沙箱执行时,u自然会undefined,把9个字母缩成1个字母,可以看出压缩后的代码减少一些字节数。

 这样做还有另外一个原因:由于在ECMAScript5之前undefined并不是ECMAScript中的关键字,即undefined是可以用作变量名的,也就是undefined是可以赋值的。例如下面所示的这段代码:

1 var undefined = "zhaojian";
2 
3 (function() {
4     console.log(undefined);   
5 }());

这段代码在ES5之前是合法的,控制台输出的结果可能会是zhaojian而非undefined。因此将undefined作为参数传入的用处就是防止某些2B程序员对undefined进行赋值,并且即使某个2B程序员真的这么做了,那么这样做的影响也只局限于这一块代码的范围,不会影响到全局范围内其他人的代码。

 

   5、深入理解形参、实参与arguments

arguments对象的值只与实参有关,而与实参无关,arguments与形参的关系是通过实参联系起来的。

先来看看下面的几道面试题:(原文出自:http://hi.baidu.com/flondon/item/544b53b5d4872870254b0999

 1 function tmp(x) {
 2     x = 10;
 3     console.log(arguments[0]);
 4 }
 5 tmp(1);
 6 
 7 function tmp(x) {
 8     arguments[0] = 10;
 9     console.log(arguments[0]);
10 }
11 tmp(1)
12 
13 function tmp(x) {
14     arguments[0] = 10;
15     console.log(arguments[0]);
16 }
17 tmp();
18 
19 function tmp(x) {
20     x = 10;
21     console.log(arguments[0]);
22 }
23 tmp();
24 
25 function tmp(x, y) {
26     y = 10;
27     console.log(arguments[1]);
28 }
29 tmp(1);

 在上面的五道题中,前两道的答案都为10,后三道的答案都为undefined。关于该答案的要点分析如下:

1、如果函数调用时没有参数传入,那么arguments对象为空(已经声明,但没有元素,并且不指向任何内存单元)。

2、如果函数调用时有参数传入,那么arguments对象和相应的形参同时指向这些传入值的内存单元,此时,对arguments对象中的元素或者函数形参的任何赋值都会直接体现到彼此(因为它们的值存储于同一块内存)。

3、当输入的参数少于形参数目时,其他形参(未传入实参)值的改变不影响arguments的值(如代码段5)。

   6、for in 遍历稀疏数组的问题

在使用for in方式遍历数组的时候,它会在遍历过程中跳过没有定义的数组位置。例如下面的代码:

1 var arr = [];
2 arr[1] = 1;                          // arr = [undefined, 1]
3 console.log(0 in arr);                // false
4 console.log(arr.indexOf(undefined));  // -1
5 console.log(arr[0] === undefined);    // true

对于上面的数组,js认为它的第一项是不存在的,虽然它有一个undefined的默认值,但是如果用indexOf去寻找值为undefined的数组元素,返回的结果是找不到(-1)。

上面的是正常的情况,但是有正常就有不正常,例如下面的代码:

1 var arr = [undefined, 1];              // arr = [undefined, 1]
2 console.log(0 in arr);                  // true
3 console.log(arr.indexOf(undefined));    // 0
4 console.log(arr[0] === undefined);      // true            

对于这里的数组,js认为它的第一项是存在的,虽然它的值也为undefined,而且如果用indexOf去寻找值为undefined的数组元素是能找到的(返回结果为0)。

因此可以得出结论,虽然上面的两个数组从外表上看起来一模一样,但是第二个数组中的undefined值是显式声明的,而第一个数组中的undefined值是隐式声明的,所以for in会忽略隐式声明的undefined数组元素,而把显示声明的数组元素作为正常的数组元素来看待

 

 

posted @ 2012-10-24 23:43  CyrilZhao  阅读(264)  评论(0编辑  收藏  举报