JavaScript實用手冊

##js的拖拽javascript

在拖拽時容易使操做變成選擇文本,這時應該添加這段:html

$("#ul").on("selectstart", "li", function(e){
  this.dragDrop && this.dragDrop();
  return false;
});

##js的event對象前端

先看文章的代碼:java

//獲取event對象
//標準DOM方法事件處理函數第一個參數是event對象
//IE可使用全局變量window.event
var evt = window.event?window.event:e;

//獲取觸發事件的原始事件源
//標準DOM方法是用target獲取當前事件源
//IE使用evt.srcElement獲取事件源
var target = evt.target||evt.srcElement;

//獲取當前正在處理的事件源
//標準DOM方法是用currentTarget獲取當前事件源
//IE中的this指向當前處理的事件源
var currentTarget= e?e.currentTarget:this;

//問題:在IE 9下  window.event 與 e 不一樣 evt沒有currentTarget屬性,e纔有currentTarget屬性(視爲標準瀏覽器作法??)
alert("src id:"+target.id+"\ncurent target id :"+currentTarget.id);

currentTarget:事件冒泡階段所在的DOM。在捕獲事件時,這個currentTarget就爲監聽事件的那個DOM元素,當事件結束時,currentTarget爲nulljquery

target, originalTarget, srcElement:觸發事件原始的DOMgit

##jQuery.ready, DOMContentLoaded, window.onload區別github

先看jQuery.ready,查看jquery-1.11.3.js源代碼:ajax

// Catch cases where $(document).ready() is called after the browser event has already occurred.
// we once tried to use readyState "interactive" here, but it caused issues like the one
// discovered by ChrisS here: http://bugs.jquery.com/ticket/12282#comment:15
if ( document.readyState === "complete" ) {
  // Handle it asynchronously to allow scripts the opportunity to delay ready
  setTimeout( jQuery.ready );

// Standards-based browsers support DOMContentLoaded
} else if ( document.addEventListener ) {
  // Use the handy event callback
  document.addEventListener( "DOMContentLoaded", completed, false );

  // A fallback to window.onload, that will always work
  window.addEventListener( "load", completed, false );

// If IE event model is used
} else {
  // Ensure firing before onload, maybe late but safe also for iframes
  document.attachEvent( "onreadystatechange", completed );

  // A fallback to window.onload, that will always work
  window.attachEvent( "onload", completed );
......

可看出jQuery也是主要利用DOMContentLoaded事件編程

DOMContentLoaded是在DOM結構繪製完畢後就執行,不必定要等全部的js和圖片加載完畢,就能夠執行一些方法json

window.onload則必須等到頁面內包括圖片(圖片也加載完成,img.complete===true時)的全部元素加載完畢後才能執行

##javascript三種設置訪問器屬性的方式

詳情:http://avalonjs.github.io/#tutorial/concepts/vmodel.html

另外一小小的知識點:普通類型變量給它定義屬性沒用

##針對retina的支持

// 優化retina, 在retina下這個值是2
var ratio = window.devicePixelRatio || 1;

##判斷圖片是否已加載了

利用complete屬性可判斷:img.complete

##運算符的優先級

輸入圖片說明

##visibilitychange事件

標籤頁激活檢測(視覺改變觸發):當用戶焦點在另一個標籤上,或從新回到標籤時,觸發visibilitychange事件:

$(document).on('visibilitychange', function (e) {
  if (e.target.visibilityState === "visible") {
    console.log('Tab is now in view!');
  } else if (e.target.visibilityState === "hidden") {
    console.log('Tab is now hidden!');
  }
});

##cookies,sessionStorage和localStorage的區別

  • sessionStorage用於本地存儲一個會話的數據,這些數據只有在同一會話中的頁面才能訪問而且會話結束後數據也隨之銷燬。所以sessionStorage不是一種持久化的本地存儲,僅僅是會話級別的存儲。而localStorage用於持久化的本地存儲,除非主動刪除數據,不然數據是永遠不會過時的。
  • cookie的容量小,WebStorage的容量大大提高
  • Cookie的大小是受限的,而且每次你請求一個新的頁面的時候Cookie都會被髮送過去,這樣無形中浪費了帶寬
  • cookie還須要指定做用域,不能夠跨域調用
  • Web Storage擁有setItem,getItem,removeItem,clear等方法,不像cookie須要前端開發者本身封裝setCookie,getCookie
  • 可是Cookie也是不能夠或缺的:Cookie的做用是與服務器進行交互,做爲HTTP規範的一部分而存在 ,而Web Storage僅僅是爲了在本地「存儲」數據而生

關於new運算符的一道題

x = 1
function bar(){
    this.x = 2
    return x
}
var foo = new bar()
alert(foo.x) // -> 2

這裏主要問題是最外面x的定義,試試把x=1改爲x={},結果會不一樣的。這是爲何呢?

在把函數看成構造器使用的時候,若是手動返回了一個值,要看這個值是否簡單類型,若是是,等同於不寫返回,若是不是簡單類型,獲得的就是手動返回的值。若是,不手動寫返回值,就會默認從原型建立一個對象用於返回。

##js的script標籤的defer和async屬性

[defer]

能夠在<script>中加入defer屬性,告訴瀏覽器這段script沒必要當即執行,那麼瀏覽器就會在徹底載入文檔以後再執行這個script,至關於window.onload,但它比window.onload更靈活。

<script defer="true"></script>

[async]

使用async屬性加載JavaScript,這樣整個腳本就能夠異步加載和執行。

<script>標籤的defer屬性——告訴瀏覽器該腳本不會在頁面加載完成以前操做DOM,腳本將會和其餘資源文件並行下載; <script>標籤的async屬性——HTML5新的異步、並行模式,腳本將在完成下載後等待合適的時機執行代碼。

##parseInt,parseFloat

parseInt('0xA')    // return 10`
parseInt('A')      // return NaN`
parseInt('A', 16)  // return 10`
parseFloat('22.22.22') // return 22.22`
parseFloat('A', 16)    // return NaN`,沒有基模式
parseFloat('0xA')      // return 0`,不轉換爲十六進制,直接轉前面數字部分而已

void運算符

void運算符對任何值都返回undefined,該運算符經常使用於避免輸出不該該輸出的值。例如: <a href="javascript:window.open('about:blank');">Click Me</a>

其中,window.open()返回對新打開窗口的引用,會輸出字符串的,應該改成: <a href="javascript:void(window.open('about:blank'));">Click Me</a>

不能忽視坑爹弱等號 ==

false == 0 -> true
false == "0" -> true
null == 0 -> false
+null === 0 -> true
null <= 0    -> true
null < 1      -> true
'' == 0 -> true    // ''會被轉換爲數字, 至關於+'' == 0
'' == false -> true
[] == false -> true
[] == ''  -> true
true == 1 -> true
true == 2 -> false
'5' == 5   -> true
isNaN('123') -> false
isNaN(null) -> false
Number([]) === Number('') === 0

小結:null 只弱等於 undefined , 但Number(null)等於0,0跟false是弱等的,因此 null != false, +null == false

ajax獲取數據中文亂碼問題

使用scriptCharset便可解決問題,用contentType就不必定能夠了。

$.ajax({
  url: testUrl,
  dataType: 'jsonp',
  type: 'post',
  scriptCharset: 'utf-8'
});

##URL的基本概念:URL完整組成部分

輸入圖片說明

糾正一下:

  • 以上圖片中,path參數不包括hash
  • window.location不包括path屬性,只有pathname

##window.onload和DOMContentLoaded事件的區別

前者是DOM,圖片,樣式表,flash等加載完成後觸發的,後者是DOM加載完成,但樣式表和圖片可能未加載完成時就觸發的,而且只在某些瀏覽器中有此事件。

##JavaScript的原型

JavaScript是基於原型的編程語言,當你讀取一個對象的屬性,JavaScript首先會在本地對象中查找這個屬性,若是沒找到,JavaScript開始在對象的原型中查找,若仍未找到,還會繼續查找原型的原型,直到查找到Object.prototype。若是找到這個屬性,則返回這個值,不然返回undefined. 換句話說,若是你給Array.prototype添加了屬性,那麼全部JavaScript數組都具備了這個屬性

##變量提高

變量提高指的是,不管是哪裏的變量,都是在一個範圍內聲明的。JavaScript引擎會將這個聲明移到範圍的頂部。如:

function foo(){
  // 此處省略若干代碼
  var a = 100;
}

運行代碼時,實質就是這樣:

function foo(){
  var a;
  // 此處省略若干代碼
  a = 100;
}

##hasOwnProperty ##isPrototypeOf ##constructor

hasOwnProperty

檢查該對象是否有屬於它自己的屬性/對象,而不是它原型上的屬性/對象。由於畢竟那是它原型的屬性,而不是它本身的。就等於你能夠花你老爸的錢,但畢竟不是你的錢。如:

isPrototypeOf

顧名思義,檢查該對象是否爲另一對象的原型

constructor

對建立對象的函數的引用(指針),指向的老是一個function

prototype

對該對象原型的引用,返回的是一個object實例

var Foo = function(){
  this.age = 25;
};
Foo.prototype.count = 100;
Foo.prototype.get = function(){return this.count;};

var f = new Foo();
console.log("age",f.hasOwnProperty("age")); // age true
console.log("count",f.hasOwnProperty("count")); // count false
console.log(Foo.prototype.hasOwnProperty("count")); // true
console.log(Foo.prototype.hasOwnProperty("get")); // true
f.age // -> 25
f.count // -> 100,雖然不是f的ownProperty,但直接讀取該屬性也是能夠的

console.log(Foo.prototype.isPrototypeOf(f)); // -> true
console.log(Foo === f.constructor); // -> true

##關於__proto__和prototype的區別

最簡單來講,__proto__屬性是實例對象的原型屬性,prototype是構造函數的原型屬性,二者應該是相等的。如:

function B(){this.name = 'kobe';} B.prototype.age = 20; var b = new B();
alert(b.__proto__ === B.prototype); // true

new構造函數返回的this

當使用new關鍵字來調用構造函數時,若是構造函數裏沒有返回任何內容,就會返回this——當前上下文的對象,要否則就返回任意非原始類型的值,如數組,object。如:

var Class1 = function(){return {};}, Class2 = function(){return [];}, Class3 = function(){return function(){};},
Class4 = function(){return 123;},
Person1 = new Class1, // {}
Person2 = new Class2, // []
Person3 = new Class3, // function(){}
Person4 = new Class4; // function instanceof Class4

##棧stack和堆heap的區別

原始值是存儲在棧中的簡單數據段,也就是說,它們的值直接存儲在變量訪問的位置;引用值是存儲在堆中的對象,也就是說,存儲在變量處的值是一個指針,指向存儲對象的內存處。若是一個值是引用類型的,那麼它的存儲空間將從堆中分配。因爲引用值的大小會改變,因此不能把它放在棧中,不然會下降變量查尋的速度。相反,放在變量的棧空間中的值是該對象存儲在堆中的地址。地址的大小是固定的,因此把它存儲在棧中對變量性能無任何負面影響。

##Number值集合的外邊界:Number.MAX_VALUE和Number.MIN_VALUE

全部ECMAScript數都必須在這兩個值之間,不過計算生成的數值結果能夠不落在這兩個數之間。當計算生成的數大於Number.MAX_VALUE時,它將被賦予值Number.POSITIVE_INFINITY,意味着再也不有數字值,一樣,生成的數值小於Number.MIN_VALUE的計算也會被賦予值Number.NEGATIVE_INFINITY,也再也不有數字值。若是返回的是無窮大值,那麼結果就不能再用在其餘計算。

無窮大的值:Infinity === Number.POSITIVE_INFINITY-Infinity === Number.NEGATIVE_INFINITY,判斷是否有窮的isFinite(123) === true

##數字轉換爲二進制字符串

a=12345, a.toString(2) === "11000000111001",與之相對的是 a = parseInt("11000000111001", 2) === 12345

##閉包(closure) ##做用域鏈

做用域鏈:js只有函數做用域和全局做用域。做用域鏈就是從內部函數做用域到外部函數做用域,一直到全局做用域。閉包是簡單來講是函數中使用函數,內部函數使用到外部函數的變量,而外部函數以外的做用域對外部函數的返回值有引用,那麼外部函數就成了一個閉包,內部函數對外部函數的引用鏈就不會銷燬。

閉包意味着內層的函數能夠引用存在於包圍它的函數內的變量,即便外層函數的執行已經終止

閉包主要的應用場景以及一些特色有:

  1. 實現私有變量
var obj = (function(){
  var privateVar;

  return {
    get: function(){
      return privateVar;
    },
    set: function(value){
      privateVar = value
    }
  };
})();
  1. 閉包傳參,保護全局做用域
(function($, undefined){/*…*/})(jQuery)
  1. 循環中使用閉包,但不聲明變量

但閉包有在for/next循環中使用閉包卻不聲明變量來保存迭代變量當前值的一些風險。閉包容許你引用父函數中的變量,但提供的值並不是該變量建立時的值,而是在父函數範圍內的最終值。

  1. 參數和變量不會被垃圾回收機制回收

在函數A內定義一個函數B,B對A中的一些變量有引用,那麼A即便運行結束,B對A變量的引用鏈也不會銷燬。因此閉包不能濫用!

##垃圾回收機制 ##循環引用

  1. 標記清除

在函數中聲明一個變量,則將其標記爲「進入環境」,當變量離開環境時,則將其標記爲「離開環境」。

垃圾回收器在運行的時候會給存儲在內存中的全部變量都加上標記(固然,可使用任何標記方式)。而後,它會去掉環境中的變量以及被環境中的變量引用的變量的標記(閉包)。而後銷燬那些帶標記的值並回收它們所佔用的內存空間

  1. 引用計數

引用計數的含義是跟蹤記錄每一個值被引用的次數。當聲明瞭一個變量並將一個引用類型值賦給該變量時,則這個值的引用次數就是1。若是同一個值又被賦給另外一個變量,則該值的引用次數加1。相反,若是包含對這個值引用的變量又取得了另一個值,則這個值的引用次數減1。當這個值的引用次數變成0時,則說明沒有辦法再訪問這個值了,於是就能夠將其佔用的內存空間回收回來。這樣,當垃圾回收器下次再運行時,它就會釋放那些引用次數爲0的值所佔用的內存。

Netscape Navigator3是最先使用引用計數策略的瀏覽器,但很快它就遇到一個嚴重的問題:循環引用。循環引用指的是對象A中包含一個指向對象B的指針,而對象B中也包含一個指向對象A的引用。

function fn() {
  var a = {};
  var b = {};
  a.pro = b;
  b.pro = a;
}

fn();

以上代碼a和b的引用次數都是2,fn()執行完畢後,兩個對象都已經離開環境,在標記清除方式下是沒有問題的,可是在引用計數策略下,由於a和b的引用次數不爲0,因此不會被垃圾回收器回收內存,若是fn函數被大量調用,就會形成內存泄露。

咱們知道,IE中有一部分對象並非原生js對象。例如,其DOM和BOM中的對象就是使用C++以COM對象的形式實現的,而COM對象的垃圾回收機制採用的就是引用計數策略。所以,即便IE的js引擎採用標記清除策略來實現,但js訪問的COM對象依然是基於引用計數策略的。換句話說,只要在IE中涉及COM對象,就會存在循環引用的問題。

因此,有時需手動切斷JS對象與DOM的鏈接:

$dom._object = null;
jsObj._dom = null;
相關文章
相關標籤/搜索