JS:輕量級的客戶端腳本編程語言。html
1.編程語言node
編程語言是具有必定邏輯的,擁有本身的編程思想(面向對象編程[OOP]、面向過程編程)es6
-面向對象編程
+C++設計模式
+JAVA數組
+PHPpromise
+C#(.net)瀏覽器
+JS服務器
+...閉包
-面向過程
+C
2.目前JS已經不只僅是客戶端語言了,基於Node能夠作服務器端程序,因此JS是全棧編程語言。
3.學習js,咱們學習它的幾部分組成
-ECMAScript(ES):JS的核心語法
-DOM:document Object Model 文檔對象模型,提供各類API(屬性和方法)讓JS能夠獲取或操做頁面中的HTML元素(DOM元素)。
-BOM:Browser Object Model 瀏覽器對模型,提供各類API讓JS能夠獲取或操做瀏覽器。
它是js的語法規劃,JS中的變量、數據類型、語法規範、操做語句、設計模式等等都是ES規定的。
1997 ES1.0 => 1998 ES2.0 => 1999 ES3.0 (最爲普遍的應用,奠基JS基礎,目前咱們用的大部分都是ES3定下的規則語法) =》 2000 ES4(激進顛覆式更新,最後夭折) =》 2015.6 ES6... (ES5和ES6是同樣的,目前的說法是ES5表明老版本也就是ES3)
-------------------------------------------
它不是具體的值,只是一個用來存儲具體值得容器或者代名詞,由於存儲的值可變因此稱爲變量。
基於ES語法規範,在JS中建立變量有如下方式
-var (ES3)
-function (ES3) 建立函數(函數名也是變量,只不過存儲的值是函數類型而已)
-let (ES6)
-const (ES6) 建立的是常量
-import (ES6) 基於ES6的模塊規範導出須要的信息
-class (ES6) 基於ES6建立類
建立變量,命名的時候要遵循一些規範:
- 嚴格區分大小寫
- 遵循駝峯命名法:按照數字、字母、下劃線來命名(數字不能爲名字開頭),命名的時候基於英文單詞拼接成一個完整的名字(第一個單詞字母小寫,其他每個有意義的單詞首字母大寫)
- 不能使用關鍵字和保留字:在JS中有特殊含義的叫作關鍵詞,將來可能會成爲關鍵字的叫作保留字。
數據值是一門編程語言進行生產的材料,JS包含如下類型:
- 基本數據類型(值類型)
+ 數字 number
+ 字符串 string
+ 布爾 boolean
+ null
+ undefined (JS獨有)
- 引用類型
+ 對象object
+ 普通對象
+ 數組對象
+ 正則對象
+ 日期對象
+ ...
+ 函數 function
- ES6中新增長的一個特殊的類型:Symbol ,惟一的值
擴展:JS代碼如何被運行以及運行後如何輸出結果。
【如何被運行】
- 把代碼運行在瀏覽器中(瀏覽器內核來渲染解析)
- 基於node來運行(NODE也是一個基於V8引擎渲染和解析的JS的工具) //node 是環境和工具,js來作後臺,依託node來運行。node不是語言仍是js。
【如何輸出結果】
- alert:在瀏覽器中經過彈窗的方式輸出(瀏覽器提示框)// window.alert(); alert(1+1);=> '2' 基於alert輸出的結果都會利用toString()轉換爲字符串。 js中表達式先行,先計算結果再輸出;
- confirm:和alert用法一致,只不過提示的內容不同,有肯定和取消兩個按鈕,因此是確認提示框。
- prompt:在confirm的基礎上增長輸入框。
- console.log:在瀏覽器控制檯輸出日誌。 console(控制檯).log(日誌);
+ Elements:當前頁面中的元素和樣式在這裏均可以看到,還能夠調節樣式和修改結構等。
+ Console:控制檯,能夠經過JS代碼中經過.log輸出到這裏,也能夠在這裏直接編寫js代碼。
+ Sources:當前網站的原文件都在這裏。
+...
- console.dirI:比log輸出的更詳細一些(尤爲是輸出對象數據值的時候)
- console.table:把一個JSON數據按照表格的方式輸出。
- ...(本身擴展更多console輸出方法)
思考:爲何對象轉換爲字符串是 '[object object]' ,toSting()結果。 // var flag = confirm('肯定要退出麼?'); if(flag){ //點擊的確認 }else{ //點擊的取消 } ; 返回的是true和false;
【JS渲染機制堆棧內存】
當瀏覽器去加載界面加載js時,首先會建立提供window全局做用域,而後,代碼開始自上而下執行,
代碼:var a = 7;
①聲明變量a,默認值爲undefined
②在當前做用域中開闢一個位置存儲7這個值
③讓變量a和值12關聯在一塊兒(賦值)
基本類型和引用類型的區別就是,存儲方式的不一樣。
基本類型直接在做用域中,引用類型由於相對複雜,因此須要單獨開闢的存儲空間。
var ary1 = [12,23]; var ary2 = ary1; ary2.push(100); console.log(ary1); //[12,23,100]
全部做用域的兩個做用:提供代碼的執行環境 和 存儲基本類型值。
IE靠的是計數器,引用加一,反之減一。Chrom則是,固定時間查看一下,是否還被引用。
IE計數器,記混的時候,就發生了內存泄漏。
想讓堆內存銷燬,直接賦值爲 null ,經過空對象指針 null 可讓 原始變量或者其它 指向空,那麼原有被佔用的堆內存就沒有被佔用了,瀏覽器就會在空閒的時候銷燬它。
【變量提高機制】
變量提高:當棧內存(做用域)造成,JS代碼自上而下執行以前,瀏覽器受限會把全部帶"VAR"/"FUNCTION"關鍵詞的進行提早"聲明"或者"定義",這種預先處理機制,叫作"變量提高"。
=》 聲明(declare): var a (默認值undefined)
=》 定義(defined): a = 12 (定義其實就是賦值操做)
[變量提高階段]
=》帶"VAR"的只聲明未定義
=》帶"FUNCTION"的聲明和賦值都完成了
=》變量提高只發生在當前做用域。(例如:開始加載頁面的時候只對全局做用域下的進行提高,由於此時函數中存儲的都是字符串而已)
=》在全局做用域聲明的函數或者邊阿玲是"全局變量",同理,在私有做用域下聲明的變量是"私有變量" [帶VAR/FUNCTION的纔是聲明]
自從學了預解釋,今後節操是路人。
=》瀏覽器很懶,從不會作相同的事情。當代碼執行遇到建立函數這部分代碼後,會直接跳過(由於在提高階段就已經完成了函數的賦值操做了)
【重名問題】
【暫時性死區】
在ES6中Let和const等方式建立變量或者函數,不存在變量提高機制。
=》切斷了全局變量和window屬性的映射機制。
=》在相同做用域,基於Let 不能聲明相同名字的變量。(無論是是什麼方式只要聲明瞭,在用let重複聲明就會報錯,var也同樣)
雖然,沒有變量提高機制,可是在當前做用域代碼自上而下執行以前,瀏覽器會作一個重複性檢測:自上而下查找當前做用域下全部變量,一旦發現重複的,直接拋出異常,代碼中止,不會繼續執行。(雖然沒有把變量提高,可是瀏覽器已經記住了,當前做用域下有哪些變量。)
a,b變爲私有的,與全局無關,c爲全局。
【私有變量練習】
【上級做用域查找】
=》arguments:實參集合
=》arguments.callee:函數自己
=》arguments.callee.caller:當前函數在哪執行的,CALLER就是誰(記錄的是執行它的宿主環境),在全局下執行的結果是null。(嚴格模式編程禁止使用這兩個屬性。)
=》當函數執行時,造成一個私有做用域A,A的上級做用域是誰,和他在哪執行沒有關係,和它在哪建立定義有關係,在哪建立的,它的上級做用域就是誰。
【堆棧內存銷燬機制】
=》JS分爲堆內存和棧內存
=》堆內存(存儲引用類型值),和代碼分開(對象:鍵值對 函數:代碼字符串)
=》棧內存,提供JS代碼的執行環境和存儲基本類型值。
[堆內存釋放] :讓全部引用堆內存空間地址的變量賦值爲 NULL 便可(沒有變量佔用這個堆內存,瀏覽器在空閒的時候就會將其釋放)
[棧內存釋放] :通常狀況下,當函數執行完成後,所造成的私有做用域(棧內存)都會自動釋放掉,(在棧內存佔用存儲的值也會釋放掉),可是也存在特殊狀況:
①函數執行完成,當前造成的棧內存中,某些內容被棧內存之外的變量佔用。
②全局棧內存,只有當頁面關閉後纔會被釋放掉。
...
若是當前棧內存沒有被釋放掉,那麼以前在棧內存中存儲的基本值也不會被釋放掉,可以一直保存下來。
i++ :自身累加1 ,和別人運算的時候 ,先拿原有值和其其它進行運算,運算結束後,自己累加1 。
++i :自身累加1 ,先自身累加1,再和別人運算。
6 12 16 8
【帶不帶var的區別】
=>在全局做用域下聲明一個變量,也至關於給Window全局對象設置了一個屬性,變量的值就是屬性值(私有做用域中聲明的私有變量和Window無關)
用 in 操做符 能夠檢測某個屬性名是否隸屬於這個對象。 'AZUKI' in BoZai ,rue;
=》全局變量和window中的屬性存在"映射機制" , 雙方互相同步。
=》不加var本質是win的屬性,建立變量必需加var,養成良好的編程習慣。
【閉包】
函數執行造成一個私有的做用域,保護裏面的私有變量不受外界干擾,這種保護機制稱之爲「閉包」。
函數執行造成一個不銷燬的私有做用域(私有棧內存)纔是閉包。
//=>閉包:柯理化函數 fn執行返回一個堆內存被f佔用,因此fn做用域不銷燬 function fn(){ return function (){ } } var f=fn(); //=>閉包:惰性函數 自執行匿名函數造成的私有做用域被utils佔用 var utils=(function(){ return{ } })();
小紙條:()內表示聲明一個函數,正常聲明函數是不能直接在後面加括號調用的。
閉包應用舉例:
真實項目爲了保證JS性能(堆棧內存的性能變化),應該儘量減小閉包的使用(不銷燬的堆棧內存是消耗性能的)。 1.閉包的保護做用:保護私有變量不受外界干擾 真實項目開發中,尤爲是團隊協做開發,應儘可能減小全局變量的使用,防止衝突,形成全局變量污染,那麼此時咱們能夠把本身這一部份內容封裝到一個閉包中,讓全局變量轉換爲私有變量。 (function(){})(); 封裝插件的時候,也會把程序都放到閉包中保護起來,防止和用戶的程序衝突,這時對於一些須要暴露給用戶的方法能夠拋到全局。 JQ:把須要暴露的方法拋到全局 Zepto:基於RETURN把須要外面使用的方法暴露出去
2.閉包的保存做用:造成不銷燬的棧內存,把一些值保存下來,方便後面調取使用
tips:
進入函數:形參賦值 變量提高 代碼自上而下執行
在傳統的ES規範中,只有全局做用域和函數執行產生的私有做用域,判斷和循環並不會產生做用域。
原生JS:閉包,oop,異步編程,promise,async和await,es6新特性,js事件機制
全部的事件綁定都是異步編程(當前事件沒有完成,再也不等待,繼續執行下面的任務。),同步編程(一件事一件事作,當前事件沒完成,下一個任務不能處理。)
小結:
有佔用,不釋放,不管是變量,仍是事件什麼佔用,就是閉包。
ES6中判斷循環都是塊級做用域,通常大括號內部都是塊級做用域。(對象除外)
每一輪循環,都會造成一個單獨的做用域。
自帶嚴格模式,嚴格模式下的一些限制:
經常使用數組遍歷方法:
-forEach
-map
-find(ES6)
-findIndex(ES6)
-filter
-some
-every
以上均可以改this
-reduce(數組去重,對象屬性求和,數組元素出現次數,這裏主要就是利用reduce第一個參數是迭代,能夠經過初始化這個參數的數據類型,達到想實現的效果。)
-reduceRight
ES6數組空位統一爲undefined處理;
擴展運算符將一個數組,變爲參數序列。
set Map【小紙條:詳情連接】:
set:
不存儲value。因爲key不能重複,因此,在Set
中,沒有重複的key
[ ...new Set(arr)] 去重,set 是一個類數組對象;
set.has(Nan) 判斷有無,返回true/false;
set.clear() 清空,無返回值undefined
map:
對象的屬性名必是字符串,便是不寫字符串也會因默認數據類型而變爲字符串。
Symbol:
基本數據類型,typeOf 可檢測,不能和字符串進行拼接,
不能進行運算,能夠轉布爾,
只要經過Symbol()函數獲得的值就是惟一的值,只作本身,和任何人都不同
Symbol("參數做爲描述,兩個Symbel建立的值描述相同,也不會相等")
對象的屬性用 [ ] 中括號括起來,表明着裏面是變量。
若是屬性名是Symbol形式,必須經過中括號,不能經過點的形式
es6中有三類結構生來就具備Iterator接口:數組、類數組對象、Map和Set結構。(Promise.all())
只要具有Iterator,遍歷接口,就可用擴展運算符 [...arr]
默認的遍歷接口:__proto__[Symbol.Iterator]
prototype與__proto__【小紙條:詳情連接】:
1.在JS裏,萬物皆對象。方法(Function)是對象,方法的原型(Function.prototype)是對象。所以,它們都會具備對象共有的特色。
即:對象具備屬性__proto__,可稱爲隱式原型,一個對象的隱式原型指向構造該對象的構造函數的原型,這也保證了實例可以訪問在構造函數原型中定義的屬性和方法。
2.方法(Function)
方法這個特殊的對象,除了和其餘對象同樣有上述_proto_屬性以外,還有本身特有的屬性——原型屬性(prototype),這個屬性是一個指針,指向一個對象,這個對象的用途就是包含全部實例共享的屬性和方法(咱們把這個對象叫作原型對象)。原型對象也有一個屬性,叫作constructor,這個屬性包含了一個指針,指回原構造函數。
proxy和defineProperty:
new Proxy(target目標對象,{代理方法});