ECMA Script
- 它是一種由ECMA組織(前身為歐洲計算機制造商協會)制定和發布的腳本語言規范
- 而我們學的JavaScript是ECMA的實現, 但術語ECMAScript和JavaScript平時表達同一個意思
- JS包含三個部分:
- ECMAScript(核心)
- 瀏覽器端擴展
- DOM(文檔對象模型)
- BOM(瀏覽器對象模型)
- 服務器端擴展
- Node
- ES的幾個重要版本
- ES5 : 09年發布
- ES6(ES2015) : 15年發布, 也稱為ECMA2015
- ES7(ES2016) : 16年發布, 也稱為ECMA2016 (變化不大)
- 教程
- ES5
- http://www.zhangxinxu.com/wordpress/2012/01/introducing-ecmascript-5-1/
- http://www.ibm.com/developerworks/cn/web/wa-ecma262/
- ES6
- http://es6.ruanyifeng.com/
- ES7
- http://www.w3ctech.com/topic/1614
- ES5
ES5
ES5兼容性
- IE8只支持defineProperty、getOwnPropertyDescriptor的部分特性和JSON的新特性
- IE9不支持嚴格模式, 其它都可以
- IE10和其他主流瀏覽器都支持了
- PC端開發需要注意IE9以下的兼容, 但移動端開發時不需要
嚴格模式
- 在ES5中,除了正常運行模式(混雜模式),ES5還添加了第二種運行模式:"嚴格模式"(strict mode),這種模式使得Javascript在更嚴格的語法條件下運行
- 嚴格模式的作用
-
消除Javascript語法的一些不合理、不嚴謹之處,減少一些怪異行為
- 消除代碼運行的一些不安全之處,保證代碼運行的安全
- 為未來新版本的Javascript做好鋪墊
-
- 使用嚴格模式
- 在全局或函數的第一條語句定義為: 'use strict';如果瀏覽器不支持, 只解析為一條簡單的語句, 沒有任何副作用 語法和行為改變:
- 必須用var聲明變量
- 創建eval作用域
- 禁止this指向window
- 對象不能有重名的屬性
- 函數不能有重名的形參
- 教程:http://www.ruanyifeng.com/blog/2013/01/javascript_strict_mode.html

<script type="text/javascript"> 'use strict'; // 使用嚴格模式 var str = 'string'; // 必須使用var來聲明變量 function Person(name, age) { this.name = name; this.age = age; } // Person(); // 禁止自定義的函數中的this指向window new Person('zh', 18); var str = '123'; eval('var str = "234"; alert(str)'); // 創建eval作用域不會污染全局變量 alert(str); // 對象不能有重名的屬性 var obj = { name: '123', name: '234' } <script
JSON對象
-
JSON.stringify(obj/arr)
-
將js對象(數組)轉換為json對象(數組)
-
-
JSON.parse(json)
-
將json對象(數組)轉換為js對象(數組)
-
ES5對Object的擴展
- Object.create(prototype[, descriptors]) : 創建一個新的對象
-
作用: 以指定對象為原型創建新的對象
-
為新的對象指定新的屬性, 並對屬性進行描述
-
value : 指定值
-
writable : 標識當前屬性值是否是可修改的, 默認為false
-
configurable: 標識當前屬性是否可以被刪除 默認為false
-
enumerable: 標識當前屬性是否能用for in 枚舉 默認為false
- 例:
var obj = { uername: 'zh', age: 18 }; var obj1 = Object.create(obj, { sex: { value: '女', writable: true, configurable: true, enumerable: true } })Object.defineProperties(object, descriptors)
-
-
Object.defineProperties(object, descriptors)
-
作用:為指定對象定義擴展多個屬性
-
get:用來獲取當前屬性值得回調函數
-
set:修改當前屬性值得觸發的回調函數,並且實參即為修改后的值
-
存取器屬性:setter,getter一個用來存值,一個用來取值
- 例:
var obj2 = { firstName: '123', lastName: '234' } Object.defineProperties(obj2, { fullName: { get: function () { // 惰性求值,獲取擴展屬性的值,獲取擴展屬性值的get方法自動調用 return this.firstName + ' '+ this.lastName; }, set: function (data) { // 監聽擴展屬性,當擴展屬性發生變化的時候會自動調用,會將變化的值作為實參注入到set函數 console.log('Set()---' + data); var names = data.split(' '); this.firstName = names[0]; this.lastName = names[1]; } } }) obj2.firstName = '456' console.log(obj2.fullName); // 456 234 console.log(obj2); // {firstName: "456", lastName: "234"} obj2.fullName = 'change fullName' console.log(obj2.fullName); // change fullName
-
-
get propertyName(){}
-
用來得到當前屬性值的回調函數
-
-
set propertyName(){}
-
用來監視當前屬性值變化的回調函數
-
- 例:
var obj = { firstName: '111', lastName: '222', get fullName() { return this.firstName + ' ' + this.lastName; }, set fullName(data) { var names = data.split(' '); this.firstName = names[0]; this.lastName = names[1]; } }; console.log(obj); obj.fullName = '333 444'; console.log(obj);
Array擴展
- Array.prototype.indexOf(value) : 得到值在數組中的第一個下標
- Array.prototype.lastIndexOf(value) : 得到值在數組中的最后一個下標
- Array.prototype.forEach(function(item, index){}) : 遍歷數組
- Array.prototype.map(function(item, index){ }) : 遍歷數組返回一個新的數組
-
var arr = [1, 2, 3, 4, 5, 6, 7, 8]; var newArr = arr.map(function (item, index) { return item + 10; }) console.log(newArr); // [11, 12, 13, 14, 15, 16, 17, 18]
-
- Array.prototype.filter(function(item, index){ }) : 遍歷過濾出一個新的子數組
-
var arr = [1, 2, 3, 4, 5, 6, 7, 8]; var newArr1 = arr.filter((item, index) => item > 3 ) console.log(newArr1); // [4, 5, 6, 7, 8]
-
Function擴展
-
Function.prototype.bind(obj)
-
作用: 將函數內的this綁定為obj, 並將函數返回
-
特點:綁定完this不會立即調用當前函數,而是將函數返回
-
bind傳參的方式和call一樣,通常用來指定回調函數的this
-
-
bind()與call()和apply()的區別
-
bind()與call()和apply()都能指定函數中的this
-
call()/apply()是立即執行函數
-
bind()是將函數返回
- call()和apply的傳參形式不同
- foo.call(obj, 123); // 直接從第二個參數開始,依次傳入
- foo.apply(obj, [123]); // 第二參數必須是數組,傳入放在數組里
-
ES6
關鍵字拓展
let關鍵字
- 作用:與var類似, 用於聲明一個變量
- 特點:
- 在塊作用域內有效
-
不能重復聲明
-
不會預處理, 不存在提升
- 例:
{ // console.log(sum); // 不會預處理(預解析),不存在變量提升 let sum = 123; // let sum = 123; // 不能重復聲明 } // console.log(sum); // 在塊級作用域內有效,在ES5及之前沒有塊級作用域
- 應用
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>01_let關鍵字</title> </head> <body> <button>測試1</button> <br> <button>測試2</button> <br> <button>測試3</button> <br> <script type="text/javascript"> let btns = document.getElementsByTagName('button'); // 閉包 // for (let i = 0; i < btns.length; i++) { // (function (i) { // btns[i].onclick = function () { // alert(i); // } // })(i) // } // 可代替閉包 for (let i = 0; i < btns.length; i++) { btns[i].onclick = function () { alert(i); } } </script> </body> </html>
const關鍵字
- 作用:定義一個常量
- 特點:
- 不能修改
- 塊作用域有效
- 應用:保存應用需要的常量數據
變量的解構賦值
- 從數組或對象中提取值, 對多個變量進行賦值
- 數組的解構賦值
// 解構數組 let arr = [1, 3, 5, 'abc', true]; let [, , a, b] = arr // 5 "abc"
- 對象的解構賦值
// 對象的解構賦值 let { username, age, xxx } = obj; // 相當於 // let username = obj.username; // 由於let不能重復聲明變量,故會在控制台中報錯 // let age = obj.age; // let xxx = obj.xxx;
- 數組的解構賦值
模板字符串
-
模板字符串簡化了字符串的拼接
-
模板字符串必須用 `` 包含
- 變化的部分使用${xxx}定義
- 例:
let obj = { userName: 'zh', age: 18 }; let str = '我的名字叫:' + obj.userName + ',我的年齡是' + obj.age; let tempalteStr = `我的名字叫:${obj.userName},我的年齡是${obj.age}`;
簡化的對象寫法
-
省略同名的屬性值
-
省略方法的function
- 例:
let username = 'zh'; let age = 18; let obj = { // 同名屬性可省略不寫 username, age, getName() { // 可以省略函數的function return this.username; } };
函數擴展
箭頭函數
-
作用: 定義匿名函數
-
基本語法:
-
沒有參數: () => console.log('xxxx')
-
一個參數: i => i+2
-
大於一個參數: (i,j) => i+j
- 函數體不用大括號:默認返回結果
-
函數體如果有多個語句: 需要用{}包圍,若有需要返回的內容,需要手動返回
-
-
箭頭函數的特點:
-
簡潔
-
箭頭函數沒有自己的this,箭頭函數的this不是調用的時候決定的,而是在定義的時候處在的對象就是它的this
-
箭頭函數的this看外層的是否有函數。如果有,外層函數的this就是內部箭頭函數的this,如果沒有,則this是window。
- 例
let obj2 = { name: '123', age: 18, text: () => { btn3.onclick = () => { console.log(this); // window console.log(this === window); // true } } } obj2.text();
-
-
形參的默認值
-
當不傳入參數的時候默認使用形參里的默認值
- 例:
function Point(x = 1 , y = 1) { this.x = x; this.y = y; }
三點運算符
rest(可變)參數
-
用來取代arguments 但比 arguments 靈活,只能是最后部分形參參數
-
使用三點運算符時,只能把三點運算符放在最后面
- 例
function foo(a, ...value) { console.log(arguments); // 偽數組 Arguments(4) [1, 2, 3, 4, callee: (...)] console.log(value); // 數組 [2, 3, 4] } foo(1, 2, 3, 4);
擴展運算符
- 例:
var arr = [1,6] var arr1 = [2,3,4,5]; arr = [1,...arr1,6]; console.log(arr); // [1, 2, 3, 4, 5, 6] console.log(...arr); // 1 2 3 4 5 6
class類
-
通過class定義類/實現類的繼承
-
在類中通過constructor定義構造方法
-
通過new來創建類的實例
-
通過extends來實現類的繼承
-
通過super調用父類的構造方法
-
重寫從父類中繼承的一般方法
- 例
// 定義一個人物的類 class Person { constructor (name,age) { // 表示類的構造方法 this.name = name; this.age = age; } // 類的一般方法 showName() { console.log(this.name); } } let person = new Person ('000', 18); console.log(person); person.showName(); // 子類 class Child extends Person { constructor (name,age,salary) { super(name, age); // 調用父類的構造方法 this.salary = salary; } showName () { console.log(this.name, this.age, this.salary) } } let child = new Child('www', 18, 10000 ); console.log(child); child.showName();
Promise對象
-
Promise對象
-
代表了未來某個將要發生的事件(通常是一個異步操作)
-
有了promise對象, 可以將異步操作以同步的流程表達出來, 避免了層層嵌套的回調函數(俗稱'回調地獄')
-
ES6的Promise是一個構造函數, 用來生成promise實例
-
-
使用promise基本步驟(2步)
-
創建promise對象
let promise = new Promise((resolve, reject) => { //初始化promise狀態為 pending //執行異步操作 if(異步操作成功) { resolve(value);//修改promise的狀態為fullfilled } else { reject(errMsg);//修改promise的狀態為rejected } })
-
調用promise的then()
promise.then(function( result => console.log(result), errorMsg => alert(errorMsg) ))
-
-
promise對象的3個狀態
-
pending: 初始化狀態
-
fullfilled: 成功狀態
-
rejected: 失敗狀態
-
- 例:
// 創建promiise對象 let promise = new Promise((resolve, reject) => { // 初始化promise狀態:pending console.log(111); // 執行異步操作,通常是發送ajax請求,開啟定時器 setTimeout(() => { console.log(333); // 根據異步任務的返回結果取修改promise的狀態 // 異步任務執行成功 // resolve('成功標記'); // 修改promise的狀態為 fullfilled:成功的狀態 // 異步任務執行失敗 reject('失敗標記');// 修改promise的狀態為 rejected:失敗的狀態 }, 2000) }) console.log(222); promise.then((data) => { // 成功的回調 console.log(data,'成功了') }, (error) => { // 失敗的回調 console.log(error,'失敗了')
Symbol
- ES5中對象的屬性名都是字符串,容易造成重名,污染環境。ES6中的添加了一種原始數據類型symbol(已有的原始數據類型:String, Number, boolean, null, undefined, 對象)
-
特點:
-
Symbol屬性值對應的值是唯一的,解決命名沖突問題(id)
-
Symbol值不能與其他數據進行計算,包括同字符串拼串
-
for in, for of遍歷時不會遍歷symbol屬性。
-
-
使用
-
調用Symbol函數得到symbol值
let symbol = Symbol(); let obj = {}; obj[symbol] = 'hello';
-
傳參標識
let symbol = Symbol('one'); let symbol2 = Symbol('two'); console.log(symbol);// Symbol('one') console.log(symbol2);// Symbol('two')
-
內置Symbol值
-
除了定義自己使用的Symbol值以外,ES6還提供了11個內置的Symbol值,指向語言內部使用的方法。
- Symbol.iterator:對象的Symbol.iterator屬性,指向該對象的默認遍歷器方法
-
- 例:
// 創建symbol屬性值 let symbol = Symbol(); console.log(symbol); let obj = {username: 'zh', age: 18}; obj[symbol] = 'symbol'; // 不能使用obj.symbol = '111' console.log(obj[symbol]); // for in, for of 不能遍歷symbol屬性 for (let i in obj) { console.log(i); } // 每創建一個symbol的值都需要通過 let symbol2 = Symbol('one'); let symbol3 = Symbol('two'); console.log(symbol2 == symbol3); // false console.log(symbol2, symbol3); // Symbol(one) Symbol(two) // 可以去定義常量 const Person_key = Symbol('person_key'); console.log(Person_key)
-
Iterator遍歷器
-
iterator是一種接口機制,為各種不同的數據結構提供統一的訪問機制
-
作用:
-
為各種數據結構,提供一個統一的、簡便的訪問接口;
-
使得數據結構的成員能夠按某種次序排列
-
ES6創造了一種新的遍歷命令for...of循環,Iterator接口主要供for...of遍歷。
-
-
工作原理:
-
創建一個指針對象(遍歷器對象),指向數據結構的起始位置。
-
第一次調用next方法,指針自動指向數據結構的第一個成員
-
接下來不斷調用next方法,指針會一直往后移動,直到指向最后一個成員
-
每調用next方法返回的是一個包含value和done的對象,{value: 當前成員的值,done: 布爾值}
-
value表示當前成員的值,done對應的布爾值表示當前的數據的結構是否遍歷結束。
-
當遍歷結束的時候返回的value值是undefined,done值為false
-
-
當使用for of去遍歷某一個數據結構的時候,首先去找Symbol.iterator,找到了就去遍歷,沒找到就不能
-
使用三點運算符、解構賦值,就是默認去調用iterator接口
-
- 原生具備iterator接口的數據(可用for of遍歷)
-
Array
-
arguments
-
set容器
-
map容器
-
String
-
注意:普通的對象(Object)沒有部署Iterator接口
-
- 為普通的對象部署iterator接口
let targetData = { [Symbol.iterator]: function () { let nextIndex = 0; // 記錄指針的位置 return { // 遍歷器對象 next: () => { return nextIndex < this.length ? { value: this[nextIndex++], done: false } : { value: undefined, done: true }; } } } }
Generator函數
-
概念:
-
ES6提供的解決異步編程的方案之一
-
Generator函數是一個狀態機,內部封裝了不同狀態的數據,
-
用來生成遍歷器對象
-
可暫停函數(惰性求值), yield可暫停,next方法可啟動。每次返回的是yield后的表達式結果
-
-
特點:
-
function 與函數名之間有一個星號
-
內部用yield表達式來定義不同的狀態
function* generatorExample(){ let result = yield 'hello'; // 狀態值為hello yield 'generator'; // 狀態值為generator }
-
generator函數返回的是指針對象(iterator),而不會執行函數內部邏輯
-
調用next方法函數內部邏輯開始執行,遇到yield表達式停止,返回{value: yield后的表達式結果/undefined, done: false/true}
-
再次調用next方法會從上一次停止時的yield處開始,直到最后
-
yield語句返回結果通常為undefined, 當調用next方法時傳參內容會作為啟動時yield語句的返回值。
-
- 例:
// generator函數 function* myGenerator() { console.log('第一次執行'); let result = yield 'hello'; // 當調用第一次 MG.next() 時,指針停在此處 console.log('第二次執行'); console.log(result); // aaaaa yield 'generator' console.log('遍歷完成') return "完成" } let MG = myGenerator(); // 返回一個遍歷器對象/遍歷器對象(Iterator) console.log(MG.next()); //done屬性反映當前generator是否遍歷完成,false表示沒有遍歷完 console.log(MG.next('aaaaa')); // next()調用的時候傳參,傳入的參數會作為next方法啟動時候的返回值 console.log(MG.next()); //
async函數
- 概念:真正意義上去解決異步回調的問題,同步流程表達異步操作
-
本質:Generator的語法糖
-
語法:
async function foo(){ await 異步操作; await 異步操作; }
-
特點:
-
不需要像Generator去調用next方法,遇到await等待,當前的異步操作完成就往下執行
-
返回的總是Promise對象,可以用then方法進行下一步操作
-
async取代Generator函數的星號*,await取代Generator的yield
-
語意上更為明確,使用簡單
-
字符串擴展
-
includes(str) : 判斷是否包含指定的字符串
-
startsWith(str) : 判斷是否以指定字符串開頭
-
endsWith(str) : 判斷是否以指定字符串結尾
-
repeat(count) : 重復指定次數
Number擴展
-
二進制與八進制數值表示法: 二進制用0b, 八進制用0o
-
Number.isFinite(i) : 判斷是否是有限大的數
-
Number.isNaN(i) : 判斷是否是NaN
-
Number.isInteger(i) : 判斷是否是整數
-
Number.parseInt(str) : 將字符串轉換為對應的數值
-
Math.trunc(i) : 直接去除小數部分
Array擴展
-
Array.from(v) : 將偽數組對象或可遍歷對象轉換為真數組
-
Array.of(v1, v2, v3) : 將一系列值轉換成數組
-
find(function(value, index, arr){return true}) : 找出第一個滿足條件返回true的元素
let arr2 = [1,2,3,4,5,6,7,8]; var result = arr2.find((item, index) => { return item > 4; }) console.log(result) // 5
-
findIndex(function(value, index, arr){return true}) : 找出第一個滿足條件返回true的元素下標
對象擴展
- Object.is(v1, v2):判斷2個數據是否完全相等。Object.is() 是根據字符串來進行判斷
- Object.assign(target, source1, source2..):將源對象的屬性復制到目標對象上
let obj = {}; let obj1 = {username:"anverson", age: 42}; let obj2 = {sex: "女"}; Object.assign(obj, obj1); // 將源對象的屬性復制到目標對象上 Object.assign(obj, obj2); console.log(obj); // {username: "anverson", age: 42, sex: "女"}
-
直接操作 __proto__ 屬性(ES6之前不能直接操作__proto__而需要通過prototype操作)
let obj2 = {}; obj2.__proto__ = obj1;
深度克隆
-
拷貝數據
- 基本數據類型:拷貝后會生成一份新的數據,修改拷貝以后的數據不會影響原數據,存儲的是該對象的實際數據
- 對象/數組:拷貝后不會生成新的數據,而是引用。修改拷貝以后的數據會影響原來的數據,存儲的是該對象在棧中引用(引用地址),真實的數據存放在堆內存里
-
淺拷貝(對象/數組):拷貝引用,拷貝后的數據會影響原來的數據,使得原數據不安全
-
深拷貝(深度克隆):拷貝的時候生成新數據,拷貝后的數據不會影響原來的數據
-
拷貝數據的方法:
-
直接賦值給一個變量:基本數據類型為深拷貝,對象/數組為淺拷貝
-
Object.assign():淺拷貝
- Array.prototye.concat():深拷貝,數組中有對象時對象為淺拷貝
- Array.prototype.slice():深拷貝,數組中有對象時對象為淺拷貝
- JSON.parse(JSON.stringfiy()):徹底的深拷貝(深度克隆),但拷貝的數據中不能有函數
-
- 深度克隆實現
// 檢測數據類型函數 function checkedType(target) { return Object.prototype.toString.call(target).slice(8, -1); } // 實現深度克隆 ---> 對象/數組 function clone(target) { let result, targetType = checkedType(target); if (targetType === 'Object') { result = {}; } else if (targetType === 'Array') { result = [] } else { return target; } // 遍歷目標數據 for (i in target) { let value = target[i]; // 判斷目標結構里的每一項值是否存在對象/數組 if (checkedType(value) === 'Object' || checkedType(value) === 'Array') { // 繼續遍歷獲取到的value result[i] = clone(value); } else { result[i] = value; } } return result; }
Set和Map
-
Set容器 : 無序不可重復的多個value的集合體
-
Set()
-
Set(array)
-
add(value)
-
delete(value)
-
has(value)
-
clear()
-
size
-
-
Map容器 : 無序的 key不重復的多個key-value的集合體
-
Map()
-
Map(array)
-
set(key, value):添加
-
get(key)
-
delete(key)
-
has(key)
-
clear()
-
size
-
- 例
// set let set = new Set([1, 3, 5, 5, 4, 8]); // 會將重復的5刪除 console.log(set.size, set); set.add(7); console.log(set.size, set); console.log(set.has(8)); console.log(set.has(0)); set.clear(); console.log(set.size, set); // map let map = new Map([['aaa', 'username'], ['ccc', 'username']]); console.log(map.size, map); map.set('age', 111); console.log(map.size, map); map.delete('aaa'); console.log(map.size, map);
for of循環
- 作用
-
遍歷數組
-
遍歷Set
-
遍歷Map
-
遍歷字符串
-
遍歷偽數組
-
- 例
// 利用set給數組去重 function removeSame(arr) { let newArr = []; let set = new Set(arr); for (i of set) { newArr.push(i) } return newArr; }
ES7
指數運算符(冪)
-
指數運算符(冪): **
- 例:
console.log(3**3); // 3的3次冪 --- 9
Array.prototype.includes(value)
-
判斷數組中是否包含指定value
- 例
let arr = [1,2,6,'abc']; console.log(arr.includes('a')); // false