Underscore.js
沒有對原生 JavaScript
對象進行擴展,而是經過調用 _()
方法進行封裝,一旦封裝完成,原生 JavaScript
對象便成爲一個 Underscore
對象。node
// Is a given variable an object? _.isObject = function(obj) { var type = typeof obj; return type === 'function' || type === 'object' && !!obj; };
這是underscore.js
的判斷給定變量是不是object
的一段源碼。 咱們知道typeof
會返回以下六個值:數組
1. 'undefined' --- 這個值未定義; 2. 'boolean' --- 這個值是布爾值; 3. 'string' --- 這個值是字符串; 4. 'number' --- 這個值是數值; 5. 'object' --- 這個值是對象或null; 6. 'function' --- 這個值是函數。
而&&
的優先級要高與||
。!!
的做用至關於Boolean()
,將其轉換爲布爾值。瀏覽器
// Is a given value a DOM element? _.isElement = function(obj) { return !!(obj && obj.nodeType === 1); };
一樣!!
至關於Boolean()
的做用,nodeType === 1
則說明是元素節點,屬性attr
是2 ,文本text
是3函數
<body> <p id="test">測試</p> <script> var t = document.getElementById('test'); alert(t.nodeType);//1 alert(t.nodeName);//p alert(t.nodeValue);//null </script> </body>
firstChild
屬性測試
var t = document.getElementById('test').firstChild; alert(t.nodeType);//3 alert(t.nodeName);//#test alert(t.nodeValue);//測試
文本節點也算是一個節點,因此p的子節點是文本節點,因此返回3this
isArray = Array.isArray || function(object){ return object instanceof Array }
Array.isArray()
方法:若是一個對象是數組就返回true
,若是不是則返回false
。spa
instanceof
用於判斷一個變量是否某個對象的實例,如prototype
var a= []; alert(a instanceof Array);//返回 true
同時 alert(a instanceof Object)
也會返回 true
code
isArray
返回布爾值,若是Array.isArray
爲true
,則返回true
,不然返回object instanceof Array
的結果。對象
class2type = {}, function type(obj) { return obj == null ? String(obj) : class2type[toString.call(obj)] || "object" } function isFunction(value) { return type(value) == "function" } function isWindow(obj) { return obj != null && obj == obj.window } function isDocument(obj) { return obj != null && obj.nodeType == obj.DOCUMENT_NODE } function isObject(obj) { return type(obj) == "object" }
class2type
是一個空對象,實際上一個什麼都沒有的空對象是這樣建立的Object.create(null);
咱們能夠經過Object.prototype.toString.call()
方法來判斷數據類型,例如:
console.log(Object.prototype.toString.call(123)) //[object Number] console.log(Object.prototype.toString.call('123')) //[object String] console.log(Object.prototype.toString.call(undefined)) //[object Undefined] console.log(Object.prototype.toString.call(true)) //[object Boolean] console.log(Object.prototype.toString.call({})) //[object Object] console.log(Object.prototype.toString.call([])) //[object Array] console.log(Object.prototype.toString.call(function(){})) //[object Function]
首先若是參數obj
是undefined
或null
,則經過String(obj)
轉換爲對應的原始字符串「undefined
」或「null
」。
而後class2type[toString.call(obj)]
首先借用Object
的原型方法toString()
來獲取obj
的字符串表示,返回值的形式是 [object class]
,其中的class
是內部對象類。
而後從對象class2type
中取出[object class]
對應的小寫字符串並返回;若是未取到則一概返回「object
。
get: function(idx){ return idx === undefined ? slice.call(this) : this[idx >= 0 ? idx : idx + this.length] },
取集合中對應指定索引的值,若是idx
小於0,則idx
等於idx+length
,length
爲集合的長度.
可能你剛看到slice.call(this)
會以爲很納悶,其實不只是zepto.js
的源碼,包括jQuery
,backbone
的源碼都是這麼寫的,只不過它們在最開頭作了聲明:
var push = array.push; var slice = array.slice; var splice = array.splice;
因此slice.call(this)
其實仍是Array.slce.call(this)
//爲對象添加 class 屬性值 addClassName: function(element, className) { element = $(element); Element.removeClassName(element, className); element.className += ' ' + className; }, //爲對象移除 class 屬性值 removeClassName: function(element, className) { element = $(element); if (!element) return; var newClassName = ''; var a = element.className.split(' '); for (var i = 0; i < a.length; i++) { if (a[i] != className) { if (i > 0) newClassName += ' '; newClassName += a[i]; } } element.className = newClassName; },
由於addClassName
依賴於removeClassName()
,因此先分析後者,$()
是先將元素封裝成prototype
對象,
if(!element) return
這句的意思就是若是元素對象不存在,則忽略再也不繼續執行的意思,也就是終止的意思。
split() 方法用於把一個字符串分割成字符串數組。
若是把空字符串 (""
) 用做 分隔符,那麼 該對象 中的每一個字符之間都會被分割。
//是否擁有 class 屬性值 hasClassName: function(element, className) { element = $(element); if (!element) return; var a = element.className.split(' '); for (var i = 0; i < a.length; i++) { if (a[i] == className) return true;//返回正確的處理結果 } return false;//返回錯誤的處理結果 },
/** * 爲兼容舊版本的瀏覽器增長 Array 的 push 方法。 */ if (!Array.prototype.push) { Array.prototype.push = function() { var startLength = this.length;//this指代Array for (var i = 0; i < arguments.length; i++) this[startLength + i] = arguments[i];//this依舊指代Array return this.length; } }
!Array.prototype.push
若是爲true
,說明瀏覽器不支持該方法,則往下執行。this[startLength + i] = arguments[i]
將傳遞進來的每一個參數依次放入數組中,最後返回數組的長度
訪問對象可使用(.)
表示法,也可使用[]
來訪問,一樣訪問數組元素也是
jQuery
源碼太多關聯了,因此很差單獨拿出來作分析,就舉一兩個簡單的例子吧:
jQuery.prototype = { toArray: function() { return slice.call( this ); }, }
Array.prototype.slice.call(arguments)
能將具備length
屬性的對象轉成數組,也就是說其目的是將arguments
對象的數組提出來轉化爲數組。例如:
<script> var a = {length:4,0:'zero',1:'one',2:'two'}; console.log(Array.prototype.slice.call(a));// Array [ "zero", "one", "two", <1 個空的存儲位置> ] </script>
slice
有兩個用法,一個是String.slice
,一個是Array.slice
,第一個返回的是字符串,第二個返回的是數組。
Array.prototype.slice.call(arguments)
可以將arguments
轉成數組,那麼就是arguments.toArray().slice()
;
由於arguments
並非真正的數組對象,只是與數組相似而已,因此它並無slice
這個方法,而Array.prototype.slice.call(arguments)
能夠理解成是將arguments
轉換成一個數組對象,讓arguments
具備slice()
方法。 好比:
var arr = [1,2,3,4]; console.log(Array.prototype.slice.call(arr,2));//[3,4]
Array
這是咱們想要的基對象名稱
prototype
這能夠被認爲是一個數組的實例方法的命名空間
slice
這提取數組的一部分並返回新的數組,並無開始和結束索引,它只是返回一個數組的拷貝
call
這是一個很是有用的功能,它容許你從一個對象調用一個函數而且使用它在另外一個上下文環境
下面的寫法是等效的:
Array.prototype.slice.call == [].slice.call
看這個例子:
object1 = { name:'frank', greet:function(){ alert('hello '+this.name) } }; object2 = { name:'trigkit4' }; // object2沒有greet方法 // 但咱們能夠從object1中借來 object1.greet.call(object2);//彈出hello trigkit4
分解一下就是object1.greet
運行彈出hello + 'this.name'
,而後object2
對象冒充,this
就指代object2
var t = function(){ console.log(this);// String [ "t", "r", "i", "g", "k", "i", "t", "4" ] console.log(typeof this); // Object console.log(this instanceof String); // true }; t.call('trigkit4');
call(this)
指向了所傳進去的對象。
在Object.prototype
中已經包含了一些方法:
1.toString ( ) 2.toLocaleString ( ) 3.valueOf ( ) 4.hasOwnProperty (V) 5.isPrototypeOf (V) 6.propertyIsEnumerable (V)
jQuery.fn.extend({ on: function( types, selector, data, fn, /*INTERNAL*/ one ) { var type, origFn; // Types can be a map of types/handlers if ( typeof types === "object" ) { // ( types-Object, selector, data ) if ( typeof selector !== "string" ) { // ( types-Object, data ) data = data || selector; selector = undefined; } } }) jQuery.extend(object) :爲擴展jQuery類自己.爲類添加新的方法。 jQuery.fn.extend(object) :給jQuery對象添加方法。
!=
在表達式兩邊的數據類型不一致時,會隱式轉換爲相同數據類型,而後對值進行比較.!==
不會進行類型轉換,在比較時除了對值進行比較之外,還比較兩邊的數據類型, 它是恆等運算符===
的非形式。
on : function(){}
是js
對象字面量的寫法
{鍵:值,鍵:值}
語法中的「健/值」
會成爲對象的靜態成員。若是給某個「健」指定的值是一個匿名函數,那麼該函數就會變成對象的靜態方法;不然就是對象的一個靜態屬性。
type: function( obj ) { if ( obj == null ) { return obj + ""; } return typeof obj === "object" || typeof obj === "function" ? class2type[ toString.call(obj) ] || "object" : typeof obj; },
前面已經分析了,class2type = {};
因此class2type[ toString.call(obj) ]
= {}.toString.call(obj)
。它的做用是改變toString
的this
指向爲object
的實例。