目錄
ES6基礎入門之let、const
變量聲明
var聲明
var name='hiyori'
直接使用
window.location.href===location.href
說明:這種不加var聲明的定義方式,相當於在全局對象window上掛了一個屬性,會造成全局對象污染 ,不建議這麼做
let和var的主要區別
- let聲明的變量只在當前(塊級)作用域內有效
- let聲明的變量不能被重複聲明
- let不存在變量提升
ES6之前的作用域
全局作用域、函數作用域、eval作用域
塊級作用域
- 通俗的講,就是一堆花括號中的區域{...}
- 塊級作用域可以嵌套
/* let聲明的變量只在當前(塊級)作用域內有效 */
//example1
{
var a = 1;
let b = 2;
}
console.log(a); //打印a
console.log(b); //出了塊級作用域,報錯信息爲未定義
//example2
{
let a = 1;
{
console.log(a); //這裏屬於a的作用範圍,打印1
let b = 2;
}
console.log(b); //這裏不屬於b的作用範圍,報錯
}
//example3
for (let i = 0; i < 3; i++) {
};
console.log(i); //報錯
for (var i = 0; i < 3; i++) {
console.log(i);
};
console.log(i); //打印3,var定義的i並不會被釋放,因爲初始化時定義的i相當於是在循環語句的作用域之外定義的
/* 使用let或者const聲明的變量不能被重新聲明 */
var dad = '我是爸爸!';
var dad;
console.log(dad); //重新聲明,沒有被賦值,該變量還是'我是爸爸'
var dad = '我纔是爸爸!';
console.log(dad); //修改爲新的值
let son = '我是兒子';
let son; //報錯,提示son已被聲明過
let son = '我纔是兒子'; //報錯,提示son已被聲明過
/* let不存在變量提升 */
console.log(dad); //undefined
var dad='我是爸爸';
//以上情形就是因爲變量提升
//預解析時會先解析帶有var關鍵字的變量,並賦值爲undefined,執行代碼時才賦真正的值
//相當於
var dad; //變量聲明被拉到最前面,而後賦值
console.log(dad);
dad='我是爸爸';
console.log(dad); //報錯,提示未定義該變量
let dad='我是爸爸';
//用let定義的變量不會把聲明拉到最前面,因此不具有變量提升
//暫存死區
var monkey = '我是美猴王';
{
console.log(monkey); //我是..
var monkey = '我覺得我還能再搶救一下!';
}
console.log(monkey); //我覺得..
let monkey = '我是美猴王';
{
console.log(monkey); //報錯
let monkey = '我覺得我還能再搶救一下!';
}
console.log(monkey);
let面試常見例子
q: 生成十個按鈕 每個按點擊的時候彈出1 - 10
var i = 0;
for (i = 1; i <= 10; i ++) {
(function(i) {
var btn = document.createElement('button');
btn.innerText = i;
btn.onclick = function() {
alert(i)
};
document.body.appendChild(btn);
})(i);
}
//在外面加上自執行匿名函數,就會形成獨立的函數作用域,i作爲參數傳進來,在作用域中獲得的就是實時更新的i
//如果沒有定義一個自執行的function,那麼這裏每次點擊彈出的都是11
//因爲發生點擊事件後要去尋找i,本層找不到就會到上一層去找,上一層的i在循環結束後值爲11
//因此事件中獲取到的i的值也是11
//使用let定義,可以實現和添加自執行函數一樣的效果
for (let i = 1; i <= 10; i ++) {
var btn = document.createElement('button');
btn.innerText = i;
btn.onclick = function() {
alert(i)
};
document.body.appendChild(btn);
}
const
常量——不可改變的量
和聲明變量一樣,基本只是關鍵字的區別
常量必須在聲明的時候賦值,否則報錯:Missing initiaizer in const declaration
const a; //不賦值,會報錯
var b=2;
let c;
const與let類似的特性
不能重複聲明
不存在變量提升
只在當前(塊級)作用域內有效
常量不可變
一旦聲明常量,就不能再改變
但常量爲引用類型的時候,不能保證不可變
const NAME='xh';
NAME='xm'; //報錯,提示常量不能被修改
說明:const只能保證引用常量的地址不變,不能保證它裏面的值不變。
//對象
const xiaoming={
age:14;
name:'xm';
}
xiaoming.age=22; //允許修改
xiaoming={}; //報錯,不允許被修改,因爲相當於把一個新的地址給了xiaoming這個常引用對象
//數組
const ARR=[];
ARR.push(1); //允許添加
ARR=[]; //報錯,不允許被修改,還是相當於把一個新的地址給了ARR這個常引用數組
怎麼解決引用類型的常量可以被修改的問題?
Object.freeze()
const xiaoming = {
age: 14,
name: '小明'
};
Object.freeze(xiaoming); //xiaoming對象中的值也不允許被修改了
console.log(xiaoming);
xiaoming.age = 22; //不報錯,但不會發生改變
xiaoming.dd = 11; //不報錯,但不會發生改變
console.log(xiaoming);
const ARR = [];
Object.freeze(ARR); //ARR數組中的值也不允許被修改了
ARR.push(1); //報錯,提示不能被擴展
console.log(ARR);
ES6之前怎麼聲明常量?
用var聲明,假裝是常量
var BASE_COLOR = '#ff0000';
Object.defineProperty();
var CST = {a: 1};
Object.defineProperty(CST, 'a', {
writable: false
});
//writable:只讀,不能被修改
Object.seal(CST); //只能防止被擴展
//Object.seal+writable:false才能達到freeze()的效果
自行封裝一個freeze()
// 1. 遍歷屬性和方法
// 2. 修改遍歷到的屬性的描述
// 3. Object.seal()
Object.defineProperty(Object, 'freezePolyfill', {
value: function(obj) {
var i;
for (i in obj) {
if (obj.hasOwnProperty(i)) {
Object.defineProperty(obj, i, {
writable: false //每個屬性都不能被修改
});
}
}
Object.seal(obj); //整個對象不能被擴展
}
});
const xiaoming = {
age: 14,
name: '小明',
obj: {
a: 1
}
};
Object.freezePolyfill(xiaoming);
ES6變量的解構賦值
解構賦值語法是一個JavaScript表達式,這使得可以將值從數組或屬性從對象提取到不同的變量中
數組的解構賦值
數組的解構賦值
// 數組的解構賦值
const arr = [1, 2, 3, 4];
let [a, b, c, d] = arr;
//會根據元素在數組中所在的位置一一對應匹配,a=1,b=2……
更復雜的匹配規則
// 更復雜的匹配規則
const arr = ['a', 'b', ['c', 'd', ['e', 'f', 'g']]];
const [ , b] = arr; //只返回b
const [ , , g] = ['e', 'f', 'g'] //只返回g
const [ , , [ , , g]] = ['c', 'd', ['e', 'f', 'g']]; //只返回g
const [ , , [ , , [ , , g]]] = arr; //只返回g
擴展運算符 ...
// 擴展運算符 ...
const arr1 = [1, 2, 3];
const arr2 = ['a', 'b'];
const arr3 = ['zz', 1];
const arr4 = [...arr1, ...arr2, ...arr3]; //可以把arr1、arr2、arr3合併起來
const arr = [1, 2, 3, 4, 5, 6];
const [a, b, ...c] = arr; //會把3,4,5,6作爲一個數組賦給c
const [a, b, ...c,d] = arr; //錯誤
注意:帶擴展運算符的變量後面不能再有其他變量,因爲擴展運算符就是用來取最後幾個元素進行合併的
默認值
// 默認值
const arr = [1, null, undefined];
const [a, b = 2, c, d = 'aaa'] = arr; //設置默認值,當匹配到undefined時,就使用默認值
//a=1,b=null,c=undefined,d='aaa'
說明:解構賦值時沒有匹配到的就被賦值爲undefined
交換變量
// 交換變量
let a = 20;
let b = 10;
//方法①
let temp;
temp = a;
a = b;
b = temp;
//方法②,利用解構賦值
[a, b] = [b, a];
接收多個 函數返回值
// 接收多個 函數返回值
function getUserInfo(id) {
// .. ajax
return [
true,
{
name: '小明',
gender: '女',
id: id
},
'請求成功'
];
};
const [status, data, msg] = getUserInfo(123);
//status匹配到函數返回值第一項布爾值,data匹配到函數返回值第二項對象,msg匹配到函數返回值第三項文字
對象的解構賦值
對象的解構賦值與數組的解構賦值相似
等號左右兩邊都爲對象結構
const {a,b}={a:1,b:2};
左邊的{}中爲需要賦值的變量
右邊爲需要解構的對象
對象解構賦值的用法
// 對象的解構賦值
const obj = {
saber: '阿爾託利亞',
archer: '衛宮'
};
const { saber, archer1 } = obj; //archer屬性名不匹配,archer1的值是undefined
注意:對象的解構賦值要求不同對象的屬性名要一致,才能匹配。因爲數組是有序的,而對象是無序的,必須用屬性名去匹配,而不是用位置去匹配。
稍微複雜的解構條件
// 稍微複雜的解構條件
const player = {
nickname: '感情的戲∫我沒演技∆',
master: '東海龍王',
skill: [{
skillName: '龍吟',
mp: '100',
time: 6000
},{
skillName: '龍捲雨擊',
mp: '400',
time: 3000
},{
skillName: '龍騰',
mp: '900',
time: 60000
}]
};
const { nickname } = player; //返回感情的戲∫我沒演技∆
const { master } = player; //返回東海龍王
const { skill: [ skill1, { skillName }, { skillName: sklName } ] } = player;
//保持格式一致,就可以解構skill裏的屬性
//對數組進行賦值時變量名可以隨便起,skill1獲得skill數組的第一項,skillName獲得數組第二項中的skillName龍捲雨擊
//這時如果想要獲得skill數組第三項的skillName再次使用{skillName}是不行的,因爲const聲明的變量中已經有skillName了
//我們需要另外起一個名字,只要在屬性名後面加上:新名字,就可以解決這個問題,意思是把skillName中的值賦給sklName
const { skill } = player; //返回一個數組
const [ skill1 ] = skill; //skill是一個數組,skill1是數組元素的第一項——龍吟,100,6000
const { skill:[skill1] }=player; //與上一行完全一樣,但不會取到skill
擴展運算符 ...
// 結合擴展運算符
const obj = {
saber: '阿爾託利亞',
archer: '衛宮',
lancer: '瑟坦達'
};
const { saber, ...oth } = obj; //會把除了saber以外的剩下所有項賦值給oth
const obj1 = {
archer: '衛宮',
lancer: '瑟坦達'
}
const obj = {
saber: '阿爾託利亞',
...obj1, //會把obj1所有屬性合併成一個對象
};
如何對已經申明瞭的變量進行對象的解構賦值
// 如何對已經申明瞭的變量進行對象的解構賦值
let age;
const obj = {
name: '小明',
age: 22
};
({ age } = obj);
//{age}外面如果不加(),會被編譯器理解成塊級作用域,然後報錯。
//最好的方法是帶上變量聲明
const obj = {
name: '小明',
age: 22
};
let {age}=obj;
默認值
// 默認值
let girlfriend = {
name: '小紅',
age: undefined,
};
let { name, age = 24, hobby = ['學習'] } = girlfriend;
//name='小紅',age=24
對象的解構賦值的主要用途
提取對象屬性
// 提取對象屬性
const { name, hobby: [ hobby1 ], hobby } = { //把hobby值賦給hobby1,再定義一個hobby就獲取到對象的hobby屬性值
name: '小紅',
hobby: ['學習']
};
使用對象傳入亂序的函數參數
function AJAX({ //傳參時解構賦值,可以不按順序賦值,如果type沒有設置默認爲get
url,
data,
type = 'get'
}) {
// var type = option.type || 'get';
// console.log(option);
console.log(type);
};
AJAX({
data: {a: 1},
url: '/getinfo',
});
獲取多個函數返回值
// 獲取多個 函數返回值
function getUserInfo(uid) {
// ...ajax
return {
status: true,
data: { name: '小紅' },
msg: '請求成功'
};
};
const { status, data, msg: message } = getUserInfo(123);
字符串的解構賦值
// 字符串的結構賦值
const str = 'I am the bone of my sword'; // 我是劍骨頭
const [ a, b ,c, ...oth ] = str;
//a=I,b= ,c=a,oth=m the bone of my sword,注意這裏oth是一個數組,每個字符是一個數組元素
const [ ...spStr1 ] = str; //spStr1是一個數組,每個數組元素是str的一個字符
const spStr2 = str.split(''); //同上一句效果一樣
const spStr3 = [ ...str ]; //同上一句效果一樣
// 提取屬性
const { length, split } = str;
數值與布爾值的解構賦值
// 數值與布爾值的解構賦值
const { valueOf: vo } = 1;
const { toString: ts } = false;
函數參數的解構賦值
// 函數參數的解構賦值
function swap([x, y]) {
return [y, x];
};
let arr = [1, 2];
arr = swap(arr);
//定義一個Computer的構造函數
function Computer({
cpu,
memory,
software = ['ie6'],
OS = 'windows 3.5'
}) {
console.log(cpu);
console.log(memory);
console.log(software);
console.log(OS);
};
//聲明一個Computer對象
new Computer({
memory: '128G',
cpu: '80286',
OS: 'windows 10'
});