代码改变世界

(二)解决前6条

2012-02-12 14:37  kwjlk  阅读(417)  评论(1)    收藏  举报

1.window.undefined = window.undefined

make the global window.undefined as real undefined value.

未定义,当属性没有定义过(不存在)时访问该属性则会返回值:未定义。虽然window.undefined一定会被浏览器定义成了"未定义"的值,但是谁会知道哪个别有用心的浏览器(火狐)是个例外呢。所以,这一段代码做了双重保证。定义了window.undefined属性为未定义的浏览器中执行这一句代码没有任何改变,在没有定义window.undefined属性的浏览器中执行后window.undefined 则会被定义并且赋值成未定义。网上有提到,对于没有定义window.undefined属性的浏览器判断一个是否是未定已要使用如下判断 if(window.p == 'undefined')。

 

2.对$元符号的处理。

// Map over the $ in case of overwrite
if ( $ )
jQuery._$ = $;
// Map the jQuery namespace to the '$' one
var $ = jQuery;

如果已经定义过美元符号了,则将已经定义存在的美元符号赋值到jQuery._$上。然后重新定义美元符号$为jQuery。这里需要特别的注意在将jQuery赋值到$上时使用了var 重新定义$美元符号的语法。否则将会把jQuery._$一起覆盖:

// Map over the $ in case of overwrite
if ( $ )
jQuery._$ = $;
// Map the jQuery namespace to the '$' one
$ = jQuery; //这一句将会导致 jQuery._$ = $ = jQuery的效果,而不是 jQuery._$ = old $ , $ = jQuery 的效果。

 

3.jQuery(a,c) 与 jQuery.fn = jQuery.prototype = { ... }

看着看着发现,jQuery(a,c)中的实现引用了后面定义的很多函数,而jQuery.fn = jQuery.prototype = {...}中代码量也很大,而且也引用到了后面定义的函数。相反,jQuery.extend 的定义则相对简单很多,于是选择阅读jQuery.extend中的代码。

 

4.jQuery.extend 方法

在分析jQuery.extend之前,我们需要理解jQuery.fn = jQuery.prototype ={ ... } 的写法

js中的prototype在面向对象方面有很大作用。你可以在网上查阅一下这方面的相关资料。经由jQuery.fn = jQuery.prototype = { ... } 我们在之后对jQuery拓展方法时就可以使用 jQuery.method = jQuery.fn.method = function(){ ... }的形式了。jQuery.method 仅会让方法成为jQuery本身的方法,而jQuery.fn.method则仅会让方法成为jQuery对象的方法。两者同时使用才会达到jQuery自身和jQuery对象同时拥有该方法的效果。我们通过如下代码来演示这种效果:

function jQuery(){} // 一个空的叫做jQuery的类型

var omygod = function(){alert('God bless you.');} //定一个函数

jQuery.me = omygod;

alert(jQuery.me); // 弹窗显示 function(){alert('God bless you.');}
var jq = new jQuery();
alert(jq.me); // 弹窗显示 undefined

jQuery.fn = jQuery.prototype;
jQuery.fn.me = omygod;
alert(jq.me); // 弹窗显示 function(){alert('God bless you.');}

jQuery.fn.you = 'hi'
alert(jq.you) // 弹窗显示 hi
alert(jQuery.you) //弹窗显示 undefined

如果你有更多的疑问点,请提出你的问题或者自行编写代码进行验证。

接下来我们看一下jQuery中伟大的extend方法,这个方法功能强大实现怎么可能是这样的?

jQuery.extend = jQuery.fn.extend = function(obj,prop) {
if ( !prop ) { prop = obj; obj = this; }
for ( var i in prop ) obj[i] = prop[i];
return obj;
};

真是不知者有罪啊,如果不知道怎么实现的将会造成多大的罪孽。——by kwjlk

jQuery.extend实现虽然简单,但是其强大的功能正是印证了js的强大。首先这里面有三个重要点:

  1. js中的真假世界观,即if(!prop)的判断何时是if(true)何时是if(false)。
  2. js中可以以数组形式访问和赋值对象的属性。
  3. js 中 for..in 数组遍历(基于第二点,则也可以遍历对象的属性)

 

对于第一点,在js中 null , undefined , false , 字符串空,数字0 均为false,非false则为true。

接下来研究如上代码的实现逻辑。首先第一个判断if(!prop){prop = obj,obj = this} 这是的当!prop计算为真(一般为没有传入prop参数)时则将obj对象的属性拓展到extend的调用者身上。接下来我们通过代码分析extend的可能调用场景:

先看如下两段代码:

第一段代码:

var obj = {}
obj['name'] = 'object';
alert(obj.name); // 弹窗显示 object
var nonObj = "12";
nonObj['name'] = 'none object';
alert(nonObj.name); //弹窗显示 none object

以上代码说明,对于非对象性的变量,使用var['key'] = 'value' 的形式并不报错,但是调用var.key时key是undefined。这就是,在extend真正对变量进行属性拓展时,如果目的变量是非对象变量则等同于没有做任何操作。于是在讨论中可以把extend最终作用对象分为对象和非对象,而对非对象的讨论则没有意义。至于那些是非对象呢?我们通过如下代码展示:

//此段代码有待商榷,希望有志认识能够提供指正
var nonObj;
nonObj = null;
nonObj = undefined;
nonObj = 'this is a string';
nonObj = 100;
nonObj = 100.9;
nonObj = ture;
nonObj = false;

 

 

第二段代码:

var nonObj;
nonObj = null;
nonObj = undefined;
nonObj = 100;
nonObj = 100.9;
nonObj = ture;
nonObj = false;
for(var i in nonObj){
alert('not here'); //这段代码不会被执行
}
nonObj = 'st';
for(var i in str){
alert(i+'-'+str[i]); // 弹窗显示 0-s 1-t
}
nonObj[1] = 'b';
alert(nonObj); //弹窗显示 st

如上代码说明,对于非字符串的非对象变量,for ... in 也不会起到任何效果,而字符串就是一个字符数组。并且,字符串变量不能通过str[index] = char 的形式改变其值。

总结extend的可能调用场景为

 

objprop结果
对象 对象 将prop的属性拓展到对象obj身上
对象 非对象真(即if(!prop)不成立),且不为字符串 无操作
对象 字符串 对象obj以obj[index] = char 的形式存储字符串,但对象obj不会变成字符串
字符串 任意值 obj仍旧为字符串,值无变化

当prop为非对象假时(即if(!prop)成立),obj指向当前extend的调用者,prop指向原obj对象。再次套用上表。

 

8. new function(){} 的神奇用法

当对象对象对象,脑子里盘旋的全是对象的时候。在Chrome控制台敲入了一段测试代码new function(){} ,Chrome控制台给出的返回结果为Object。顿时,我就明白了new function(){} 与 (function(){})()实现了一样的效果(这里涉及到了js中的匿名函数,还可以发散一下js中的闭包),即定义函数后立即执行。但两者之间孰优属劣呢?