<script> /*1.如何區分私有變量和全局變量? 1)在全局做用域下聲明(預解釋的時候上)的變量是全局變量 2)在「私有做用域中聲明的變量」和「函數的形參」都是私有變量 在私有做用域中,咱們代碼執行的時候遇到了一個變量,首先咱們須要肯定它是否爲私有的變量,若是是私有的變量,那麼和外面的沒有任何的關係;若是不是私有的,則往當前做用域的上級做用域進行查找,若是上級做用域也沒有則繼續查找,一直找到window爲止 ...(做用域鏈) 2.當函數執行的時候(直接目的:讓函數體中的代碼執行),首先會造成一個新的私有的做用域,而後按照以下的步驟執行: 1)若是沒有形參,先給形參賦值 2)進行私有做用域中的預解釋 3)私有做用域中的代碼自上而下執行 ... 4)函數造成一個新的私有的做用域保護了裏面的私有變量不受外界干擾(外面修改不了裏面的),私有的也修改不了外面的-》閉包 閉包:閉包是一種機制,函數執行的時候造成了一個私有的做用域,保護裏面的私有變量不受外界干擾。 //預解釋的時候無論你的條件是否成立,都要把帶var的進行提早的聲明 //window的預解釋:var num; -> window.num if(!('num' in window)){ var num = 12; } console.log(num) // undefined 3.執行函數定義的那個function在全局做用域下不進行預解釋,當代碼執行到這個位置的時候定義和執行一塊兒完成了 // 自執行函數:定義和執行一塊兒完成了,不進行預解釋 (function(num){})(100) ~function(num){}(100 +function(num){}(100) -function(num){}(100) !function(num){}(100) 4.函數體中的return下面的代碼雖然不在執行了,可是須要進行預解釋;return後面跟着的都是咱們的返回值,因此不進行預解釋。 function fn(){ console.log(num); // undefined return function(){ }; var num = 10; } fn(); 5.在預解釋的時候,若是名字已經聲明過了,不須要從新聲明,可是須要從新賦值;在JS中若是變量的名字和函數的名字重複了,也算衝突 預解釋:var fn; window.fn; fn = xxxfff000 window.fn = xxxfff000 var fn = 10; function fn(){ console.log('ok'); } //window預解釋: //聲明+定義 fn = xxxfff11 //聲明 var fn;(不須要從新聲明) //聲明(不重複進行) + 定義 fn = xxxfff222 //->fn=xxxfff222 fn(); function fn(){ console.log(1) } fn(); var fn = 10; fn(); function fn(){ console.log(2) } fn(); //如何查找當前做用域上一級做用域 //看當前函數是在哪一個做用域下定義的,那麼它的上級做用域就是誰->和函數在哪執行的沒有任何關係 var num = 12; function fn(){ var num = 120; return function(){ console.log(num); }; } var f = fn(); f(); //120 ~function(){ var num = 1200; f() //120 } // 堆內存 // 對象數據類型或者函數數據類型在定義的時候首先會開闢一個堆內存,堆內存有一個引用的地址,若是外面有變量等引用了這個地址,咱們就說這個內存被佔用了,就不能銷燬了。 咱們要讓堆內存釋放/銷燬,只須要把這個引用它的變量賦值爲null。若是當前的堆內存沒有任何東西被佔用了,那麼瀏覽器會在空閒的時候把它銷燬。。。 //銷燬: obj = null: //棧內存 1)全局做用域 只有當頁面關閉的時候全局做用域纔會銷燬 2)私有的做用域(只有函數執行會產生私有的做用域) //通常狀況下,函數執行會造成一個新的私有做用域,當私有做用域中的代碼執行完成後,咱們當前做用域都會主動的進行釋放和銷燬 //可是仍是存在特殊狀況的: //當前私有做用域中的部門內存被做用域之外的東西佔用了,那麼當前的這個做用域就不能銷燬了 //a,函數執行返回了一個引用數據類型的值,而且在函數的外面被一個其餘的東西給接收了,這種狀況下通常造成的私有做用域都不會銷燬。 function fn(){ var num = 100; return function(){ num++; console.log(num); } } var f = fn(); f(); 下述狀況屬於不當即銷燬->fn返回的函數沒有被其餘的東西佔用,可是還須要執行一次呢,因此暫時不銷燬,當返回的值執行完成後,瀏覽器會在空閒的時候把它銷燬了。->「不當即銷燬」 function fn(){ var num = 100; return function(){ num++; console.log(num); } } fn()(); 檢測數據類型的四種方式: 1.typeof 用來檢測數據類型的運算符 2.instanceof 檢測某一個實例是否屬於某個類 3.constructor 構造函數 4.Object.prototype.toString.call() 1.for,while 都是同步模式 2.異步: 不會當即執行,須要等必定時間,只有當下面的事情都處理完成了,纔會回頭處理以前的事情;若是下面的事情並無處理完成,無論以前的事情有沒有到時間,都等着。 3.在JS中異步編輯有四種狀況: 定時器 事情綁定 Ajax 回調函數 每個瀏覽器對於定時器的等待時間都有一個最小的值,谷歌5-6ms,IE:10-13ms,若是設置的等待時間小於這個值,不起做用,還須要等到最小時間才執行;0也不是當即執行。 var n = 0; setTimeout(function(){ n++; console.log(n) },0) console.log(n) 咱們定時器設置的等待時間不必定是最後執行時間,若是定時器以後還有其餘的事情正在處理中,無論定時器的時間有沒有到,都是不會執行定時器的 var n = 0; setTimeout(function(){ n++; console.log(n) //不執行 },0) console.log(n) //1 while(1){ //死循環 n++; } console.log(n); //不執行 數組forEach不支持return,沒有返回值 數組map支持return,有返回值,並不影響原來的數組,至關於把原數組克隆一份返回出去 var obj = {name:'hongliang'} var ary = [1,2,3,4,5]; //->forEach方法中的this是ary;匿名回調函數中的this默認是window; ary.forEach(function(item,index){ console.log(this); //window },obj);//->不論是forEach仍是map都支持第二個參數值,第二個參數的意思是把匿名回調函數中的this進行修改 var obj = {name:'hongliang'} var ary = [1,2,3,4,5]; ary.forEach(function(item,index){ console.log(this); //window }.call(obj)) //->給forEach賦值的時候,首先把匿名函數執行,把匿名函數中的this改變成obj,把匿名函數執行的返回結果undefined賦值給forEach(不行); var obj = {name:'hongliang'} var ary = [1,2,3,4,5]; ary.forEach(function(item,index){ console.log(this); //obj }.bind(obj)) //->兼容性(ie8及如下) 咱們在js中主要研究的都是函數中的this; JS中的this表明的是當前行爲執行的主體;JS中的context表明的是當前行爲執行的環境(區域) this 是誰和函數在哪定義的和在哪執行的都沒有任何的關係:如何區分this呢? 1,函數執行,首先看函數名前面是否有".",有的話,"."前面是誰this就是誰;沒有的話this就是window 2,自執行函數中的this永遠是window 3,給元素的某一個事件綁定方法,當事件執行時,this是綁定的元素 4,全局做用下,自定義執行函數中不預解析 function fn(){ console.log(this); } var obj = {fn:fn}; fn(); //this->window obj.fn(); //this->obj document.getElementById('div1').onclick = fn; //this->#div1 document.getElementById('div1').onclick = function(){ //this->#div1 fn(); //this->window }; function sum(){ //this->window fn(): //this->window } sum(); var oo = { sum:function(){ //this->oo fn() //this->window } } oo.sum(); var num = 20; var obj = { num:30, fn:(function(num){ this.num *= 3; num += 15; var num = 45; return function(){ this.num *= 4; num += 20; console.log(num); } })(num); }; var fn = obj.fn; fn(); //65 obj.fn(); //85 console.log(window.num,obj.num) //240,120 做用域不銷燬的三種情形: 1,函數執行返回一個引用類型,被一個變量接收 2,在私有做用域裏給元素綁定一個方法 3,fn()(); 1, var count = 0; obtn.onclick = function(){ count++; console.log(count); } 2, ~function(){ var count = 0; obtn.onclick = function(){ count++; console.log(count); } }() obtn.onclick = (function(){ var count = 0; return function(){ count++; console.log(count); } })(); 弊端:有一個不銷燬的私有做用域,因此佔那麼一點內存。 3,利用innerHTML的方式處理:每點擊一次都去頁面獲取最新的值,累加,最後再賦值過去 obtn.onclick = function(){ spanNum.innerHTML++; } 弊端:每一次都把頁面中的內容轉換爲字符串再累加,累加完再從新添加回去,瀏覽器會從新渲染一下 4,利用自定義屬性存儲(推薦使用) obtn.count = 0; obtn.onclick = function(){ spanNum.innerHTML = ++this.count; } 全部的編程語言都是面向對象開發的->類的繼承、封裝、多態 繼承:子類繼承父類中的屬性和方法 多態:當前方法的多種形態->後臺語言中:多態包含重載和重寫 JS中不存在重載,方法名同樣的話,後面的會把前面的覆蓋掉。 JS中有一個操做相似重載但不是重載:「咱們能夠根據傳遞的參數不同,實現不一樣的功能。 重寫:子類重寫父類的寫法 工廠模式: function createPerson(){ var obj = new Object(); obj.name = 'zhl'; obj.getName = function(){ return this.name; } return obj; } 構造函數模式: function createPerson(){ this.name = 'zhl'; this.getName = function(){ return this.name; } } //構造函數模式中擁有了類和實例的概念,而且實例和實例之間是相互獨立開的->實例識別 //基於構造函數模式的原型模式解決了 方法或者屬性公有的問題->把實例之間相同的屬性和方法提取成公有的屬性和方法->類.prototype = fn; *1.每個函數數據類型(普通函數、類)都有一個天生自帶的屬性:prototype(原型),而且這個屬性是一個對象數據類型的值 2.而且在prototype上瀏覽器天生給它增長了一個屬性constructor(構造函數),屬性值是當前函數(類)的自己 3.每個對象數據類型(普通對象、實例、prototype...)也天生自帶一個屬性:__proto__,屬性值是當前實例所屬類的原型(prototype). 二、Object是JS中全部對象數據類型的基類(最基層的類) 1),f1 instanceof Object ->true 經過__proto__能夠向上級查找,無論有多少級,最後總能找到Object. 2),在Object.prototype上沒有__proto__這個屬性 三、原型鏈模式 f1.hasOwnProperty("x");//->hasOwnProperty是f1的一個屬性 可是咱們發如今f1的私有屬性上並無這個方法,那如何處理的呢? 1)經過 對象名.屬性名 的方式獲取屬性值的時候,首先在對象的私有屬性上進行查找,若是私有屬性中存在這個屬性,則獲取的是這私有屬性的值。 2)若是私有屬性上沒有,則經過__proto__找到所屬類的原型(類的原型上定義的屬性和方法都是當前實例公有的屬性和方法),原型上存在的話,獲取的是公有屬性值。 3)若是原型上也沒有,則繼續經過原型上的__proto__繼續向上查找,一直找到Object.prototype爲止...若是仍是找不到則是undefined -->這種查找機制就是"原型鏈模式" 一、 JS中的全部的類都是函數數據類型,它經過new執行變成一個類,可是它自己也是一個普通的函數 JS中全部的實例都是對象數據類型的 二、構造函數中的this指當前new出來的實例對象 function Fn(){ //this->f1 this.x = 100; this.getX = function(){ //this->須要看getX執行的時候才知道 console.log(this.x); } } var f1 = new Fn; f1.getX(); //->方法中的this是f1->100 var ss = f1.getX; ss(); //->方法中的this是window -> undefined; 一、在構造函數模式中 new Fn() 執行,若是Fn不須要傳遞參數的話,後面的小括號能夠省略 二、this的問題:在類中出現的this.xx = xxx中的this 都是當前類的實例,而某一個屬性值(方法),方法中的this須要看方法執行的時候,前面是否有"."才知道this是誰。 匿名函數中的 this 是 window; 事件對象: e.pageX = e.pageX || (e.clientX + (document.documentElement.scrollLeft || document.body.scrollLeft)) e.pageY = e.pageY || (e.clientY + (document.documentElement.scrollTop || document.body.scrollTop)) e.preventDefault() // 阻止默認行爲 表格排序: function sortTable(n){ var _this = this; //-> 把存儲全部行的類數組轉化爲數組 var ary = [].slice.call(oRows); //->點擊當前列,讓其它列flag迴歸到初始值-1;這樣就不會亂; for(var k = 0; k<oThs.length; k++){ if(oThs[k] != this){ oThs[k].flag = -1; } } //->給數組進行排序; _this.flag *= -1; ary.sort(function(a,b){ var curInn = a.cells[n].innerHTML; var nextInn = b.cells[n].innerHTML; var curInnNum = parseFloat(a.cells[n].innerHTML); var nextInnNum = parseFloat(b.cells[n].innerHTML); if(isNaN(curInnNum) || isNaN(nextInnNum)){ return (curInn.localeCompare(nextInn)) * _this.flag; }else{ return (curInnNum - nextInnNum) * _this.flag; } }) //-> 按照ary中的最新順序,把每一行從新添加到tBody中 var frg = document.createDocumentFragment(); for (var i = 0; i < ary.length; i++) { frg.appendChild(ary[i]); }; tBody.appendChild(frg); frg = null; } //點擊排序:全部具備class="cursor" 這個樣式的列均可以實現點擊排序 for(var i = 0; i<oThs.length; i++){ var curTh = oThs[i]; if(curTh.className === "cursor"){ curTh.index = i; curTh.flag = -1; curTh.onclick = function(){ sortTable.call(this,this.index); } } } */ </script>