一句話概括ES6 和 JS 的關(guān)系
- ES是標(biāo)準(zhǔn) JS是實(shí)現(xiàn)
ECMAScript 6.0(以下簡(jiǎn)稱 ES6)是 JavaScript 語(yǔ)言的下一代標(biāo)準(zhǔn)蝠检,已經(jīng)在 2015 年 6 月正式發(fā)布了谣殊。==它的目標(biāo)经窖,是使得 JavaScript 語(yǔ)言可以用來(lái)編寫復(fù)雜的大型應(yīng)用程序肠槽,成為企業(yè)級(jí)開發(fā)語(yǔ)言。==
- 日常喊法隘庄,ES ≈ JS囤官。
- ES6現(xiàn)在來(lái)說(shuō)泛指5.1版本后的Javascript標(biāo)準(zhǔn)。
- 從2015年開始后颤霎,越來(lái)越多的瀏覽器開始支持ES6標(biāo)準(zhǔn)的媳谁,當(dāng)然即使如此它仍然不夠普及(用戶瀏覽器上跑的,程序員們的寫法友酱,大部分還是ES5標(biāo)準(zhǔn))晴音。
var 變成了 let定義變量 和 const定義常量
- ES6以前:都用var
// var 和 function 存在變量提前聲明
// var 只會(huì)提前聲明 function既聲明又定義
console.log(a); // a=undifined
console.log(getA()); // '123'
var a = 1;
function getA() {
return 123;
}
// var 和 function 定義的變量可以重復(fù)聲明重新賦值
var a = 1;
var a = 2;
function getA() {}
// 全局作用域下 var 和 function 定義的變量相當(dāng)于給全局對(duì)象window增加屬性window.變量名 = 值
console.log(window.a);
console.log("getA" in window);
- let
// let 變量
// console.log(a); //報(bào)錯(cuò):a is not defined “a未被定義”
// 【1】let 定義的變量沒有提前聲明的特點(diǎn)
let a = 1;
// 【2】let 定義的變量無(wú)法像 var 一樣重復(fù)聲明
// let a = 2; //報(bào)錯(cuò):'a' has already been declared “a已經(jīng)被定義”
// 【3】let 定義的變量不會(huì)在全局對(duì)象window下生成新的屬性
console.log(window.a);
// 越來(lái)越嚴(yán)謹(jǐn)...
- const
// const 常量
// 1、無(wú)法提前聲明 2缔杉、不可以重復(fù)聲明 3锤躁、全局作用域下不會(huì)給window對(duì)象增加屬性(ES6通用)
let a; //let 定義變量可以不給值 值默認(rèn)為undifined
console.log(a);
a = 1; //let 定義的變量不能重新定義重名變量 但可以重新賦值
console.log(a);
// const b; //會(huì)報(bào)錯(cuò):Missing initializer in const declaration “忘記給const定義的常量一個(gè)初始值”
// 【4】 const定義的常量一旦聲明必須賦值
const b = 1;
// 【5】const定義的常量一旦聲明將無(wú)法在程序運(yùn)行中重新賦值
// const b = 2; //會(huì)報(bào)錯(cuò):Identifier 'b' has already been declared “b已經(jīng)被定義了”
- {塊級(jí)作用域}
// {塊級(jí)作用域}
{
let a = 1;
console.log("第1作用域a=",a);;
var b = 1;
}
console.log("b即使在塊級(jí)作用域中定義,依舊是全局的,b=",b);
{
let a = 2;
console.log("第2作用域a=",a);
var b = 2;
}
console.log("b即使在塊級(jí)作用域中定義或详,依舊是全局的,同時(shí)依舊會(huì)給window增加屬性window.b",window.b);
console.log("塊級(jí)作用域下系羞,var和function聲明的變量依舊是全局的郭计。");
// console.log(a); // 報(bào)錯(cuò):a is not defined “a未定義” 在塊級(jí)作用域下a定義的變量只在作用域內(nèi)有效
/**
* 實(shí)際應(yīng)用
* 對(duì)象{} for(){} if(){}
*/
// ES6中,花括號(hào)想表示對(duì)象椒振,{}不可以放在行首昭伸。(ES6以為那是一個(gè)塊級(jí)作用域)
let obj = {name:"liuhaoyu",age:10};
({name:"liuhaoyu", age:10});
eval('var o = {name:"liuhaoyu", age:10}'); //eval將字符串轉(zhuǎn)成對(duì)象的時(shí)候也有這個(gè)問題
// if()
if(1) {
var x = 1;
let y = 1;
function getX() {
return x;
}
}
// {里面用var} 下面的變量會(huì)提前聲明(即使if(false){} x依然等于undifined**但 function 不會(huì):function要if條件為true的時(shí)候,先給函數(shù)聲明賦值,再執(zhí)行if里面的代碼**)
// {里面用var 和 function} 下面的變量會(huì)存在于全局作用域(下面兩個(gè)永遠(yuǎn)存在)
console.log(x);
// console.log(y); //y is not defined , if 里面 let 定義的變量 , 只在{里面跑,跑完出不來(lái)}
console.log(getX());
for(var i=0; i<5; i++) {
console.log("現(xiàn)在i=",i);
}
console.log("for循環(huán)結(jié)束后,i=",i);
for(let j=0; j<5; j++) {
console.log("現(xiàn)在j=",j);
}
// console.log("for循環(huán)結(jié)束后,j=",j); //j is not defined
console.log("let定義的變量j,for循環(huán)跑完就沒了");
- 總結(jié):比以往更加嚴(yán)謹(jǐn),let聲明過的變量無(wú)法再重新聲明澎迎,let存在作用域的概念庐杨,最顯著的提升應(yīng)該是for循環(huán)那一部分,跑完就釋放了很好夹供。const在程序執(zhí)行時(shí)無(wú)法修改灵份。
解構(gòu)賦值
- 什么是解構(gòu)賦值:等號(hào)左右兩邊結(jié)構(gòu)一樣(或按照一定規(guī)則類似)。左邊的變量逐一取值對(duì)應(yīng)右邊的每個(gè)元素或?qū)傩浴?/li>
- 數(shù)組解構(gòu)
// 什么是解構(gòu)賦值,數(shù)組舉例:
// 先來(lái)個(gè)數(shù)組
let arr = [1, 2, 3];
// 現(xiàn)有變量 x,y,z想分別等于數(shù)組里的1,2,3
// ES5的寫法
// let x = arr[0];
// let y = arr[1];
// let z = arr[2];
// ES6提供的解構(gòu)賦值
let [x, y, z, l, m, n] = arr;
console.log("x=",x,",y=",y,",z=",z);
// 多出來(lái)的 = undifined
console.log("l=",l,",m=",m,",n=",n);
// 設(shè)默認(rèn)值 x2=10,只有后面解構(gòu)的值是undifined的時(shí)候,才會(huì)取默認(rèn)值
let [x1, x2=10] = [1, undefined];
let [y1, y2=10] = [1]; // 不寫就是undifined
console.log(x1, x2);
console.log(y1, y2);
// 省略賦值 想讓m1=1,m2=3:把中間空出來(lái)即可
let [m1, , m2] = [1, 2, 3];
console.log(m1,m2);
// 不定參數(shù)賦值 n1=1,n2=2,n3將會(huì)定于后面所有的元素組成的數(shù)組[3,4,5,6,7]...
let [n1, n2, ...n3] = [1,2,3,4,5,6,7]; // ...擴(kuò)展運(yùn)算符
console.log(n3);
- 對(duì)象解構(gòu)
// 對(duì)象解構(gòu)賦值 要求變量名和屬性名是一致的(name=obj.name)
// let {name, age} = {name:'liuhaoyu', age:10};
// console.log(name);
// 設(shè)默認(rèn)值
let {name, age=100} = {name:'liuhaoyu'};
console.log(age);
// 先定義再賦值
let x1,x2;
// {x1, x2} = {x1:1, x2:2}; //塊作用域的問題
({x1, x2} = {x1:1, x2:2}); //這么寫就好了 {}不再行首即可
- 數(shù)組對(duì)象嵌套解構(gòu)(只要左邊結(jié)構(gòu)和右邊一樣即可)
let obj = {
name: 'liuhaoyu',
age: undefined,
// 嵌套個(gè)數(shù)組
array: [
'a1',
'a2',
'a3',
'a4',
// 數(shù)組里嵌套個(gè)對(duì)象
{
o1: 'o1',
o2: 'o2',
o3: 'o3'
}
],
}
// 如何解構(gòu):照著結(jié)構(gòu)寫就行了,注意數(shù)組后面有個(gè):
let {name, age, array:[a1,a2,a3,a4,{o1, o2,o3}]} = obj;
console.log(name,age,a1,o1);
- 數(shù)據(jù)類型不對(duì)應(yīng)的結(jié)構(gòu)
// 使用數(shù)組解構(gòu)字符串:會(huì)將右邊字符串轉(zhuǎn)換為數(shù)組
let [x, y] = "123";
// let [m, n] = 1; //會(huì)報(bào)錯(cuò):1 is not iterable 要求必須右邊是一個(gè)有l(wèi)ength屬性的東西(類數(shù)組:比如dom操作獲取一組元素,普通數(shù)組,Set對(duì)象,Map等)
console.log(x,y);
// 使用對(duì)象解構(gòu) : 如果右邊不是對(duì)象,會(huì)轉(zhuǎn)為對(duì)象,再進(jìn)行解構(gòu)賦值
// let {__proto__:a} = 1; 這句話的意思是,將 1這個(gè)對(duì)象中的proto屬性用變量a接收.
let {__proto__:a} = 1;
console.log(Object(1)); //看看1轉(zhuǎn)為對(duì)象是什么樣子
console.log(a); // undefined
let {length:objLen} = "1234";
console.log(objLen);
- 在參數(shù)列表里解構(gòu)
// 在參數(shù)列表中解構(gòu)數(shù)組
// 要求a等于數(shù)組第一個(gè)元素,b等于數(shù)組第二個(gè)元素,c等于剩下所有元素組成的數(shù)組
function getA([a,b,...c]) {
console.log(a);
console.log(b);
console.log(c);
}
let arr = [1,2,3,4,5,6,7,8,9];
getA(arr);
// 在參數(shù)列表中解構(gòu)對(duì)象 還能給默認(rèn)值
function getO({name, age=100}) {
console.log(name);
console.log(age);
}
let obj = {name:'liuhaoyu', age:undefined};
getO(obj);
// 在參數(shù)列表中解構(gòu)對(duì)象 給默認(rèn)值,要求不傳任何參數(shù)不報(bào)錯(cuò)依然可以打印name和age
function getObj1({name='liuhaoyu', age='100'} = {}) {
console.log(name);
console.log(age);
}
// 看看這種寫法
function getObj2({name, age} = {name:'liuhaoyu', age:100});
getObj1();
getObj2(); //不寫都一樣
getObj1({}); // 傳了一個(gè)空對(duì)象.默認(rèn)值為空對(duì)象,沒問題
getObj2({}); // 傳了一個(gè)空對(duì)象,默認(rèn)值為{name:'liuhaoyu', age:100},現(xiàn)在值為{},所以會(huì)出現(xiàn)name,age = undefined
字符串方法擴(kuò)展
// 看看字符串原型有哪些方法和屬性
// console.log(String.prototype);
let str = "abcdefg12345";
// 1 includes("指定字符串string", 開始查找的位置int默認(rèn)0) 返回 true|false
console.log(str.includes('cdef', 3));
// 2 startsWiths("指定字符串string", "開始查找的位置int默認(rèn)0") | endsWith, 判斷字符串是否以指定字符 開頭 | 結(jié)尾
console.log(str.startsWith('bcd', 1));
console.log(str.endsWith('345',3)); //endsWith第二個(gè)參數(shù)是判斷:前幾個(gè)字符組成的字符串是否以第一個(gè)參數(shù)結(jié)尾
// 3 repeat(重復(fù)多少次)
console.log(str.repeat(3));
// 4 ES7新增 : padStart(最終長(zhǎng)度int, "指定字符string") padEnd 按照指定字符,補(bǔ)全字符串的長(zhǎng)度
let str1 = 'ab';
console.log(str1.padStart(5,"cde")); //補(bǔ)在前面
console.log(str1.padEnd(3,"cde")); //補(bǔ)在后面 , 長(zhǎng)度超了自動(dòng)截取
==模板字符串==
// `` 包起來(lái),跟普通字符串一樣
let str = `哈哈`;
// 但是可以添加變量 ${}
let strMid = 'ha';
str = `哈 ${strMid} 哈`;
console.log(str);
// 實(shí)際應(yīng)用: js動(dòng)態(tài)渲染網(wǎng)頁(yè)
var content = "我是要被渲染進(jìn)去的內(nèi)容";
// ES5中
var htmlText =
'<div>' +
'<span>' + content + '</span>';
'</div>';
// 插入 $("body").innerHTML(htmlText);
// ES6中
let htmlText1 = `
<div>
<span> ${content} </span>
</div>
`;
數(shù)組方法擴(kuò)展
/**
* 數(shù)組的空位 : 數(shù)組某個(gè)索引位置沒有任何值empty *undefined不是空位*
*/
let arr = [,undefined,,,]; //一個(gè) , 一個(gè)空位
console.log(arr.length);
// in: 判斷數(shù)組索引位置上有沒有值 undefined不是空位 返回值為true
console.log(1 in arr);
// 在ES5中 數(shù)組方法對(duì)空位的處理不一致 一般直接跳過空位
let arr1 = [1,2,,,,3];
arr1.filter(function(item) { // filter是ES5的方法
console.log(item); //跳過空位
});
// 在ES6中 將空位處理為undefined
arr1.find(function(item) {
console.log(item);
});
for(let item of arr1) {
console.log(item);
}
// 面試題 得到一個(gè)有7個(gè)1的數(shù)組
console.log(Array(7).fill(1));
對(duì)象擴(kuò)展
- 更簡(jiǎn)潔的表達(dá)方式
let name = "liuhaoyu", age = 100;
let person = {name, age};
// let person = {name:name, age:age};
let str = 'name';
let obj = {
fn(){},
// fn:function(){}
// 屬性名是字符串
str: name, //這個(gè)是把name 賦值給了 obj.str
// [變量]: 值, //這樣可以把變量的值當(dāng)作屬性名key.
[str]: name, //這個(gè)是把name 賦值給了 obj.name
["my"+str]: name, //還可以拼接
}
console.log(obj.name);
- set和get
// 普通set
// obj.name = 'liuhaoyu';
// 普通get
// obj.name
let obj = {
get name() {
// 這個(gè)函數(shù)只要調(diào)用 obj.name時(shí) 就會(huì)觸發(fā)
// 可以通過return 返回值
return 'liuhaoyu';
},
// 必須有1個(gè)參數(shù)
// set name(value) {
// this.name = value;
// 不能這么寫,會(huì)一直調(diào)用自己
// }
}
console.log(obj.name);
- 對(duì)象的擴(kuò)展方法
// Object(); //將參數(shù)變成對(duì)象
// console.log(Object(1));
// is 判斷兩個(gè)值是否相等
// ES5 "===" 判斷的問題 : NaN !== NaN (NaN和任何值都不等) | -0 === 0 (-0和0又相等)
console.log((NaN === NaN)); //false
console.log((-0 === 0)); //true
// 用Object.js判斷
console.log(Object.is(NaN, NaN)); //true
console.log(Object.is(-0, 0)); //false
// assign 合并對(duì)象
let obj1 = {name:'liuhaoyu'};
let obj2 = {age:10};
Object.assign(obj1, obj2); //將第個(gè)對(duì)象的所有屬性 合并到第一個(gè)對(duì)象
console.log(obj1); //第一個(gè)會(huì)變
console.log(obj2); //第二個(gè)不變
obj1 = {name:'liu'};
obj2 = {name:'liuhaoyu', age:20};
Object.assign(obj1, obj2);
console.log(obj1); //如果兩個(gè)屬性名稱重復(fù) 那么第二個(gè)會(huì)覆蓋第一個(gè)的值
console.log(obj2);
// ES7中提供的 對(duì)象的擴(kuò)展運(yùn)算符 ... 合并對(duì)象
let o1 = {name:'liu'};
let o2 = {name:'hao'};
let me = {...o1, ...o2}; // 這樣合并為一個(gè)新對(duì)象,原對(duì)象o1 o2不變
console.log(o1);
console.log(o2);
console.log(me);
// getOwnPropertyDescriptor 獲取一個(gè)對(duì)象中的某個(gè)屬性的描述
let desc = Object.getOwnPropertyDescriptor("123", length); // 獲取對(duì)字符串對(duì)象的 length的描述
console.log(desc);
// 具體打印的屬性
// configurable: false #不可配置 (是否可以刪除這個(gè)屬性)
// enumerable: true #可枚舉
// value: "1" #具體值
// writable: false #不可修改
// keys() 返回值 數(shù)組 [所有可枚舉的屬性]
console.log(Object.keys(me));
// values() 返回值 數(shù)組 [所有可枚舉屬性的鍵值]
console.log(Object.values(me));
// entries() 返回值 數(shù)組 [[鍵], [值]]
console.log(Object.entries(me));
- proxy
let user = {}; // 有一個(gè)人
user.fname = 'Horry'; //名hoory
user.lname = 'yoo'; //姓yoo
// user.name = user.fname + '.' + user.lname; //他的全名就是Horry.Yoo
console.log(user.name);
// 每次算name很麻煩
user = {
fname: 'Horry',
lname: 'Yoo',
name: function() {
return this.fname + '.' + this.lname;
}
};
// 想要獲得全名name()
console.log(user.name());
// 這個(gè)()看著很刺眼,我希望全名是個(gè)屬性而不是個(gè)方法
let newUser = new Proxy({}, {
get: function(obj, prop) {
if(prop === 'name') {
return obj.fname + '.' + obj.lname;
}
}
});
/**
* new Proxy({原對(duì)象}, {
* // 代理對(duì)象
* get: function(obj表示原對(duì)象, prop表示叫的屬性名) {
* // 判斷prop的值 返回叫的指定屬性的值
* }
* })
*/
newUser.fname = 'haoyu';
newUser.lname = 'Liu';
console.log(newUser.name);
新的數(shù)據(jù)類型和對(duì)象
- Symbol
/**
* Symbol 是ES6新增的一個(gè)基本數(shù)據(jù)類型
*/
// 定義 Symbol()
let sym1 = Symbol();
let sym2 = Symbol();
console.log(typeof(sym1));
console.log(typeof(sym2));
console.log(sym1 === sym2); // 不全等
// Symbol數(shù)據(jù)類型的特點(diǎn) : 跟字符串差不多 但是使用Symbol()函數(shù)得到一個(gè)數(shù)據(jù) 每一個(gè)都是完全不同的
// 可以接收一個(gè)參數(shù)('描述這個(gè)Symbol')
// 即使描述一樣 值也是不一樣的
sym1 = Symbol('foo');
sym2 = Symbol('foo');
console.log(sym1);
console.log(sym2);
// 具體作用: 作對(duì)象屬性的名稱,防止對(duì)象屬性被重寫
let person = {
name: 'haoyu',
}
person.name = 'horry'; //加入我們引用了一個(gè)person對(duì)象,但不知道person里有name屬性,我們大膽地把它改了
//這樣做很危險(xiǎn),可能有其他的代碼依賴這person.name這個(gè)屬性,我們把它改了可能直接導(dǎo)致整個(gè)程序崩掉
console.log(person);
// ES6中解決它:
let name = Symbol('name');
person = {
[name] : 'haoyu',
}
person.name = 'horry';
console.log(person);
// 再看個(gè)例子
// file1.js
let p;
{
let n = Symbol('name');
p = {
[n] : 'file1',
};
}
// file2.js
{
let n = Symbol('name');
p[n] = 'file2';
}
console.log(p);
// 你會(huì)發(fā)現(xiàn)p對(duì)象里有兩個(gè)
// Symbol(name): "file1"
// Symbol(name): "file2"
// 即在不同的作用域, Symbol的值無(wú)法改變
- Set
/**
* Set
* 可以理解為一個(gè)元素的值絕對(duì)不會(huì)重復(fù)的強(qiáng)數(shù)據(jù)類型數(shù)組
*/
// 先來(lái)個(gè)數(shù)組
let arr = [1, 2, 3, 3]; //可以寫2個(gè)3
// 定義set : new Set(傳個(gè)數(shù)組進(jìn)來(lái))
let set = new Set(arr);
console.log(set); //你會(huì)發(fā)現(xiàn)3只出現(xiàn)了一次
set = new Set([1,'1', 2, '2', 3, '3']);
console.log(set); //在set里 1!='1' 即值沒有重復(fù)
// Set的一些常用屬性和方法
// Set.size ≈ Array.length
console.log('size中共有元素:', set.size);
// 添加和刪除 元素
set.add(4); //添加元素
set.add(4); //添加元素
// 添加兩次也不會(huì)報(bào)錯(cuò),只是依然只有一個(gè)數(shù)字4存在Set中
set.delete('2'); //刪除元素
set.delete('2'); //刪除元素
// 刪除同理,刪了再刪,不會(huì)報(bào)錯(cuò)
// 看看有沒有某個(gè)元素 有true 沒有false
console.log(set.has(5));
// 清空Set
set.clear();
console.log(set);
- Map
// 創(chuàng)建一個(gè)Map
// new Map([[key, value], [key, value], [key, value]]);
// 參數(shù)要求 傳進(jìn)來(lái)的是一個(gè)二維數(shù)組 一維數(shù)組必須是[第一個(gè)元素當(dāng)key, 第二個(gè)元素當(dāng)value];
let map1 = new Map([[1,'liu'], [2, 'hao'], [3, 'yu']]);
console.log(map1);
// 一個(gè)對(duì)象 屬性名必須是字符串,如果你寫的不是字符串也默認(rèn)轉(zhuǎn)換為字符
let o = {};
let a = [];
let obj = {
true: 'true', //前面的true 就不是關(guān)鍵字"真"了 而是可以通過obj.true調(diào)用的一個(gè)屬性的屬性名
1: 1, //同理前面的1也不是常量1,而是obj中的一個(gè)屬性的屬性名
[a]: [],
[o]: {}, // 即使我們?cè)趯?duì)象外面去定義變量然后用[變量名]這樣的方式創(chuàng)建對(duì)象的屬性,屬性名依然會(huì)是一個(gè)字符串
}
// console.log(obj); //也就是說(shuō)無(wú)論如何, 屬性名一定是個(gè)字符串
// Map解決了這樣一個(gè)問題: 屬性名(key)可以是任意數(shù)據(jù)類型
let map2 = new Map([['name','liuhaoyu'], [true, 'true'], [{age:12}, {age:12}], [[1,2,3], [1,2,3]]]);
console.log(map2); //上面的Map , 四個(gè)鍵值對(duì)的key 分別是 字符串, 布爾, 對(duì)象, 數(shù)組
// 當(dāng)然對(duì)象和數(shù)組這種可以給它一個(gè)第一參數(shù)[暫時(shí)叫做代號(hào)吧, key, value]
map2 = new Map([['name','liuhaoyu'], [true, 'true'], [o, {age:12}, {age:12}], [a, [1,2,3], [1,2,3]]]);
// Map常用的屬性和方法
// size 鍵值對(duì)的個(gè)數(shù)
console.log(map2.size);
// get 通過key或代號(hào)獲取value
console.log(map2.get('name'));
console.log(map2.get(true));
console.log(map2.get(o));
console.log(map2.get(a));
// set 通過key或代號(hào)新增或修改value
map2.set('age', 20); //沒有age 新增age
map2.set('name','horryyoo'); //有name 修改name
console.log(map2);
// has 通過key判斷有沒有對(duì)應(yīng)的value值
console.log(map2.has('age'));
// delete 通過key或代號(hào)干掉一個(gè)屬性 找到元素并刪除成功為true 找不到或刪不掉為false
console.log(map2.delete('age'));
console.log(map2);
// 清空 沒有返回值
// map2.clear();
// console.log(map2.size);
// 遍歷forEach(順序必須是 參數(shù)1是值, 參數(shù)2是鍵, 參數(shù)3是實(shí)例)
map2.forEach((value, key, instance)=> {
console.log(value); //value
console.log(key); //key
console.log(instance); //實(shí)例
});
// for of + Map.keys() 遍歷所有的key
for (let key of map2.keys()) {
console.log(key);
}
// for of + Map.values() 遍歷所有的value
for (let value of map2.values()) {
console.log(value);
}
// 練習(xí):給你一個(gè)數(shù)組變成Map實(shí)例
let ary = ['liuhaoyu', 'JS', 'ES6', 'AngularJS2+', 'Laravel'];
let map3 = new Map();
for (let [index, item] of ary.entries()) {
map3.set(index, item);
}
console.log(map3);
oop => 類的擴(kuò)展
class關(guān)鍵字 和constructor()構(gòu)造函數(shù)
// ES5 通常是這樣弄個(gè)對(duì)象出來(lái)的
// 類定義
function Fn() {
this.x = 10;
}
// 實(shí)例化
var f = new Fn();
// ES6 有 class 了
class A {
// 同時(shí)有構(gòu)造函數(shù)了
constructor(x, y) {
this.x = x; // 添加私有屬性
this.y = y;
}
}
let a = new A(1,2);
console.log(a);
類的“立即執(zhí)行” 和 變量提前聲明
// 立即執(zhí)行 let 變量 = new class {構(gòu)造函數(shù)(){}}("傳入?yún)?shù)立即執(zhí)行");
let aa = new class {
constructor(name) {
this.name = "name";
}
}("liuhaoyu");
console.log(aa);
// ES5 老方法定義類和實(shí)例化時(shí)哮洽,變量會(huì)提前聲明
let ff = new FF();
console.log(ff);
function FF() {
this.f = "ff";
}
// ES6
// let c = new C(); //ES6中沒有變量提聲:這里會(huì)報(bào)錯(cuò)找不到C
class C {
constructor() {
this.c = 'c';
}
}
let c = new C(); //ES必須寫在后面
繼承 extends
class A {
constructor(x, y) {
this.x = x;
this.y = y;
}
fn1() {
console.log('我是A.fn1()');
}
static fn2() {
console.log('我是A.fn2()');
}
}
// 繼承extends
class B extends A {
constructor(x, y) {
// this.y = y; // 報(bào)錯(cuò) ust call super constructor in derived class before accessing 'this' or returning from derived constructor
// console.log(this); // 子類沒有 "this" 它的this是父類填渠,因此需要調(diào)用super()方法
super(x, y);
// 在super()執(zhí)行完成后,就可以使用this了
alert(this.y);
}
// 當(dāng)然 子類的constructor()構(gòu)造函數(shù)是可以省略的鸟辅,它會(huì)自動(dòng)繼承父類的constructor()方法
// 所以上面所有代碼都在“脫了褲子放屁”
// 方法可以重寫
fn1() {
console.log('我是B.fn1()');
}
static fn2() {
console.log('我是B.fn2()');
}
}
let b = new B(1,2);
b.fn1();
A.fn2();
B.fn2();
console.log(b);
靜態(tài)方法
// static 定義靜態(tài)方法 (比如Array.of)
class AA {
static myStaticFn() {
alert('這是一個(gè)靜態(tài)方法揭蜒,只有類本身才能調(diào)用。');
}
}
AA.myStaticFn();
// 靜態(tài)方法無(wú)法被實(shí)例拿到
// let aa = new AA();
// aa.myStaticFn(); // 報(bào)錯(cuò) aa.myStaticFn is not a function “對(duì)象是繼承不到靜態(tài)方法的”
// 靜態(tài)方法也無(wú)法被繼承
class B1 {
static myStaticFn() {
console.log('我是b1的靜態(tài)方法');
}
}
class B2 extends B1 {}
// console.log(B2.myStaticFn()); //undefined
// 但是我非要拿到B1的靜態(tài)方法怎么辦呢剔桨?
class B3 extends B1 {
// 1、再定義一個(gè)靜態(tài)方法
static myStaticFn2() {
// 2徙融、這個(gè)方法執(zhí)行調(diào)用 super這里相當(dāng)于父類B1.myStaticFn()父類的靜態(tài)方法
super.myStaticFn();
}
}
// let b3 = new B3();
// console.log(b3.myStaticFn2());
函數(shù)方面的擴(kuò)展
- ==默認(rèn)值問題==
/**
* 參數(shù)默認(rèn)值問題
*/
// function fn(x,y) {
// // ES5我們這樣設(shè)置默認(rèn)值 如果 x為真 函數(shù)內(nèi)的x = x 否則 = 我們?cè)O(shè)置的默認(rèn)值'liuhaoyu'
// x = x || 'liuhaoyu';
// y = y || 'ES6';
// }
// // 問題來(lái)了
// fn(0,0); //這樣傳進(jìn)去 0被讀成false 則函數(shù)內(nèi)x = 'liuhaoyu'
// ES6支持參數(shù)列表中設(shè)置默認(rèn)值
function fn(x='liuhaoyu', y='ES6'){};
// ES6參數(shù)列表還支持解構(gòu)賦值
function fn1({name="liuhaoyu", age="100"}={}) {
console.log(name);
console.log(age);
}
fn1();
/**
* function.length 屬性 沒有默認(rèn)值的形參的個(gè)數(shù)
*/
function fn2(x, y) {
}
fn2(1,2);
console.log(fn2.length);
/**
* 參數(shù)默認(rèn)值位置
* 一般參數(shù)的默認(rèn)值都放在最后面
*/
// function fn3(x=10, y=20) {}
// arguments 類數(shù)組 實(shí)參集合
function fn4(...arg) {
// ES5 獲取實(shí)參 集合
console.log(arguments); //對(duì)象
// ES6 獲取實(shí)參集合 參數(shù)列表中解構(gòu)取值
console.log(arg); // 數(shù)組
}
fn4(1,2,3,4,5);
// 參數(shù)作用域
let x = 100;
function fn5(x, y=x) {
console.log(y); //為什么y=1 而!= 100呢
}
fn5(1);
/**
* 解釋: 參數(shù)列表作用域是這么找值的
* x=1 進(jìn)來(lái)了 y=x 這里的這個(gè)x是先找函數(shù)里面的x,沒有,才會(huì)找函數(shù)外面的x(上面的x=100)
*/
- 函數(shù)名問題
function fn() {
}
// 獲取當(dāng)前函數(shù)名
console.log(fn.name);
// 匿名函數(shù)名
console.log((function(){}).name);
// 特殊情況
// 1. 通過bind方法得到一個(gè)新的函數(shù) name是 "bound 原來(lái)函數(shù)名字"
let fn1 = fn.bind(null);
console.log(fn1.name);
// 2. 通過構(gòu)造函數(shù)創(chuàng)建一個(gè)函數(shù) new Function("形參", "函數(shù)體") name 是 "anonymous" 即匿名
let fn2 = new Function("x,y", "console.log(x,y); return x+y;");
console.log(fn2(10,100));
console.log(fn2.name);
// 面試題 禁止使用eval() 使用new Function的方法 取得str 的json字符串
let str = '[{"name": "珠峰"}, {"age":100}]';
let arr = (new Function("return" + str))();
// console.log(arr);
// arr ==> [{"name": "珠峰"}, {"age":100}]
- 擴(kuò)展運(yùn)算符:更多的是操作數(shù)組
/**
* 擴(kuò)展運(yùn)算符 ...
*/
// 將非數(shù)組變成數(shù)組(類數(shù)組 length) [...]
let str = "123";
console.log([...str]);
function fn(str) {
console.log([...arguments]);
}
fn(str);
// 將數(shù)組變成非數(shù)組
let arr1 = [1,2,3,4];
let arr2 = [10,20,30,40];
// 合并他們
newArr1 = arr1.concat(arr2); //可以用Array.concat()函數(shù)
newArr2 = [...arr1,...arr2]; //也可以使用擴(kuò)展運(yùn)算符把他們連起來(lái)
console.log(newArr1);
console.log(newArr2);
/**
* 實(shí)際應(yīng)用
*/
// 求數(shù)組最大值
let ary = [1,23,12,45,242,132];
// Math.max(ary); //×
// Math.max.apply(null, ary); //√
let max = Math.max(...ary); //把數(shù)組展開
console.log(max);
// 把數(shù)組展開傳進(jìn)參數(shù)列表
function fn1(...ary) {
}
- 箭頭函數(shù)
function fn(x, y) {
}
// 箭頭函數(shù)都是匿名函數(shù)
// let 函數(shù)名 = (參數(shù)列表) => {函數(shù)體}
let fn1 = () => {};
// 參數(shù)列表只有一個(gè)參數(shù) 函數(shù)體只有一段代碼 可以省略參數(shù)列表 函數(shù)體可以省略{} 和 return
let fn2 = x => x+1;
// 通常函數(shù)當(dāng)作參數(shù)的時(shí)候使用箭頭函數(shù)
let ary = ['liu', 1, 2, 3, 'haoyu'];
let newAry = ary.filter(item => typeof item === "number");
console.log(newAry);
/**
* 特點(diǎn)
*/
// 1. 箭頭函數(shù)沒有this指向 里面的this是上一級(jí)的作用域
let obj = {
fn: function() {
let f=()=> {
console.log(this); // 這里的this得是上一級(jí)
}
f();
},
}
obj.fn();
// 2. 箭頭函數(shù)沒有arguments
let f1 = () => {
console.log(arguments);
}
// f1(123);
// 我非要拿到實(shí)參集合
let f2 = (...arg) => {
console.log(arg);
}
f2(1,2,3);
// 3. 箭頭函數(shù)不可以用作構(gòu)造函數(shù) 因?yàn)椴豢梢允褂胣ew 執(zhí)行
function FF () {
}
console.log(new FF);
let F=()=>{};
console.log(new F); // F is not a constructor
- async 異步函數(shù)
console.log("這是同步代碼開始1");
// 2
async function fn() {
return "執(zhí)行fn()方法成功2";
}
console.log("這是定義了一個(gè)一步方法fn()3");
fn().then(function(res){
console.log(res);
}).catch(function(e) {
console.log(e);
});
console.log("我已經(jīng)調(diào)用了方法fn()洒缀,并且給他“綁定”了then()執(zhí)行成功回調(diào)和catch()執(zhí)行錯(cuò)誤回調(diào)4");
/**
* 執(zhí)行順序:1 3 4 2
* 原因:我們定義的是一個(gè)非阻塞的異步方法 anync function () {}
* 好處:異步執(zhí)行:程序跑到2的時(shí)候,開個(gè)任務(wù)欺冀,繼續(xù)往下執(zhí)行树绩,最后跑回去執(zhí)行2。(類似node.js)
* 調(diào)用方法: 1調(diào)用函數(shù)fn().2調(diào)用then(res) {//這里的res就是fn()執(zhí)行完成后return回來(lái)的結(jié)果}.3調(diào)用catch(e) {//這里的e就是錯(cuò)誤信息}
*/
ES 的 “模塊化”
- 定義模塊 和 暴露模塊 ==e.js==
// 定義
var firstName = 'Michael';
var lastName = 'Jackson';
var year = 1958;
// 暴露
export {firstName, lastName, year};
- 引用模塊 和 使用它內(nèi)部的元素(變量隐轩、函數(shù)等) ==i.js==
// 引用
// 全部引用
// import * as mj from './e';
// 調(diào)用
// console.log(mj.firstName);
// 解構(gòu)引用
import {firstName, lastName} from './e';
console.log(firstName);
- 在html文檔中調(diào)用模塊化的js文件時(shí)
<!-- 寫上type="module" -->
<script type="module" src="./modules/i.js"></script>
TS
- 大白話:改進(jìn)了JS饺饭。
- ES6語(yǔ)法寫,可以編譯為支持ES5及以下的版本职车。
開發(fā)環(huán)境搭建
- npm安裝typescript
# 先裝cnpm
npm install -g cnpm --registry=https://registry.npm.taobao.org
# 再用cnpm 裝 typescript
cnpm install -g typescript
- 編譯 tsc 命令編譯 .ts 文件
tsc name.ts
會(huì)生成一個(gè)編譯后可以放在瀏覽器里執(zhí)行的.js文件
多行字符串
- 這個(gè)好像是ES6提供的吧【``】
# ES5-
var htmlText = "aaa" +
"bbb" +
"ccc"; //無(wú)法換行 換行需要用+連接
# ES6 / TS
var htmlText = `aaa
bbb
ccc
`;
模板字符串
var htmlText = `
<div>
<span> ${變量|方法()} </span>
</div>
`
自動(dòng)拆分字符串
// 定義一個(gè)方法
function test(template, name, age) {
console.log(template);
console.log(name);
console.log(age);
}
// 定義參數(shù)
var myName = 'liuhaoyu';
var getAge = function() {
return 500;
}
// 調(diào)用方法 test`整個(gè)對(duì)應(yīng)參數(shù)template, ${myName}對(duì)應(yīng)參數(shù)name, ${myAge}對(duì)應(yīng)參數(shù)age`
test`hellow my name is ${myName}, I'm ${ageAge()}`
函數(shù)默認(rèn)參數(shù)
/**
* 默認(rèn)參數(shù)值
*/
// 調(diào)用test()時(shí)瘫俊,我如果只寫兩個(gè)參數(shù),那么c默認(rèn)值'liuhaoyu'
// 有默認(rèn)值的參數(shù)最好寫在最后面
function test(a:string, b:string, c:string='liuhaoyu') {
console.log(a);
console.log(b);
console.log(c);
}
test('a', 'b');
==函數(shù)可選參數(shù)==
/**
* 可選參數(shù)
*/
// 聲明可選參數(shù) b?
// 可選參數(shù)必須寫在必選參數(shù)后面
// 順序: (必選參數(shù)悴灵, 可選參數(shù)扛芽?, 帶默認(rèn)值的參數(shù)=默認(rèn)值)
function test(a:string, b?:string, c:string='liuhaoyu') {
// 如果你聲明了可選參數(shù)积瞒,在有必要的情況下川尖,請(qǐng)?jiān)诤瘮?shù)內(nèi)部處理當(dāng)可選參數(shù)沒填時(shí)候的情況
}
test('hahaha');
解構(gòu)賦值(ES6)
function getStock() {
return {
code: 'ibm',
price: 100,
}
}
// 跟ES6解構(gòu)賦值一樣
var {code, price} = getStock();
箭頭函數(shù)(ES6)
// 箭頭函數(shù): (參數(shù)列表)=>{函數(shù)體}
// var fn = () => {};
// 箭頭函數(shù)好處
// ES5-
function getStock(name) {
this.name = name;
setInterval(function() {
console.log('name is', this.name);
}, 1000);
}
var stock = new getStock("IBM"); // 無(wú)法讀得到this.name
// ES6 TS:
function getStock2(name:string) {
this.name = name;
// 不僅代碼更少,而且this關(guān)鍵字可用
setInterval(()=>{
console.log('name is', this.name);
}, 1000);
}
var stock = new getStock2("IBM2"); //可以讀取this.name = ibm2
擴(kuò)展操作符... (ES6)
// 無(wú)限參數(shù)列表的函數(shù)
function fn1(...args) {
// 傳進(jìn)去的其實(shí)是一個(gè)數(shù)組
// 原理是編譯后js遍歷Function.arguments屬性
args.forEach(function(arg) {
console.log(arg);
})
}
function fn2(a, b, c) {
console.log(a);
console.log(b);
console.log(c);
}
// 傳實(shí)參的時(shí)候?qū)?..args
var args = [1, 2, 3, 4, 5];
// fn2(...args); // 編輯器會(huì)提示語(yǔ)法錯(cuò)誤茫孔,但是可以編譯
==generator函數(shù)==
// function* 函數(shù)名() {} 進(jìn)行定義
function* doSomething() {
console.log("start");
yield; // 可以理解為調(diào)試的時(shí)候打斷點(diǎn)
console.log("finish");
}
// 這樣的函數(shù)必須要用變量存儲(chǔ)起來(lái)
var fn1 = doSomething();
// 使用 .next() 函數(shù)執(zhí)行下一步操作(只會(huì)跑到y(tǒng)ield就停下)再次調(diào)用才會(huì)接著跑
fn1.next();
generator實(shí)際應(yīng)用
/**generator函數(shù)實(shí)際應(yīng)用
* 模擬買股票
*/
// 定義函數(shù)
function* getStockPrice(stock) {
// 無(wú)限循環(huán)
while(true) {
// .next()被調(diào)用時(shí)會(huì)一直生成 0~100之間的隨機(jī)數(shù)
yield Math.random()*100; // 假裝在獲取當(dāng)前股票價(jià)格
}
}
// 獲取函數(shù)
var priceGenerator = getStockPrice("IBM");
// 定義最低價(jià)
var limitPrice = 15;
// 定義當(dāng)前價(jià)
var price = 100;
// 當(dāng)當(dāng)前價(jià) > 最低價(jià)的時(shí)候
while(price > limitPrice) {
// 調(diào)用函數(shù)獲取當(dāng)前股票值并將值賦給price叮喳。再次進(jìn)入循環(huán)
price = priceGenerator.next().value;
// 獲取一定時(shí)間內(nèi)的大于15每股的股票價(jià)格
console.log(`the gererator return ${price}`);
}
各種“for”循環(huán)
/**
* for of循環(huán)
*/
var arr = [1,2,3,4];
// forEach(閉包(){})
arr.forEach((element)=> {
console.log(element);
});
// for(index對(duì)應(yīng)索引 in 數(shù)組)
for(var index in arr) {
console.log(index); //讀索引
console.log(arr[index]); //讀值
}
// for(value of arr)
for(var value in arr) {
// if(value > 1) break; //for of 可以在循環(huán)中break終止循環(huán)
console.log(value); //讀值
}
類
// 類定義
class Person {
name; //屬性
eat(){
console.log('我吃');
} //方法
}
// 實(shí)例化
var p1 = new Person();
p1.name = 'liuhaoyu';
console.log(p1.name);
類 訪問權(quán)限控制
/**
* 訪問權(quán)限控制符
*/
class Person {
public name;//默認(rèn)公開 對(duì)象√ 子類√ 自身√
protected address;//保護(hù)的 對(duì)象× 子類√ 自身√
private age;//隱私的 對(duì)象× 子類× 自身√
}s
類 構(gòu)造函數(shù) (默認(rèn)private)
class Person {
// name;
// age;
// 構(gòu)造函數(shù)
// constructor(name:string, age:number) {
// this.name = name;
// this.age = age;
// console.log("實(shí)例化成功");
// }
// 可以簡(jiǎn)寫
constructor(public name:string, public age:number) {
// 參數(shù)列表里定義帶訪問控制符的屬性被芳,直接可以在實(shí)例化時(shí)創(chuàng)建屬性
}
}
// 實(shí)例化
var p1 = new Person('liuhaoyu', 500);
繼承
// 爹
class Father {
public lastName;
protected money;
private firstName;
}
// 兒子
class Son extends Father {
// 兒子 可以繼承姓public 可以繼承錢money 繼承不了名name
}
// 真實(shí)情況
var son = new Son; // 而真是的情況是,實(shí)例化的兒子是拿不出來(lái)錢的(都放爹那了)【對(duì)象不能繼承protected 的 money】
繼承中的super
class Father {
name;
money;
constructor(name, money) {
this.name = name;
this.money = money;
}
eat() {
console.log('我能吃');
}
}
// super()的作用
class Son extends Father {
age;
// 1馍悟、在子類的構(gòu)造函數(shù)中充當(dāng)父類的構(gòu)造函數(shù)畔濒,實(shí)例化后使子類的this關(guān)鍵字生效
constructor(name, money, age) {
// this.age = age; //錯(cuò)誤必須先實(shí)例化父類
super(name, money); //先有爹后有兒子:先實(shí)例化爹:這里super()相當(dāng)于調(diào)父類的構(gòu)造函數(shù)
this.age = age; //super()的作用:讓this關(guān)鍵字生效
}
// 2、調(diào)用父類的其他方法
work() {
super.eat(); //這里super充當(dāng)了父類
}
}
==接口:約束類定義==
/**
* 接口的作用:代碼約定赋朦,是的其他開發(fā)者開調(diào)用某個(gè)方法或者創(chuàng)建新的類的時(shí)候必須遵循接口所定義的規(guī)定
* “插線板三角插頭只能查三角的篓冲,不帶地線的只能插進(jìn)兩腳插孔”
*/
// 聲明接口 屬性約束
interface Life {
age: number; //這個(gè)屬性一旦聲明,再實(shí)現(xiàn)的時(shí)候宠哄,是必須的
}
// 采用接口定義的屬性約束類屬性
class Person {
constructor(public config:Life) {
}
}
// var p1 = new Person('500'); //錯(cuò)誤
// var p1 = new Person(500); //錯(cuò)誤
var p2 = new Person({
age: 500,
}); //參數(shù)得這樣寫: ({接口要求必須的屬性:賦值})
// 聲明接口 必須實(shí)現(xiàn)的方法
interface Animal {
eat();
}
// 實(shí)現(xiàn) implements
class Sheep implements Animal {
// 必須寫一個(gè)eat()方法不然會(huì)報(bào)錯(cuò)
eat() {
console.log('我吃草');
}
}
class Tiger implements Animal {
eat() {
console.log('我吃肉');
}
}
generic 泛型約束
/**
* 泛型 generic
*/
class Person{
name;
age;
}
class Student extends Person {
school;
}
// people:數(shù)據(jù)限制Array<泛型限制Person> : 一個(gè)只能放Person對(duì)象的數(shù)組
var people: Array<Person> = [];
people[0] = new Person;//父類可以放進(jìn)去
people[1] = new Student;//子類可以放進(jìn)去
// people[2] = 1; //這個(gè)就不行了
模塊
- 定義和暴露
/**
* 模塊:
* 幫助開發(fā)者將代碼分割為可重用的單元壹将。(提高代碼的復(fù)用性,方便管理)
* 開發(fā)者在模塊定義中決定將模塊中的哪些資源(類毛嫉、方法诽俯、變量) 暴露出去供外部使用
* 哪些資源只能在模塊能使用(不暴露)
*/
// 定義模塊
export var prop1;
var prop2; //不寫export就不暴露模塊內(nèi)的資源
export function fn1() {
}
function fn2() {
}
export class C1 {
}
class C2 {
}
// 現(xiàn)在一次把暴露所有之前未暴露的資源
export{prop2, fn2, C2};
- 引入和使用
// 引入 {資源名稱} from "模塊相對(duì)路徑";
import { prop1 } from "./module_export";
// 引入 *所有資源 叫 Modules from "模塊相對(duì)路徑"
import * as Modules from "./module_export";
console.log(prop1);
Modules.fn2();
==模塊注解==
// angularJS 中的模塊注解
// import ( {Component} ) from '@angular/core';
// 這里就是注解
// @Component({
// selecor: '選擇器',
// templateUrl: '模板地址.html',
// StyleUrls: ['樣式地址1.css', '樣式地址2.css']
// })
// 這樣定義一個(gè)組件
// export class Component {
// // 當(dāng)實(shí)例化這個(gè)組件的時(shí)候,會(huì)通過上面的注解承粤,去找對(duì)應(yīng)的模板地址和對(duì)應(yīng)的樣式地址
// titile = 'app Works!';
// }
==類型定義文件 .d.ts==
/**
* 只能白話解釋:
* 比如我想在angular JS 里面用 jquery
* 直接寫$符 ts是不懂得
* 所以需要下載一個(gè) jquery.d.ts (所有類型定義文件都以.d.ts結(jié)尾)
* 下載地址是 gitHub上得 DefinetelyTyped(里面托管了幾乎所有的.d.ts)
* 也可以用 typings (npm install -g typings) **推薦**
* typings seach 你要的類型定義文件
* 在項(xiàng)目里安裝 .d.ts文件 (typings install 文件名 --save) 通潮┣框架里已經(jīng)寫好了package.json所以我們不用管--save寫沒寫依賴關(guān)系進(jìn)去
*/