let和const命令
ES6中新增了let命令,用來聲明變量,用法類似與var
let和var的不同:
1、不存在變量提升????????
? ????????console.log(a); //Cannot access 'a' before initialization
? ????????let a = 100;
2、同一個作用域不能重復定義同一個名稱
? ????????var c = 20;
????????? let c = 30;
? ????????console.log(c);//Identifier 'c' has already been declared
3、有嚴格的作用域????????
????????function fn() {
? ? ????????var a = "a";
? ? ????????if (true) {
? ? ? ????????var a = "b";
? ? ????????}
? ? ????????console.log(a);//b
? ????????}
? ????????fn();
? ????????function fn() {
? ? ????????var a = "a";
? ? ? ? ? ? ?//ES6中引入了塊級作用域,var a 和let a不在一個作用域中
? ? ????????if (true) {
? ? ? ????????let a = "b";
? ? ????????}
? ? ????????console.log(a);//a
? ????????}
? ????????fn();
4、塊級作用域的重要性
????????//for循環的i會提升為全局變量
? ? ? ? ? for (var i = 0; i < 5; i++) {}
? ????????console.log(i); //5
? ????????for (let i = 0; i < 5; i++) {} //i的作用域范圍只能在for循環的過程中
? ????????console.log(i); //i is not defined
const的使用
const 聲明一個只讀的常量。一旦聲明,常量的值就不能改變。
保持let的不存在變量提升,同一個作用域內不能重復定義同一個名稱,有著嚴格的作用域;
常量obj儲存的是一個地址,這個地址指向一個對象。不可變的只是這個地址,即不能把obj指向另一個地址, 但對象本身是可變的,所以依然可以為其添加新屬性
const x = 10;//如果聲明的是常量,則不能修改
? x = 100; //Assignment to constant variable.
? console.log(x);
? const y;//Missing initializer in const declaration const聲明變量時,需要立即初始化
? console.log(y);
? //const聲明引用類型,可以對值進行修改
? const arr = [1,2,3,4];
? arr[0] = 100;
? console.log(arr);
? const obj = {};
? obj.id = 1;
? console.log(obj);
解構
ES6 允許按照一定模式,從數組和對象中提取值,對變量進行賦值,這被稱為解構(Destructuring)
解構是ES6的新特性, 比ES5代碼簡潔,清晰,減少代碼量
數組解構
左邊模式匹配,定義變量,右邊是定義的數組或者對象
let [a, b, c] = [1, 2, 3];
let [a2, b2, c2, d2] = ["red", "blue", "green"];
let [x, [y1, y2], z] = [1, [2, 3], 4];
let arr = [100, 200];
var x = arr[0] || 1;
//默認值寫法
let [x = 1] = arr; //arr[0]存在在解構成x,如果不存在,則賦值為1
//當值是undefined的時候,才會觸發默認值機制
let [x = 1] = [undefined, undefined];
console.log(x);//1
var [y = 1, z] = [100, null];
console.log(y,z);//100 null//默認值如果是表達式【函數】,值在用到的時候,才會執行,惰性求值
var [y = 1, z = f()] = [100, 200];
console.log(y,z);//100,200
對象解構
對象的解構與數組有一個重要的不同。數組的元素是按次序排列的,變量的取值由它的位置決定;而對 象的屬性沒有次序,變量必須與屬性同名,才能取到正確的值
對象解構的寫法:let { id, name } = { id: 1, name: "jack" };
如果沒有對應的屬性名,則返回undefined
//id:_id? 別名
let { id:_id, name:_name } = { id: 1, name: "jack" };
//i為undefined,則返回1
let { id: _id, name: _name, i = 1 } = { id: 1, name: "jack" };
let { x = 10 } = {};
console.log(x);//10
let { x:a = 10 } = {};
console.log(x);//x is not defined,x是匹配模式,真正的變量是a
//解構用于方法入參
const fn = ({ count, num }) => num + count;
var obj = { count: 100, num: 99 };
let sumcount = fn(obj);
console.log(sumcount);//累加&解構
let obj = { id: 1, msg: "error", arr: [5, 6, 7, 8] };
const sum = ({ id, arr }) =>
arr.reduce((total, current) => total + current, id);
console.log(sum(obj));
如果要將一個已經聲明的變量用于解構賦值,必須非常小心
//報錯的原因:因為 JavaScript 引擎會將{x}理解成一個代碼塊,從而發生語法錯誤。只有不將大括號寫在 行首,避免 JavaScript 將其解釋為代碼塊,才能解決這個問題
let x;
{x} = {x:1};//編譯錯誤
console.log(x);正確寫法:
let x;
({x} = {x: 1});
將整個解構賦值語句,放在一個圓括號里面,就可以正確執行
函數參數解構
//數組參數解構
function sum([x = 0, y = 0]=[]) {
return x + y;
}函數參數?
[x = 0, y = 0] = []
?表示:
- 參數是一個數組,默認值為空數組?
[]
- 如果傳入的數組沒有第一個元素,x默認為0
- 如果傳入的數組沒有第二個元素,y默認為0
sum();//0+0=0
sum([1]);//1+0=1;
sum([1,2]);
//對象參數解構
function fn2({ x = 1, y = 2 } = {}) {
? console.log(x + y);
}
var obj = { x: 10, y: 20 };
fn2(obj);
?擴展
字符串擴展
includes(): ? ? 返回布爾值,表示是否找到了參數字符串。
startsWith(): ? 返回布爾值,表示參數字符串是否在原字符串的頭部。
endsWith(): ? ? 返回布爾值,表示參數字符串是否在原字符串的尾部
repeat(): ? ? ? 返回一個新字符串,表示將原字符串重復n次。
padStart(): ? ? 用于頭部補全
padEnd(): ? ? ? 用于尾部補全
數值擴展
Number.parseInt("100");
Number.parseFloat("100.01");
//用來判斷數字是否是一個整數,返回bool
Number.isInteger(100.01);
Math.ceil() ? ? ? 返回大于或等于一個給定數字的最小整數,ES5
Math.floor() ? ? 返回小于或等于一個給定數字的最大整數,ES5
Math.round() ? ? 返回一個數字四舍五入后最接近的整數,ES5
//ES6
Math.trunc() ? ? 用于去除一個數的小數部分,返回整數部分
Math.sign() ? ? ? 方法用來判斷一個數到底是正數、負數、還是零。對于非數值,會先將其轉換為數 值
//運算符:**,指數運算符
2**3 = 8
數組擴展
//用于將一組值,轉換為數組
var v = Array.of(); //[]
var v = Array.of(1, 2, 3); //[1,2,3]
//ES6??
var v = Array.of(); //[]
var v = Array.of(1, 2, 3); //[1,2,3]
//創建指定長度的數組,ES5
var v = new Array(3);//參數是數字,則是數組長度
console.log(v.length);
//創建一個數組,數組內的元素是字符3,ES5
var v1 = new Array("3");
console.log(v1);
//find()用于找出第一個符合條件的數組成員
//find方法的回調函數可以接受三個參數,依次為當前的值、當前的位置和原數組
var arr = [3, 4, 7, 9];
var a = arr.find((value, index, arr) => {
? return value > 5;
});
//findIndex方法的用法與find方法非常類似,返回第一個符合條件的數組成員的位置,
// 如果所有成員都不符合條件,則返回-1
var arr = [3, 4, 7, 9];
var a = arr.find(function (item, index, arr) {
? //返回第一個符合條件的數組成員的位置
? return item > 5;
});
//用于將一個固定值替換數組的元素
var arr = ["blue", "Orange", "red", "green"];
arr.fill("abc", 2, 4); //["blue", "Orange", "abc", "abc"]
//方法返回一個布爾值,表示某個數組是否包含給定的值,與字符串的 includes 方法類似
[1, 2, 3].includes(2); // true
[(1, 2, 3)].includes(4); // false
var arr = ["blue", "Orange", "red", "green"];
arr.includes("blue"); //true
//用于將嵌套的數組“拉平”,變成一維的數組
var v = [1, 2, [3, 4], 5, [6, 7, 8]].flat(); //[1, 2, 3, 4, 5, 6, 7, 8]
對象擴展
? //對象屬性2種定義方式
? var o = {};
? o.name = "xp";
? let v = "age";
? o[v] = 20; //這種定義v指的是變量
? console.log(o);
? //對象屬性定義方式
? let age = "age1";
? o = {
? ? [age]: 22,
? };
? console.log(o);
//鏈判斷運算符
let firstName = message.body.user.firstName; //可以這樣寫,但是不規范,沒有對數據的存在進行校驗
firstName =
? (message &&
? ? message.body &&
? ? message.body.user &&
? ? message.body.user.firstName) || 'default';
//這樣的層層判斷非常麻煩,引入了“鏈判斷運算符” ?.,簡化上面的寫法
firstName = message?.body?.user?.firstName || "default";
//空值合并運算符
let info = "aaaa";
let b = info ?? "bbbb";//如果info為null或者undefined,則取很后面的值
函數擴展
函數默認參數
/****************ES5*************** */function fun(x, y) {y = y || 20;console.log(y);}fun(123);/****************ES6********************* */function fun(x, y = 10) {console.log(y);}fun(234);
rest參數
/****************arguments******************* *///方法的參數是動態的,使用arguments參數集合,類似與數組function fn() {console.log(arguments); //類似數組}fn(1, 2, 3);////rest動態參數function fn(...values) {console.log(values);let filterNum = values.filter((value, index, values) => {return value > 20;});console.log(filterNum); //[ 222, 333 ]}fn(11, 222, 333, 13); //結果是一個標準的數組//報錯function fun(a,...b,c){}fun(1,2,3,4)
箭頭函數
var f = (n1, n2) => n1 + n2;//定義一個方法,返回一個對象var f = function (n1, n2) {return { n1, n2 };};//箭頭函數寫法---寫法錯誤var f = (n1, n2) => {n1, n2;};//正確寫法var f = (n1, n2) => {return { n1, n2 };};var a = f(1, 2);console.log(a); //{ n1: 1, n2: 2 }//正確寫法,返回對象,需要使用()把對象包起來var f = (n1, n2) => ({ n1, n2 });var a = f(1, 2);console.log(a); //{ n1: 1, n2: 2 }///方法入參解構let f = ({ x = 0, y = 0 } = {}) => {return [x, y];};f({ x: 3, y: 3 });
箭頭函數的坑
1、箭頭函數不能當成構造函數,也就是不能使用new關鍵字?
//箭頭函數不能當成構造函數,也就是不能使用new關鍵字var p_fn = (name, age) => {this.name = name;this.age = age;};var pfn = new p_fn("aaa", 30); //p_fn is not a constructor
2、箭頭函數沒有原型對象
3、不可以使用arguments對象 該對象在函數體內不存在 替代 rest
var f = () => {console.log(arguments[2]);};f(); //Uncaught ReferenceError: arguments is not defined//使用rest代替var f = (...rest) => {console.log(rest);};f(1, 2, 3, 4);function fn3() {console.log(arguments[1]);}fn3(1, 2, 3, 4); //2
4、this指向 由于箭頭函數不綁定this,它會捕獲其所在上下文的this的值,作為自己的this值
let x = "x";let y = "y";let obj = {x: "x2",y: "y2",getX: function () {console.log(this.x);},getY: () => {console.log(this); //this指向Windowconsole.log(this.y);},};obj.getX(); //this指向objobj.getY(); //undefined//箭頭函數中this指向://箭頭函數中沒有this,但是箭頭函數會捕獲所在(定義的位置)上下文的this的值。//這里的getY在obj對象中,obj對象定義在Window里。
盡量不要在對象的方法里寫箭頭函數【不確定就在箭頭函數中打印this】
擴展運算符
擴展運算符是三個點...
它好比rest參數的逆運算。
擴展運算符將一個數組轉為用逗號分隔的參數序列。
該運算符主要用于函數調用。
//合并兩個數組let arr2 = [1, 2, 3];let arr3 = [4, 5];let arr4 = [...arr2, ...arr3];console.log(arr4);function sum(x, y) {return x + y;}const item = [1, 2];sum(...item);/***************************************************///第一種寫法var a = [];function f(x, y) {a.push(...y);}f(a, [1, 2, 3, 4]);console.log(a); //[ 1, 2, 3, 4 ]//第二種寫法var a = [];function f(x, ...y) {//這的...y是可變參數,會將參數變成數組,也就是[[1, 2, 3, 4]]a.push(...y);//這的...y是擴展運算符,會將[[1, 2, 3, 4]]分解成[ 1, 2, 3, 4 ]}f(a, [1, 2, 3, 4]);console.log(a); //[[ 1, 2, 3, 4 ]]/**********************擴展************************ */let array = [{ id: 1, name: "a" },{ id: 3, name: "a" },{ id: 10, name: "a" },{ id: 4, name: "a" },{ id: 27, name: "a" },{ id: 50, name: "a50" },];//求id最大的對象?let maxId = Math.max(...array.map((v) => v.id));console.log(maxId);
擴展運算符可以和解構結合起來使用
? let [first, ...rest] = [1, 2, 3, 4, 5];console.log(first);//1console.log(rest);//[ 2, 3, 4, 5 ]
擴展運算符在對象中的使用
let o1 = { id: 1 };let o2 = { name: "o2" };let o3 = { ...o1, ...o2 };console.log(o3);//{ id: 1, name: 'o2' }