本系列博客爲ES6基礎語法的使用及總結,若有錯誤,歡迎指正。
重學ES6之出來混早晚要還的(一)主要包括 var、let、const變量聲明 和 箭頭函數相關 。面試
其餘筆記:
重學ES6之出來混早晚要還的(二)
重學ES6之出來混早晚要還的(三)
重學ES6之出來混早晚要還的(四)
重學ES6之出來混早晚要還的(五)
重學ES6之出來混早晚要還的(六)
數據類型的轉換/判斷/比較segmentfault
var
的使用1.基本用法
1.1 定義變量格式:var 變量名稱 = 變量值
,若是沒有給變量賦值,默認爲undefined
1.2 用 var 聲明的變量的做用域是它當前的執行上下文,它能夠是嵌套的函數,也能夠是聲明在任何函數外的變量。
1.3 經過var定義變量,能夠重複定義同名變量,不會報錯;後定義的會覆蓋先定義的。
1.4 經過var定義在{}(塊級做用域)的變量,不區分全局變量和局部變量,後續仍可使用。
1.5 經過var定義變量,能夠先使用後定義(預解析)數組
//定義一個變量 var a; //重複定義同名變量 var a = 18; var a = 16; console.log(a); //輸出16
2.變量提高(hoisting)
2.1 經過var聲明的變量能夠在聲明以前使用,輸出undefined(也就是咱們常說的能夠先使用後定義)
2.2 這個行爲叫作「hoisting」,也就是咱們說的預解析。把全部的變量聲明移動到函數或者全局代碼的開頭位置。瀏覽器
console.log(a); //輸出undefined var a = 18 //預解析以後 var a; console.log(a); //輸出undefined a = 18
3.注意點
3.1 經過var聲明的變量屬於函數做用域,若是當前沒有函數,則屬於全局做用域。在外界是能夠訪問到的。app
var price = 10; var count = 10; if(count > 5){ var discount = price * 0.8; //discount是一個全局變量,在控制檯能夠訪問到 console.log(`the discount is ${discount}`); }
若是換成let定義:經過let定義的discount是一個局部變量,在控制檯不能夠訪問
函數
var price = 10; var count = 10; if(count > 5){ let discount = price * 0.8; console.log(`the discount is ${discount}`); }
3.2 window對象上有一個叫作name的屬性,若是使用var定義一個叫作name的屬性,那麼就會覆蓋掉window的name屬性。this
var name = "mss";
解決:能夠經過當即執行函數(IIFE (Immediately Invoked Function Expression) ),使變量私有化,避免屬性重寫的問題。此時輸出的name就是window上面的name屬性。spa
可是,利用當即執行函數僅僅爲了聲明一個變量,避免變量重寫有點大材小用了...請避免這樣的用法prototype
(function () { var name = 'mss'; console.log(name); })()
let
的使用1.基本用法
1.1 經過let不能夠重複定義同名變量。
1.2 經過let定義變量,不能夠先使用再定義,瀏覽器不會對let定義的變量進行預解析。會輸出ReferenceError
1.3 經過let定義在{}的變量區分全局變量和局部變量
1.4 經過let定義在{}的局部變量,只能在{}中使用,後續不可使用,只在塊級做用域內有效。code
//不能夠先使用再定義 console.log(a); //ReferenceError let a = 18; //不可重複定義 let a = 18; let a = 88; console.log(a); //Identifier 'a' has already been declared //塊級做用域內區分全局變量和局部變量 { let a = 18; //局部變量 var person = 'jelly'; //全局變量 console.log(a); //18 } console.log(a); //ReferenceError console.log(person); //jelly
2.注意點
2.1 let不會在全局聲明時(在最頂部的範圍)建立window 對象的屬性。
在程序和方法的最頂端,let不像 var 同樣,let不會在全局對象裏新建一個屬性。
位於函數或代碼頂部的var聲明會給全局對象新增屬性, 而let不會。例如:
var x = 'global'; let y = 'global'; console.log(this.x); // "global" console.log(window.x); // "global" console.log(this.y); // undefined console.log(window.y); // undefined
2.2 在同一做用域內經過let定義變量,毫不容許同名變量出現;包括用var聲明的變量。
{ let name = "jelly"; var name = "vicky"; //Identifier 'name' has already been declared } let name = "jelly"; { var name = "vicky"; //Identifier 'name' has already been declared } { let name = "jelly"; { let name = "vicky"; //不報錯 } }
3.暫時性死區(TDZ(Temporal dead zone))
與經過 var 聲明的有初始化值 undefined 的變量不一樣,經過 let 聲明的變量直到它們的定義被執行時才初始化。在變量初始化前訪問該變量會致使 ReferenceError
。該變量處在一個自塊頂部到初始化處理的「暫存死區」中。
4.一道很切題的題
var a = 5; //var定義的a綁定到了window對象上面 let obj = { a: 10, foo: function () { console.log(this.a); } }; let bar = obj.foo; obj.foo(); //10 obj調用了foo函數,this就是obj對象,輸出10 bar(); //5 bar函數是輸出當前對象(window)上面的a,爲5 let a = 5; //let定義的a不會綁定到window對象上面 let obj = { a: 10, foo: function () { console.log(this.a); } }; let bar = obj.foo; obj.foo(); //10 obj調用了foo,this就是obj對象,輸出10 bar(); //undefined 當前的this是window對象,可是window上面沒有a屬性,輸出undefined
一道奇怪寫法的筆試題
var a = 5; function test() { a = 0; console.log(a); //0 console.log(this.a); //undefined var a; console.log(a); //0 } new test();
上例中,在函數內聲明變量a=0
,在後面又使用var a
,會進行變量提高,因此在函數內部就存在一個局部變量a了,因此兩次console.log(a)
都輸出0;console.log(this.a)
輸出undefined能夠理解爲沒有東西調用test函數,致使this的指向不明確,也就找不到this.a屬性。
const
的使用1.用法
1.1 const 用於聲明一個或多個常量,常量的值不可改變。例如亙古不變的PI,能夠用const定義。
1.2 const定義常量與使用let 定義的變量有着驚人的類似之處:
var x = 10; { const x = 2; console.log(x); //2 } console.log(x); //10
1.3 二者還有如下兩點區別:
// 錯誤寫法 const PI; PI = 3.14159265359; // 正確寫法 const PI = 3.14159265359;
2.const用法之面試現場還原
使用 const 定義的對象或者數組,實際上是可變的。對象的引用(地址)不可更改,可是對象的屬性能夠改變;只是咱們不能對常量對象從新賦值
// 建立常量對象 const car = {type:"Fiat", model:"500", color:"white"}; // 修改屬性: car.color = "red"; // 合法 // 添加屬性 car.owner = "Johnson"; // 合法 const car = {type:"Fiat", model:"500", color:"white"}; car = {type:"Volvo", model:"EX60", color:"red"}; // 錯誤
var
,let
,const
的使用場景const
by default)let
if rebinding is needed)var
shouldn't be used in ES6)//沒有參數 () => {函數聲明} //一個參數 單一參數 => {函數聲明} //多個參數 (參數1, 參數2, …, 參數N) => { 函數聲明 }
什麼是顯示返回?
顯示返回格式:return 「返回的內容」
2.1.1 箭頭函數的隱式返回:
const arr = [2,4,6,8,10]; const double = arr.map(function (number) { return number *2; }); console.log(double); //等價於 const double2 = arr.map((number) => number*2); console.log(double2);
2.1.2 注意:箭頭函數都是匿名函數,若是想要經過命名函數的方式使用箭頭函數,通常把箭頭函數賦值給一個變量便可
const greet = name => console.log(`hello ${name}`); greet("mss");
例1:
let p = { name: "lnj", say: function () { console.log(this); }, hi: () => { console.log(this); } }; p.say(); //object p.hi(); //window
例2:
const person = { name: 'mss', hobbies: ['money','sleeping','eating'], output: function () { //console.log(this); //this是person這個對象 this.hobbies.map(function (hobby) { //console.log(this);//this是window console.log(`${this.name} loves ${hobby}`); }) } }; person.output(); /* 輸出結果: loves money loves sleeping loves eating */
上述例子中能夠看出,並無輸出name屬性。在output的函數中,this指向person這個對象,而map方法的回調函數是一個獨立的函數,一個獨立函數運行的時候,沒有做爲對象的方法調用或者沒有使用call等修改this的值時,則此時this指向window;
過去的作法是:在外面保存一下this
const person = { name: 'mss', hobbies: ['money','sleeping','eating'], output: function () { let that = this; this.hobbies.map(function (hobby) { console.log(`${that.name} loves ${hobby}`); }) } }; person.output(); /* 輸出結果 mss loves money mss loves sleeping mss loves eating */
2.2.1 解決:在ES6中能夠用箭頭函數來解決這種問題
2.2.2 緣由:
const person = { name: 'mss', hobbies: ['money','sleeping','eating'], output: function () { this.hobbies.map(hobby => { console.log(`${this.name} loves ${hobby}`); }) } }; person.output(); /* 輸出結果 mss loves money mss loves sleeping mss loves eating */
2.2.3 應用:函數節流/防抖中使用箭頭函數簡化代碼
//防抖 function debounce(fn,delay) { let timerId = null; return function (...args) { timerId && clearTimeout(timerId); timerId = setTimeout(()=>{ fn.apply(this,args); },delay || 3000); } } //節流 function throttle(fn,delay) { let timerId = null; let flag = true; return function (...args) { if(!flag) return; flag = false; timerId && clearTimeout(timerId); timerId = setTimeout(()=>{ flag = true; fn.apply(this,args); },delay || 3000); } }
箭頭函數不綁定Arguments 對象,即箭頭函數沒有Arguments對象。
3.1 做爲構造函數或者是一個對象的方法或者給原型綁定方法的時候,是不容許使用箭頭函數的
箭頭函數沒有prototype屬性。
let Foo = (name,age) => { this.name = name; this.age = age; }; let foo = new Foo('ghk',22); // TypeError: Foo is not a constructor Foo.prototype.say = () => { console.log(`hello ${this.name}`); // TypeError: Foo is not a constructor }
3.1.1 緣由:經過new生成一個實例的時候,在內部會完成四個步驟
(1)建立一個新的對象
(2)將構造函數中的做用域賦值給新對象(構造函數的this就指向了該新生成的對象)
(3)執行構造函數中的代碼(爲新對象添加屬性)
(4)返回新對象
箭頭函數用做構造器時,並未完成把this值綁定到新生成的對象上面去這個步驟,因此會報錯,所以只能使用原始函數做爲構造函數。
正確寫法:
let Foo = function(name,age){ this.name = name; this.age = age; }; let foo = new Foo('ghk',22); Foo.prototype.say = function (){ console.log(`hello ${this.name}`); }; foo.say();
3.2 須要使用this的時候(交互的時候),不推薦使用箭頭函數
給元素綁定事件時,不可用箭頭函數。由於此時箭頭函數的this是window,而觸發事件this應該指向到觸發事件的該元素上。
錯誤寫法:
let oBtn = document.querySelector(".btn"); oBtn.addEventListener("click",() => { console.log(this); //this是window,因此會報錯 this.classList.add("in"); setTimeout(() => { console.log(this); //this是oBtn this.classList.remove("in"); },2000) })
正確寫法:
let oBtn = document.querySelector(".btn"); oBtn.addEventListener("click",function () { console.log(this); //this是oBtn this.classList.add("in"); setTimeout(() => { console.log(this); //this是oBtn this.classList.remove("in"); },2000) })
3.3 須要使用Arguments對象的時候,不推薦使用箭頭函數
箭頭函數中沒有Arguments對象
錯誤寫法:
let sum = () =>{ return Array.from(arguments) .reduce((prevSum,curValue) => prevSum + curValue); }; sum(1,2,3); //arguments is not defined
正確寫法:
let sum = function(){ return Array.from(arguments) .reduce((prevSum,curValue) => prevSum + curValue); }; console.log(sum(1, 2, 3)); //6
或者:
let sum = (...args) => { return args.reduce((prevSum,curValue) => prevSum + curValue); }; console.log(sum(1, 2, 3));
3.4 不可使用 yield
命令,所以箭頭函數不能用做Generate函數。
補充知識
注:Array.from()
做用是把類數組對象轉換爲真數組
Array.from(arrayLike[, mapFn[, thisArg]])
console.log(Array.from('foo')); // expected output: Array ["f", "o", "o"] console.log(Array.from([1, 2, 3], x => x + x)); // expected output: Array [2, 4, 6]
注:reduce()
爲數組中的每個元素依次執行callback函數,不包括數組中被刪除或從未被賦值的元素
arr.reduce(callback(accumulator, currentValue[, index[, array]])[, initialValue])
let arr = [1,2,3,4]; let sum = (accumulator,currentValue) => accumulator + currentValue; console.log(arr.reduce(sum)); //10 console.log(arr.reduce(sum, 5)); //15
上面的代碼中,sum函數的參數accumulator是累積變量,參數currentValue是當前的數組成員。每次執行時,currentValue會加到accumulator,最後輸出accumulator。
reduce方法中的第二個參數不傳的時候,初始值默認使用數組中的第一個元素。即1+2+3+4輸出10;當初始值爲5時,即5+1+2+3+4輸出15.
本文章參考到的連接:
https://developer.mozilla.org...
http://www.ruanyifeng.com/blo...
https://www.runoob.com/