es6-selfnote

ECMAScript6(ES6)基礎(chǔ)知識(shí)及核心原理

使用Babel編譯ES6

一、下載安裝Babel
環(huán)境:需要電腦上安裝node(node中一般都會(huì)自帶npm包管理器)

npm install babel-cli -g 把模塊安裝在全局環(huán)境下(在任何的項(xiàng)目中,都可以使用命令來(lái)編譯我們的代碼了)
npm uninstall babel-cli -g 把全局下安裝的babel模塊卸載掉

[圖片上傳失敗...(image-be07d3-1570785377246)]

觀看安裝目錄發(fā)現(xiàn)一些細(xì)節(jié)需要了解的知識(shí)點(diǎn):
1、我們后期之所以可以使用babel的命令,是因?yàn)榘惭b在全局環(huán)境下之后,會(huì)生成一些 xxx.cmd 的文件,而這里的xxx就是可以在DOC窗口中執(zhí)行的命令
babel.cmd 以后可以使用babel命令了
babel-node.cmd
...

2、執(zhí)行babel命令后我們可以完成一些編譯或者其它的任務(wù),主要原因是執(zhí)行babel命令后,會(huì)自動(dòng)加載一些處理任務(wù)的文件
[圖片上傳失敗...(image-b51a8a-1570785377246)]

二、配置.babelrc文件,安裝一些語(yǔ)言解析包
1、我們需要把.babelrc文件配置在當(dāng)前項(xiàng)目的根目錄下(這個(gè)文件沒(méi)有文件名,后綴名是babelrc)
a:在電腦上不能直接創(chuàng)建沒(méi)有文件名的文件,我們需要使用WS中的 new -> file 來(lái)創(chuàng)建,或者使用命令創(chuàng)建
b:babelrc這個(gè)后綴名在某些ws中是不識(shí)別的,它其實(shí)是一個(gè)json文件,我們需要在ws中配置一下(讓他隸屬于json文件)
[圖片上傳失敗...(image-34afb4-1570785377246)]

2、在文件中編寫一些內(nèi)容

{
  "presets": [], //=>存放的是,我們編譯代碼時(shí)候需要依賴的語(yǔ)言解析包
  "plugins": [] //=>存放的是,我們編譯代碼時(shí)候需要依賴的插件信息
}

3、安裝依賴的語(yǔ)言解析包
在當(dāng)前項(xiàng)目的根目錄下安裝(不是安裝在全局),需要特殊注意的是:要在當(dāng)前項(xiàng)目根目錄中打開DOC命令才可以
npm install babel-preset-latest 安裝最新已經(jīng)發(fā)布的語(yǔ)言標(biāo)準(zhǔn)解析模塊
npm install babel-preset-stage-2 安裝當(dāng)前還沒(méi)有發(fā)布但是已經(jīng)進(jìn)入草案的語(yǔ)言解析模塊(如果你的代碼中用到了發(fā)布非標(biāo)準(zhǔn)的語(yǔ)法,我們需要安裝他)
...
安裝成功后在自己的當(dāng)前項(xiàng)目根目錄下,會(huì)存在一個(gè) node_modules文件夾,在這個(gè)文件夾中有我們安裝的模塊

4、完成最后.babelrc文件的配置

{
  "presets": [
    "latest",
    "stage-2"
  ],
  "plugins": []
}

三、使用命令編譯JS代碼
基本上所有支持命令操作的模塊都有一個(gè)命令
babel --help / babel -h 查看幫助

babel --version / babel -V 查看版本號(hào)

babel --out-file / babel -o 把某一個(gè)JS文件中的ES6代碼進(jìn)行編譯

babel --out-dir / babel -d 把某一個(gè)文件夾中所有的JS文件中的ES6代碼進(jìn)行編譯

babel --watch / babel -w 監(jiān)聽文件中代碼的改變,當(dāng)代碼改變后,會(huì)自動(dòng)進(jìn)行編譯

結(jié)束監(jiān)聽的程序:ctrl+c 按兩遍

[圖片上傳失敗...(image-90e7f0-1570785377246)]

1.ES6

ES6 的模塊自動(dòng)采用嚴(yán)格模式,不管你有沒(méi)有在模塊頭部加上"use strict"; 嚴(yán)格模式主要有以下限制。

  • 變量必須聲明后再使用
  • 函數(shù)的參數(shù)不能有同名屬性,否則報(bào)錯(cuò)
  • 不能使用with語(yǔ)句
  • 不能對(duì)只讀屬性賦值,否則報(bào)錯(cuò)
  • 不能使用前綴 0 表示八進(jìn)制數(shù),否則報(bào)錯(cuò)
  • 不能刪除不可刪除的屬性,否則報(bào)錯(cuò)
  • 不能刪除變量delete prop,會(huì)報(bào)錯(cuò),只能刪除屬性delete global[prop]
  • eval不會(huì)在它的外層作用域引入變量
  • eval和arguments不能被重新賦值
  • arguments不會(huì)自動(dòng)反映函數(shù)參數(shù)的變化
  • 不能使用arguments.callee
  • 禁止this指向全局對(duì)象
  • 不能使用fn.caller和fn.arguments獲取函數(shù)調(diào)用的堆棧
  • 增加了保留字(比如protected、static和interface);

1.數(shù)組遍歷方法

  • forEach:遍歷
  • map:遍歷,可以修改返回值
  • find: 數(shù)組實(shí)例的find方法,用于找出第一個(gè)符合條件的數(shù)組成員。它的參數(shù)是一個(gè)回調(diào)函數(shù),所有數(shù)組成員依次執(zhí)行該回調(diào)函數(shù),直到找出第一個(gè)返回值為true的成員,然后返回該成員。如果沒(méi)有符合條件的成員,則返回undefinedfind方法的回調(diào)函數(shù)可以接受三個(gè)參數(shù),依次為當(dāng)前的值、當(dāng)前的位置和原數(shù)組。
  • findIndex: 數(shù)組實(shí)例的findIndex方法的用法與find方法非常類似,返回第一個(gè)符合條件的數(shù)組成員的位置,如果所有成員都不符合條件,則返回-1
  • filter:篩選,返回一個(gè)新數(shù)組,原數(shù)組不變
  • some::返回結(jié)果只要有一個(gè)true,就返回true
  • every:返回結(jié)果只要有一個(gè)false,就返回false

上面都可以改this

  • reduce:迭代,比如數(shù)組求和,consloe.log(ary.reduce((prev,item)=>{return prev+item}))
  • reduceRight:從數(shù)組的最后一項(xiàng)往前迭代.

2.set &&map

  • set可以數(shù)組去重,返回的是一個(gè)類數(shù)組.只有value沒(méi)有key.遍歷只能遍歷他的value值,比如forEach((value,set)=>{})
  • keys():返回鍵名的遍歷器
  • values():返回鍵值的遍歷器
  • entries():返回鍵值對(duì)的遍歷器
  • forEach():使用回調(diào)函數(shù)遍歷每個(gè)成員
//數(shù)組去重
let ary=[1,1,1,1,2,2,2];
console.log([...new Set(ary)]);//1,2
console.log(Object.is(NaN,NaN));解決NAN問(wèn)題

Array.from方法可以將 Set 結(jié)構(gòu)轉(zhuǎn)為數(shù)組。

const items = new Set([1, 2, 3, 4, 5]);
const array = Array.from(items);
//這就提供了去除數(shù)組重復(fù)成員的另一種方法。

function dedupe(array) {
  return Array.from(new Set(array));
}

dedupe([1, 1, 2, 3]) // [1, 2, 3]

keys方法、values方法、entries方法返回的都是遍歷器對(duì)象,由于 Set 結(jié)構(gòu)沒(méi)有鍵名,只有鍵值(或者說(shuō)鍵名和鍵值是同一個(gè)值),所以keys方法和values方法的行為完全一致。
這意味著,可以省略values方法,直接用for...of循環(huán)遍歷 Set。

let set = new Set(['red', 'green', 'blue']);

for (let x of set) {
  console.log(x);
}
// red
// green
// blue

set

add 增加一項(xiàng),重復(fù)的加不上,返回當(dāng)前set
set.add((value):添加某個(gè)值,返回 Set 結(jié)構(gòu)本身。
delete(value):刪除某個(gè)值,返回一個(gè)布爾值,表示刪除是否成功。刪除已有的返回true.
has(value):返回一個(gè)布爾值,表示該值是否為Set的成員。 返回true或者false
clear 清空沒(méi)有返回值 undefined
size 相當(dāng)于數(shù)組中的length.

map
它類似于對(duì)象,也是鍵值對(duì)的集合,但是“鍵”的范圍不限于字符串,各種類型的值(包括對(duì)象)都可以當(dāng)作鍵。也就是說(shuō),Object 結(jié)構(gòu)提供了“字符串—值”的對(duì)應(yīng),Map 結(jié)構(gòu)提供了“值—值”的對(duì)應(yīng),是一種更完善的 Hash 結(jié)構(gòu)實(shí)現(xiàn)。如果你需要“鍵值對(duì)”的數(shù)據(jù)結(jié)構(gòu),Map 比 Object 更合適。

  • 對(duì)象的屬性名一定是字符串,如果寫的不是字符串是其他類型,默認(rèn)將其變?yōu)樽址?
  • map的key可以是任意數(shù)據(jù)類型.
  • map.set(key,value)返回值是這個(gè)MAP
  • map.get(key);返回的是對(duì)應(yīng)的value;
  • map.has();返回的值是布爾類型的
  • clear delete同set類似
  • foreach key values entries
let map=new Map([[true,true],[{},{a:"a"}],[[],[]],[null,null]]);
  //key可以是任意數(shù)據(jù)類型的
  console.log(map);
  //set(key,value) 返回值是這個(gè) map
  console.log(map.set(NaN, NaN));

  //get(key)返回對(duì)應(yīng)的value
  console.log(map.get(true));

  //has(key)->布爾值
  console.log(map.has(NaN));//true

  //clear  delete

  //foEach keys  values  entries
  map.forEach((value,key,c)=>{});
  for (let key of map.keys()){
    //console.log(key);
  }
  for (let value of map.values()){
    //console.log(value);
  }
  for (let [key,value] of map.entries()) {
    console.log(value, key);
  }
map.foreach((value,key,c)=>{
for(let key of map.keys()){consloe.log(key)};
for(let key of map.values()){consloe.log(value)};
for(let [key,value] of map.entries()){console.log(value,key)};
}) 

3.Symbol

  • 基本數(shù)據(jù)類型 通過(guò)函數(shù)執(zhí)行得到 不能使用new執(zhí)行
  • 唯一值
  • 不能進(jìn)行運(yùn)算 因?yàn)椴豢梢赞D(zhuǎn)數(shù)字 也不可以進(jìn)行字符串拼接 這些都會(huì)報(bào)錯(cuò)
  • 可以轉(zhuǎn)為布爾值
  • 當(dāng)做屬性名的時(shí)候只能用[""]的形式
  • Object.getOwnPropertySymbols()
  • Reflect.ownKeys方法可以返回所有類型的鍵名

4.proxy

  • get(target, propKey, receiver):攔截對(duì)象屬性的讀取,比如proxy.foo和proxy['foo']。
  • set(target, propKey, value, receiver):攔截對(duì)象屬性的設(shè)置,比如proxy.foo = v或proxy['foo'] = v,返回一個(gè)布爾值。
  • has(target, propKey):攔截propKey in proxy的操作,返回一個(gè)布爾值。
  • deleteProperty(target, propKey):攔截delete proxy[propKey]的操作,返回一個(gè)布爾值。
  • ownKeys(target):攔截Object.getOwnPropertyNames(proxy)、Object.getOwnPropertySymbols(proxy)、Object.keys(proxy)、for...in循環(huán),返回一個(gè)數(shù)組。該方法返回目標(biāo)對(duì)象所有自身的屬性的屬性名,而Object.keys()的返回結(jié)果僅包括目標(biāo)對(duì)象自身的可遍歷屬性。
  • getOwnPropertyDescriptor(target, propKey):攔截Object.getOwnPropertyDescriptor(proxy, propKey),返回屬性的描述對(duì)象。
  • defineProperty(target, propKey, propDesc):攔截Object.defineProperty(proxy, propKey, propDesc)、Object.defineProperties(proxy, propDescs),返回一個(gè)布爾值。
  • preventExtensions(target):攔截Object.preventExtensions(proxy),返回一個(gè)布爾值。
  • getPrototypeOf(target):攔截Object.getPrototypeOf(proxy),返回一個(gè)對(duì)象。
  • isExtensible(target):攔截Object.isExtensible(proxy),返回一個(gè)布爾值。
  • setPrototypeOf(target, proto):攔截Object.setPrototypeOf(proxy, proto),返回一個(gè)布爾值。如果目標(biāo)對(duì)象是函數(shù),那么還有兩種額外操作可以攔截。
  • apply(target, object, args):攔截 Proxy 實(shí)例作為函數(shù)調(diào)用的操作,比如proxy(...args)、proxy.call(object, ...args)、proxy.apply(...)。
  • construct(target, args):攔截 Proxy 實(shí)例作為構(gòu)造函數(shù)調(diào)用的操作,比如new proxy(...args)。

5.Iterator接口 和for of

一個(gè)數(shù)據(jù)結(jié)構(gòu)只要部署了Symbol.iterator屬性,就被視為具有 iterator 接口,就可以用for...of循環(huán)遍歷它的成員。也就是說(shuō),for...of循環(huán)內(nèi)部調(diào)用的是數(shù)據(jù)結(jié)構(gòu)的Symbol.iterator方法。

for...of循環(huán)可以使用的范圍包括數(shù)組、Set 和 Map 結(jié)構(gòu)、某些類似數(shù)組的對(duì)象(比如arguments對(duì)象、DOM NodeList 對(duì)象)、后文的 Generator 對(duì)象,以及字符串。

Iterator 的遍歷過(guò)程是這樣的。

(1)創(chuàng)建一個(gè)指針對(duì)象,指向當(dāng)前數(shù)據(jù)結(jié)構(gòu)的起始位置。也就是說(shuō),遍歷器對(duì)象本質(zhì)上,就是一個(gè)指針對(duì)象。

(2)第一次調(diào)用指針對(duì)象的next方法,可以將指針指向數(shù)據(jù)結(jié)構(gòu)的第一個(gè)成員。

(3)第二次調(diào)用指針對(duì)象的next方法,指針就指向數(shù)據(jù)結(jié)構(gòu)的第二個(gè)成員。

(4)不斷調(diào)用指針對(duì)象的next方法,直到它指向數(shù)據(jù)結(jié)構(gòu)的結(jié)束位置。

每一次調(diào)用next方法,都會(huì)返回?cái)?shù)據(jù)結(jié)構(gòu)的當(dāng)前成員的信息。具體來(lái)說(shuō),就是返回一個(gè)包含value和done兩個(gè)屬性的對(duì)象。其中,value屬性是當(dāng)前成員的值,done屬性是一個(gè)布爾值,表示遍歷是否結(jié)束。

var it = makeIterator(['a', 'b']);

it.next() // { value: "a", done: false }
it.next() // { value: "b", done: false }
it.next() // { value: undefined, done: true }

function makeIterator(array) {
  var nextIndex = 0;
  return {
    next: function() {
      return nextIndex < array.length ?
        {value: array[nextIndex++], done: false} :
        {value: undefined, done: true};
    }
  };
}

next方法返回一個(gè)對(duì)象,表示當(dāng)前數(shù)據(jù)成員的信息。這個(gè)對(duì)象具有value和done兩個(gè)屬性,value屬性返回當(dāng)前位置的成員,done屬性是一個(gè)布爾值,表示遍歷是否結(jié)束,即是否還有必要再一次調(diào)用next方法。

總之,調(diào)用指針對(duì)象的next方法,就可以遍歷事先給定的數(shù)據(jù)結(jié)構(gòu)。

Iterator 接口的目的,就是為所有數(shù)據(jù)結(jié)構(gòu),提供了一種統(tǒng)一的訪問(wèn)機(jī)制,即for...of循環(huán)。當(dāng)使用for...of循環(huán)遍歷某種數(shù)據(jù)結(jié)構(gòu)時(shí),該循環(huán)會(huì)自動(dòng)去尋找 Iterator 接口。
ES6 規(guī)定,默認(rèn)的 Iterator 接口部署在數(shù)據(jù)結(jié)構(gòu)的Symbol.iterator屬性,或者說(shuō),一個(gè)數(shù)據(jù)結(jié)構(gòu)只要具有Symbol.iterator屬性,就可以認(rèn)為是“可遍歷的”(iterable)。Symbol.iterator屬性本身是一個(gè)函數(shù),就是當(dāng)前數(shù)據(jù)結(jié)構(gòu)默認(rèn)的遍歷器生成函數(shù)。執(zhí)行這個(gè)函數(shù),就會(huì)返回一個(gè)遍歷器。至于屬性名Symbol.iterator,它是一個(gè)表達(dá)式,返回Symbol對(duì)象的iterator屬性,這是一個(gè)預(yù)定義好的、類型為 Symbol 的特殊值,所以要放在方括號(hào)內(nèi)

調(diào)用 Iterator 接口的場(chǎng)合
  • 解構(gòu)賦值
  • 擴(kuò)展運(yùn)算符
    for...of
    Array.from()
    Map(), Set(), WeakMap(), WeakSet()(比如new Map([['a',1],['b',2]]))
    Promise.all()
    Promise.race()
    字符串是一個(gè)類似數(shù)組的對(duì)象,也原生具有 Iterator 接口。
原生具備 Iterator 接口的數(shù)據(jù)結(jié)構(gòu)如下。
  • Array
  • Map
  • Set
  • String
  • TypedArray
  • 函數(shù)的 arguments 對(duì)象
  • NodeList 對(duì)象

6.async await

  • async 將一個(gè)函數(shù)變成promise對(duì)象
  • await后面跟一個(gè)promise對(duì)象 如果不是默認(rèn)將其變成一個(gè)resolve的promise 值作為resolve 的參數(shù)
  • await的結(jié)果就是resolve或者reject的參數(shù)
  • await異步執(zhí)行完成之后再去執(zhí)行后面的代碼

7.Object.getOwnPropertyDescriptor

  • configurable:true 是否可配置 是否可以刪除這個(gè)屬性
  • enumerable:true 是否可枚舉 是否可遍歷
  • value:"dali"
  • writable:true 是否可修改

8.Object.defineProperty

let obj={name:"dali",age:10};
  //new Proxy(target目標(biāo)對(duì)象,{代理的方法})
  let proxy1=new Proxy(obj,{
    get(target,prop){
      //獲取屬性名的屬性值的時(shí)候就會(huì)觸發(fā)這個(gè)get
      return target[prop];
    },
    set(target,prop,value){
      target[prop]=value;
    }
  });
 Object.defineProperty(obj,"name",{
    value:"mq",
    enumerable:false,
    writable:false,
    configurable:false
  });

ES6中的let和const

let基礎(chǔ)語(yǔ)法

let 變量名 = 變量值

使用let創(chuàng)建變量和使用var創(chuàng)建變量的區(qū)別

1、let不存在變量提升機(jī)制

console.log(str);//=>undefined
console.log(fn);//=>FN本身
console.log(avg);//=>undefined
console.log(sum);//=>Uncaught ReferenceError: sum is not defined
console.log(num);//=>Uncaught ReferenceError: num is not defined

var str = '珠峰培訓(xùn)';
let num = 12;
function fn() {}
var avg = function () {};
let sum = function () {};

//=>ES6中只提供了創(chuàng)建變量的新語(yǔ)法標(biāo)準(zhǔn)(let),創(chuàng)建函數(shù)還是沿用ES5中的function(還會(huì)存在變量提升),如果想讓函數(shù)也不存在變量提升,都使用函數(shù)表達(dá)式賦值的方式操作:let fn=function(){}

//=>創(chuàng)建變量
let xxx=xxx;

//=>創(chuàng)建函數(shù)
let xxx=function(){}

//=>自執(zhí)行函數(shù)
;(function(){
    
})();

//=>好處:此時(shí)代碼中就不要在考慮變量提升了,只要這樣處理,沒(méi)有所謂的變量提升

2、使用let定義的變量不允許在同一個(gè)作用域中重復(fù)聲明

var num2 = 12;
var num2 = 13;
console.log(num2);//=>13

let str = '珠峰';
let str = '培訓(xùn)';
console.log(str);//=>Uncaught SyntaxError: Identifier 'str' has already been declared  當(dāng)前報(bào)錯(cuò),上面代碼也不會(huì)執(zhí)行(在JS代碼執(zhí)行之前就已經(jīng)知道有重復(fù)聲明的了,也就是瀏覽器依然存在類似于變量提升的機(jī)制:在JS代碼之前先把所有LET聲明的變量過(guò)一遍,發(fā)現(xiàn)有重復(fù)的直接報(bào)錯(cuò))

let num = 12;
num = 13;
console.log(num);//=>13 LET不允許重復(fù)被聲明,但是允許重新賦值

var att=200;
let att=100;//=>Uncaught SyntaxError: Identifier 'att' has already been declared 不管你之前使用什么方式在當(dāng)前作用域中聲明的變量,再使用let聲明的時(shí)候都會(huì)報(bào)錯(cuò)
let num = 12,
    fn = function () {
        let num = 13;
    };
console.log(num);//=>12 當(dāng)前作用域下別重復(fù)聲明即可(不同作用域中的變量是自己私有的,名字重復(fù)沒(méi)有關(guān)系)

let att = 13,
    sum = function () {
        att = 14;
    };
sum();
console.log(att);//=>let也存在私有變量和作用域鏈的概念,和ES5中基本上差不多  =>14

3、關(guān)于暫時(shí)性死區(qū):使用typeof檢測(cè)一個(gè)未被聲明過(guò)的變量
ES5中返回的結(jié)果是undefined但是不報(bào)錯(cuò)
ES6中直接報(bào)錯(cuò)

"use strict";
console.log(typeof num);//=>undefined 當(dāng)前變量不存在,但是使用typeof檢測(cè)的時(shí)候,不會(huì)提示錯(cuò)誤,而是返回undefined

console.log(typeof num);//=>Uncaught ReferenceError: num is not defined  ES6中檢測(cè)一個(gè)沒(méi)有被聲明過(guò)的變量直接報(bào)錯(cuò),不像之前ES5中的值是UNDEFINED一樣了
let num;

let num;
console.log(typeof num);//=>undefined 只聲明沒(méi)有定義(賦值),默認(rèn)值是UNDEFINED

4、ES6語(yǔ)法創(chuàng)建的變量(let)存在塊級(jí)作用域,ES5語(yǔ)法創(chuàng)建變量(var/function)沒(méi)有塊級(jí)作用域

[ES5]
window全局作用域
函數(shù)執(zhí)行形成的私有作用域

[ES6]
除了有ES5中的兩個(gè)作用域,ES6中新增加塊級(jí)作用域(我們可以把塊級(jí)作用域理解為之前學(xué)習(xí)的私有作用域:存在私有變量和作用域鏈的一些機(jī)制) ES6語(yǔ)法中把大部分用大括號(hào)包起來(lái)都稱之為塊級(jí)作用域

let num = 12,
    str = '';
let fn = function (str) {
    str = 'HELLO';
    //console.log(arguments[0]);//=>"HELLO" 當(dāng)前JS并沒(méi)有開啟嚴(yán)格模式,所以形參變量和ARG存在映射機(jī)制(但是我們以后盡量不要這樣處理:因?yàn)榘袳S6編譯為ES5之后,會(huì)默認(rèn)的開啟嚴(yán)格模式,映射機(jī)制會(huì)中斷,此處的值依然是'珠峰',這樣導(dǎo)致我們的ES6結(jié)果和ES5結(jié)果不一致)
    // console.log(num);//=>Uncaught ReferenceError: num is not defined
    let num = 13;
    console.log(num, str);//=>13 "HELLO"
};
fn('珠峰');
console.log(num, str);//=>12 ''

大部分我們遇到的大括號(hào)操作都是塊級(jí)作用域

/*
if (10 >= 10) {
    let total = 100;
}
console.log(total);//=>Uncaught ReferenceError: total is not defined 判斷體也是一個(gè)塊級(jí)私有作用域,在這個(gè)作用域中聲明的變量是私有變量,在塊級(jí)作用域之外是無(wú)法使用的
*/

/*
for (let i = 0; i < 5; i++) {
    console.log(i);
}
console.log(i);//=>Uncaught ReferenceError: i is not defined 循環(huán)體也是一個(gè)塊級(jí)作用域(每一次循環(huán)都會(huì)形成一個(gè)新的塊級(jí)作用域:當(dāng)前案例形成五個(gè)塊級(jí)作用域,每一個(gè)塊級(jí)作用域中都有一個(gè)私有變量i,分別存儲(chǔ)的是0~4)
*/

/*{
    let i=12;
}
console.log(i);//=>Uncaught ReferenceError: i is not defined 這是一個(gè)ES6中標(biāo)準(zhǔn)的塊級(jí)作用域*/

/*
let i=10;
{
    let i=20;
    {
        {
            console.log(i);//=>Uncaught ReferenceError: i is not defined 雖然ES6沒(méi)有變量提升,但是每一次進(jìn)入當(dāng)前作用域都會(huì)把LET定義的變量找一遍(不提升但是找了,找到了說(shuō)明當(dāng)前作用域中是有這個(gè)變量的,提前用都會(huì)報(bào)錯(cuò))
        }
        let i=30;
    }
}
*/

/*
try{
    let i=100;
}catch (e){
    let k=200;
}
console.log(k);//=>Uncaught ReferenceError: k is not defined
console.log(i);//=>Uncaught ReferenceError: i is not defined TRY CATCH中的任何大括號(hào)都是塊級(jí)作用域
*/

/*
switch (10){
    case 10:
        let i=20;
        break;
}
console.log(i);//=>Uncaught ReferenceError: i is not defined
*/

/*
let obj={name:'珠峰'};
for (let key in obj) {

}
console.log(key);//=>Uncaught ReferenceError: key is not defined
*/

塊級(jí)作用域的增加有什么用?

let tempList = document.getElementsByName('TEMP');
// for (var i = 0; i < tempList.length; i++) {
//     tempList[i].onclick = function () {
//         console.log(i);//=>5 怎么點(diǎn)擊都是5 異步操作以及作用域鏈的查找,找到的都是全局下最后一次循環(huán)的結(jié)束值
//     }
// }

//=>自定義屬性解決
// for (var i = 0; i < tempList.length; i++) {
//     tempList[i].index = i;
//     tempList[i].onclick = function () {
//         console.log(this.index);
//     }
// }

//=>閉包解決
// for (var i = 0; i < tempList.length; i++) {
//     ~function (i) {
//         tempList[i].onclick = function () {
//             console.log(i);
//         }
//     }(i);
// }

//=>使用ES6的塊級(jí)作用域
for (let i = 0; i < tempList.length; i++) {
    tempList[i].onclick = function () {
        console.log(i);
    }
}

const的基礎(chǔ)語(yǔ)法

const的細(xì)節(jié)知識(shí)點(diǎn)和let一樣,和let的主要區(qū)別在于:let是創(chuàng)建變量,const是創(chuàng)建常量

變量:值是可以修改的
常量:值不能被修改

let num = 12;
num = 13;
console.log(num);//=>13

const str = '珠峰';
str = '培訓(xùn)';//=>而且使用BABEL如果遇到了CONST設(shè)置的常量在進(jìn)行修改,就無(wú)法進(jìn)行編譯了
console.log(str);//=>Uncaught TypeError: Assignment to constant variable.

JS中創(chuàng)建變量方式匯總

var :ES5中創(chuàng)建變量
function:ES5中創(chuàng)建函數(shù)
ES5中創(chuàng)建變量或者函數(shù)存在:變量提升、重復(fù)聲明等特征,但是沒(méi)有塊級(jí)作用域的機(jī)制

let:ES6中創(chuàng)建變量
const:ES6創(chuàng)建常量
ES6中創(chuàng)建的變量或者常量都不可以變量提升,也不可以重復(fù)聲明,而且還存在塊級(jí)作用域

class:ES6中創(chuàng)建類的方式
import:ES6中模塊導(dǎo)入的方式

class Parent{
    constructor(){
        //=>this.xxx=xxx
    }
    //=>Parent.prototype
    aa(){}
    
    //=>Parent own property
    static bb(){}
}

ES6中的解構(gòu)賦值

按照原有值的結(jié)構(gòu),把原有值中的某一部分內(nèi)容快速獲取到(快速賦值給一個(gè)變量)

數(shù)組的解構(gòu)賦值

結(jié)構(gòu)賦值本身是ES6的語(yǔ)法規(guī)范,使用什么關(guān)鍵字來(lái)聲明這些變量是無(wú)所謂的

let [a,b,c] = [12,23,34];
//=>a:12 b:23 c:34

var [d,e,f] = [12,23,34];
//=>d:12 e:23 f:34

[g,h,i] = [12,23,34];
//=>此處相當(dāng)于給window增加的全局屬性
//g:12 h:23 i:34
//=>但是這個(gè)操作在JS的嚴(yán)格模式下是不允許的,因?yàn)閲?yán)格模式下不允許出現(xiàn)非使用var/let等聲明的變量

多維數(shù)組的結(jié)構(gòu)賦值,可以讓我們快速獲取到需要的結(jié)果

let [,[,A],[,B,[,C]]] = [12, [23, 34], [45, 56, [67, 78]]];
console.log(A, B, C);//=>34 56 78

如果只想獲取數(shù)組中前面的某幾項(xiàng)內(nèi)容,后面的結(jié)構(gòu)不需要不全

let [D]=[12, 23, 34];
console.log(D);//=>12

let [,E]=[12, 23, 34];
console.log(E);//=>23

在解構(gòu)賦值中,我們可以給某一項(xiàng)設(shè)置默認(rèn)值

let [,,,A]=[12, 23, 34];
console.log(A);//=>undefined

let [,,,B = 0]=[12, 23, 34];
console.log(B);//=>0

在解構(gòu)賦值中,支持...xxx的拓展運(yùn)算符

let [A,...B]=[12, 23, 34, 45, 56];
console.log(A, B);//=>12 [23,34...]

let [...C]=[12, 23, 34, 45, 56];
console.log(C);//=>[12,23...] 數(shù)組克隆

let [D,...E,F]=[12, 23, 34, 45, 56];
console.log(D, E, F);//=>Uncaught SyntaxError: Rest element must be last element 拓展運(yùn)算符只能出現(xiàn)在解構(gòu)賦值中的結(jié)構(gòu)末尾的位置

let [G,,,...H]=[12, 23, 34, 45, 56];
console.log(G, H);//=>12 [45,56]

對(duì)象的解構(gòu)賦值

let {name, age}={name: '珠峰培訓(xùn)', age: 9};
console.log(name, age);//=>'珠峰培訓(xùn)' 9

let {A, B}={name: '珠峰培訓(xùn)', age: 9};
console.log(A, B);//=>在對(duì)象的解構(gòu)賦值中需要注意的是:賦值的變量需要和對(duì)象中的屬性名吻合,否則無(wú)法獲取對(duì)應(yīng)的屬性值 undefined*2

let {C = 0}={name: '珠峰培訓(xùn)', age: 9};
console.log(C);//=>0 可以給當(dāng)前的變量設(shè)置默認(rèn)值
let {name}={name: '珠峰培訓(xùn)', age: 9};
console.log(name);//=>'珠峰培訓(xùn)'  和數(shù)組的解構(gòu)賦值一樣,我們可以把后面不需要獲取的結(jié)構(gòu)省略掉

let {,age}={name: '珠峰培訓(xùn)', age: 9};//=>Uncaught SyntaxError: Unexpected token , 和數(shù)組的解構(gòu)賦值不一樣的地方在于,對(duì)象前面不允許出現(xiàn)空來(lái)占位(因?yàn)閷?duì)象獲取需要通過(guò)具體的屬性名獲取,寫成空的話,瀏覽器不知道怎么識(shí)別)

let {age}={name:'xxx',age:'xxx'};//=>但是我們可以把逗號(hào)去掉,這樣就是只獲取其中一個(gè)
let {name, ...arg}={name: '珠峰培訓(xùn)', age: 9, teacher: '周嘯天'};
console.log(name, arg);//=>'珠峰培訓(xùn)' {age:9...}  支持拓展運(yùn)算符的

//=>把對(duì)象進(jìn)行淺克隆(只把第一級(jí)克隆了)
let obj = {name: 'xxx', age: 10, score: [100, 90, 80]};
let {...arg}=obj;
console.log(arg, obj);
console.log(arg === obj);//=>false
console.log(arg.score === obj.score);//=>true
let {name:A, age:B}={name: '珠峰培訓(xùn)', age: 9};
console.log(A, B);//=>'珠峰培訓(xùn)' 9  在對(duì)象的結(jié)構(gòu)賦值中,我們可以把對(duì)象的屬性名起一個(gè)小名(A和B相當(dāng)于小名或者叫做別名)
let data = [
    {
        "name": "張三",
        "age": 25,
        "score": {
            "english": [100, 90, 95],
            "math": [100, 100, 100],
            "chinese": [98, 99, 100]
        }
    },
    {
        "name": "李四",
        "age": 24,
        "score": {
            "english": [8, 9, 3],
            "math": [149, 150, 148],
            "chinese": [138, 140, 145]
        }
    }
];
let [{score:{english:[A], math:[,B], chinese:[,,C]}}]=data;
console.log(A, B, C);//=>100 100 100

解構(gòu)賦值的作用

快速交換兩個(gè)變量的值

let a = 12;
let b = 13;
[a, b] = [b, a];
console.log(a, b);//=>13 12

接收函數(shù)返回的多個(gè)值

let fn = function () {
    let a = 12,
        b = 13,
        c = 14;
    return [a, b, c];
};
let [a,b,c] = fn();
console.log(a, b, c);//=>12 13 14

可以快速接收到傳遞的多個(gè)值(我傳遞的是一個(gè)數(shù)組或者對(duì)象)

let fn = function ([A,B,C,D = 0]) {
    console.log(A, B, C, D);//=>12 23 34 0
};
fn([12, 23, 34]);
//console.log(A);//=>Uncaught ReferenceError: A is not defined 函數(shù)中的ABC是私有的變量

//=>快速處理options參數(shù)的初始化操作
let animate = function ({curEle = null, target = {}, duration = 1000, callBack = null}={}) {
    console.log(curEle, target, duration, callBack);//=>body {opacity: 1} 1000 null
};
animate({
    curEle: document.body,
    target: {opacity: 1}
});

在ES6中支持給函數(shù)設(shè)置默認(rèn)值

let fn = function (x) {
    console.log(x);//=>undefined
    x = x || 0;
    console.log(x);//=>0
};
fn();

let fn2 = function (x = 0) {
    console.log(x);//=>0
};
fn2();

按照一個(gè)數(shù)據(jù)值得結(jié)構(gòu),快速解析獲取到其中的內(nèi)容
1.真實(shí)項(xiàng)目中一般都是針對(duì)于數(shù)組或者對(duì)象進(jìn)行解構(gòu)賦值。

`數(shù)組解構(gòu)賦值`
let ary=[1,2,3]
let[a,b,c]=ary;//讓等號(hào)左邊出現(xiàn)和右邊相同的數(shù)據(jù)結(jié)構(gòu),左邊可以創(chuàng)建一些變量快速獲取到右側(cè)對(duì)應(yīng)位置的值
let[,,c]=ary;//=>c=3
獲取第一項(xiàng),把剩下的項(xiàng)作為一個(gè)數(shù)組返回
let[a,...b]=ary;//...在此處被稱為剩余運(yùn)算符
console.log(a,b);//=>1,[2,3]
let[a,...b,c]=ary;//會(huì)報(bào)錯(cuò),剩余運(yùn)算符只能處于解構(gòu)中最后的位置
let ary=[12];
let [a,b=0]=ary;//解構(gòu)的時(shí)候可以給變量設(shè)置默認(rèn)值,如果當(dāng)前變量對(duì)應(yīng)結(jié)構(gòu)中的這一項(xiàng)沒(méi)有值,變量用默認(rèn)值。
console.log(a,b);//12,0
如果對(duì)應(yīng)的位置有值,會(huì)把默認(rèn)的值覆蓋。
let a=12,b=13;//讓a,b互換位置
[a,b]=[b,a]


----------
對(duì)象解構(gòu)賦值
let obj={name:"dali",age:25,high:184};
let {name,age}=obj;//左側(cè)變量名和對(duì)象中的屬性名保持一致才可以
let {high}=obj;//=>184;
let {age:ageAA}=obj;
console.log(ageAA);//=>25,給解構(gòu)的屬性名起別名作為我們使用的變量
let {friend=0}=obj;
console.log(friend);//=>0給不存在的屬性設(shè)置默認(rèn)值
let fn=function({}={}){//把傳遞的對(duì)象解構(gòu)了,不傳遞值默認(rèn)賦值為空對(duì)象:現(xiàn)在傳遞對(duì)象或者不傳遞,形參接收到的都是對(duì)象,結(jié)構(gòu)的時(shí)候可以把傳遞進(jìn)來(lái)的對(duì)象中,如果某個(gè)屬性不存在我們賦值默認(rèn)值

};
fn({name:"xxx",age:25})
let value={}


2."..."有三個(gè)含義:
1.剩余運(yùn)算符
2.拓展運(yùn)算符
3.展開運(yùn)算符:把數(shù)組(對(duì)象/類數(shù)組)中的每一項(xiàng)展開,分別傳遞給一個(gè)函數(shù)

let ary=[1,2,3];
let[...arg]=ary;//=>ary.slice(0);


function fn(context,...arg)
//獲取傳遞值中的第一個(gè)和剩下的{console.log(context,arg)//arg是一個(gè)數(shù)組、arguments是類數(shù)組。
}
let={}
fn(obj,1,2,3)

function sun(...arg){//類似于arguments但是arg是數(shù)組,arguments是類數(shù)組
}
let obj={name:"dali",age:25}
let newObj={...obj,sex:0}//{name:"dali",age:25,sex:0}
let ary=[12,23];
let Newary=[...ary,100,...ary];//=>[12,23,100,12,13];

ES6中的箭頭函數(shù)

let fn=(x,y)=>{};
fn(10,20);

let fn=x=>{};只有一個(gè)形參我們可以省略小括號(hào)。
fn(10);

let fn=(x,y)=>x+y;
fn(10,20);//如果函數(shù)體只有一句操作并且是return的我們可以省略大括號(hào)(給形參設(shè)置默認(rèn)值)

let fn=x=>y=>x+y;等同于
var fn=function fn(x){
return function(y){
return x+y;}}
箭頭函數(shù)沒(méi)有arguments,
let fn=(...arg)=>{};//可以使用剩余運(yùn)算符而且arg是一個(gè)數(shù)組
fn(1,2,3,4);

箭頭函數(shù)中沒(méi)有自己的執(zhí)行主體(this),他的this都是繼承上下文中的this.
let obj={
fn:(function(){
return function (){console.log(this);}
})()
}
obj.fn();//this:obj//如何把this指向window,可以用call,也可以在自執(zhí)行那里自定義一個(gè)變量,在return后的輸出這個(gè)變量
用箭頭函數(shù):
let obj ={fn:(function(){return ()=>{console.log(this);}
})()
};
obj.fn();//this:window箭頭函數(shù)執(zhí)行和是否有點(diǎn),點(diǎn)前面是誰(shuí)都沒(méi)有關(guān)系了,因?yàn)樗麤](méi)有自己的執(zhí)行主體,在箭頭函數(shù)中使用到的this都是直接找上下文中的this來(lái)使用

自執(zhí)行函數(shù)用箭頭函數(shù)表示:
(()=>{})();

箭頭函數(shù)的基礎(chǔ)語(yǔ)法

let fn = function (x, y) {
    return x + y;
};
console.log(fn(10, 20));//=>30

//=>改寫成箭頭函數(shù)
let fn = (x, y)=> x + y;
let fn = function (n = 0) {
    let x = 10,
        y = 20;
    return x + y + n;
};
//=>改寫成箭頭函數(shù)
let arrowFn = (n = 0)=> {
    let x = 10,
        y = 20;
    return x + y + n;
};

箭頭函數(shù)中不支持arguments

//=>傳統(tǒng)函數(shù)支持ARGUMENTS
// let fn = function () {
//     let arg = Array.prototype.slice.call(arguments);
//     return eval(arg.join('+'));
// };

let fn = (...arg)=> {
    //console.log(arguments);//=>Uncaught ReferenceError: arguments is not defined
    //=>不支持ARGUMENTS沒(méi)事,我們使用ES6中的剩余運(yùn)算符...來(lái)獲取傳遞的進(jìn)來(lái)的所有參數(shù)值(優(yōu)勢(shì):使用剩余運(yùn)算符接收到的結(jié)果本身就是一個(gè)數(shù)組,不需要再轉(zhuǎn)換了)
    //console.log(arg instanceof Array);//=>true
    return eval(arg.join('+'));
};
//=>也可以把FN簡(jiǎn)寫成以下方式
//let fn = (...arg)=> eval(arg.join('+'));
console.log(fn(10, 20, 30, 40));

箭頭函數(shù)中的this問(wèn)題

復(fù)習(xí)普通函數(shù)中this指向的問(wèn)題

let obj = {
    name: 'obj',
    fn(){
        //=>這樣處理和下面SUM的處理是一樣的
        console.log(this);
    },
    sum: function () {

    }
};
obj.fn();//=>this:obj 普通函數(shù)執(zhí)行THIS的指向:看函數(shù)執(zhí)行前面是否有點(diǎn),有點(diǎn),點(diǎn)前面是誰(shuí)THIS就是誰(shuí),沒(méi)有點(diǎn)THIS指向WINDOW或者UNDEFINED(嚴(yán)格模式下)
document.body.onclick = obj.fn;//=>this:body
setTimeout(obj.fn, 1000);//=>this:window
obj.fn.call(12);//=>this:12

箭頭函數(shù)中沒(méi)有自己的THIS指向,用到的THIS都是所在宿主環(huán)境(它的上級(jí)作用域)中的THIS

let obj = {
    name: 'obj',
    fn: ()=> {
        console.log(this);
        //=>不管我們?cè)趺慈ゲ僮?最后THIS都指向WINDOW:箭頭函數(shù)中沒(méi)有自己的THIS指向,用到的THIS都是所在宿主環(huán)境(它的上級(jí)作用域)中的THIS
    }
};
obj.fn();
document.body.onclick = obj.fn;
setTimeout(obj.fn, 1000);
obj.fn.call(12);

以后實(shí)戰(zhàn)項(xiàng)目中,不是要把所有的函數(shù)都改為箭頭函數(shù),根據(jù)自身需要來(lái)修改即可(例如:我們需要讓函數(shù)中的this是宿主環(huán)境中的this,我們才來(lái)使用箭頭函數(shù);或者不涉及this問(wèn)題,我們想讓代碼寫起來(lái)簡(jiǎn)單一些也可以使用箭頭函數(shù);)

let obj = {
    name: 'obj',
    fn(){
        //=>this:obj

        // setTimeout(function () {
        //     //=>this:window
        // }, 1000);

        // setTimeout(function () {
        //     //=>this:obj
        // }.bind(this), 1000);

        // var _this = this;
        // setTimeout(function () {
        //     //=>_this:obj
        // }, 1000);

        setTimeout(()=> {
            //=>this:obj
        }, 1000);
    }
};
obj.fn();

箭頭函數(shù)的一點(diǎn)擴(kuò)充

宿主環(huán)境:不是執(zhí)行的環(huán)境而是定義的環(huán)境

let fn = ()=> {
    console.log(this);
};

let obj = {
    name: 'obj',
    sum: function () {
        //=>this:obj

        fn();//=>this:window
        //宿主環(huán)境:不是執(zhí)行的環(huán)境而是定義的環(huán)境,F(xiàn)N雖然是在這執(zhí)行的,但是它是在WINDOW下定義的,所以它的宿主環(huán)境還是WINDOW
    }
};
obj.sum();

層級(jí)嵌套的箭頭函數(shù)

// let fn = function (i) {
//     return function (n) {
//         return n + (++i);
//     }
// };

let fn = (i)=> (n)=> n + (++i);

ES6中的類和繼承

ES5中創(chuàng)建類和實(shí)例,以及如何禁止用戶把類當(dāng)做普通函數(shù)執(zhí)行:new.target

function Person(name, age) {
    //console.log(new.target);//=>ES6新增加的語(yǔ)法,如果是通過(guò)NEW執(zhí)行的,返回的結(jié)果是當(dāng)前創(chuàng)建的類,如果是當(dāng)做普通函數(shù)執(zhí)行的,返回的是UNDEFINED
    if (typeof new.target === 'undefined') {
        throw new SyntaxError(`當(dāng)前Person不能作為一個(gè)普通函數(shù)執(zhí)行,請(qǐng)使用new Person來(lái)執(zhí)行~~`);
    }

    //=>NEW執(zhí)行的時(shí)候,THIS是當(dāng)前類的實(shí)例,THIS.XXX=XXX是給當(dāng)前實(shí)例增加的私有屬性
    this.name = name;
    this.age = age;
}
//=>原型上存放的是公有的屬性和方法:給創(chuàng)建的實(shí)例使用
Person.prototype = {
    constructor: Person,
    say: function () {
        console.log(`my name is ${this.name},i am ${this.age} years old~`);
    }
};
//=>把PERSON當(dāng)做一個(gè)普通的對(duì)象,給對(duì)象設(shè)置的私有屬性
Person.study = function () {
    console.log(`good good study,day day up~`);
};

var p1 = new Person('王雪超', '80');
Person('王雪超', '80');

ES6中創(chuàng)建類

//console.log(Person);//=>Uncaught ReferenceError: Person is not defined 不存在變量提升
class Person {
    constructor(name = '珠峰培訓(xùn)', age = 9) {
        //=>給實(shí)例設(shè)置的私有屬性
        this.name = name;
        this.age = age;
    }

    //=>直接在大括號(hào)中編寫的方法都設(shè)置在類的原型上:ES6默認(rèn)把CONSTRUCTOR的問(wèn)題解決了,此時(shí)原型上的CONSTRUCTOR指向的就是PERSON
    say() {
        console.log(`my name is ${this.name},i am ${this.age} years old~`);
    }

    //=>把PERSON當(dāng)做普通對(duì)象設(shè)置屬性和方法,只需要在設(shè)置的方法前面加STATIC即可
    static study() {
        console.log(`good good study,day day up~`);
    }
}
let p1 = new Person('王雪超');
//Person();//=>Uncaught TypeError: Class constructor Person cannot be invoked without 'new' =>ES6中使用CLASS創(chuàng)建的類,天生自帶NEW.TARGET的驗(yàn)證,不允許把創(chuàng)建的類當(dāng)做普通函數(shù)執(zhí)行

ES6中的繼承

class Person {
    constructor(...ARG) {
        let [x = 0,y = 0]=ARG;
        this.x = x;
        this.y = y;
    }

    sum() {
        return this.x + this.y;
    }
}

class Child extends Person {
    //=>創(chuàng)建CHILD類,并且讓CHILD類繼承了PERSON類:
    //1、把PERSON中的私有屬性繼承過(guò)來(lái)設(shè)置給了子類實(shí)例的私有屬性
    //2、讓子類實(shí)例的原型鏈上能夠找到PERSON父類的原型(這樣子類的實(shí)例就可以調(diào)用父類原型上的方法了)

    //-------------
    //=>我們可以不寫CONSTRUCTOR,瀏覽器默認(rèn)會(huì)創(chuàng)建它,而且默認(rèn)就把父類私有的屬性繼承過(guò)來(lái)了(而且把傳給子類的參數(shù)值也傳遞給父類了)
    // constructor(...arg) {
    //     //=>ARG:傳遞給子類的參數(shù)(數(shù)組) [剩余運(yùn)算符]
    //     super(...arg);//=>[展開運(yùn)算符] 把ARG中每一項(xiàng)值展開,分別傳遞給父類方法 SUPPER(10,20,30)
    // }

    //------------
    //=>很多時(shí)候我們不僅要繼承父類私有的,還需要給子類增加一些而外私有的,此時(shí)就必須寫CONSTRUCTOR,但是一定要在CONSTRUCTOR中的第一行寫上SUPPER,否則會(huì)報(bào)錯(cuò)
    // constructor(...arg) {
    //     super(...arg);
    //
    //     let [,,z]=arg;
    //     this.z = z;
    // }

    constructor(x, y, z) {
        super();//<=>Person.prototype.constructor.call(this)
        this.z = z;
    }

    fn() {

    }
}
let c = new Child(10, 20, 30);

ES6:let創(chuàng)建的變量不存在變量提升

在es6中基于let或者const等方式創(chuàng)建變量或者函數(shù)

  • 不存在變量提升機(jī)制,
  • 切斷了全局變量和window屬性的映射機(jī)制。
  • 在相同作用域中,基于let不能聲明相同名字的變量( 不管用什么方式在當(dāng)前作用域下聲明了變量再次使用let創(chuàng)建都會(huì)報(bào)錯(cuò))
  • 雖然沒(méi)有變量提升機(jī)制,但是在當(dāng)前作用于代碼自上而下執(zhí)行之前,瀏覽器會(huì)做一個(gè)重復(fù)性檢測(cè)(語(yǔ)法檢測(cè)):自上而下查找當(dāng)前作用域下所有變量,一旦發(fā)現(xiàn)有重復(fù)的直接拋出異常代碼也不會(huì)在執(zhí)行了(雖然沒(méi)有把變量提前聲明定義但是瀏覽器記住了當(dāng)前作用域有哪些變量)
  • 基于let和基于var創(chuàng)建變量,在私有變量和作用域鏈機(jī)制上是一樣的
  • 現(xiàn)有項(xiàng)目當(dāng)中是es5和es6混合開發(fā)模式,如果當(dāng)前變量是基于let創(chuàng)建的,就按照es6的語(yǔ)法機(jī)制渲染的,否則按照es5的老語(yǔ)法機(jī)制渲染

基于let創(chuàng)建的變量存儲(chǔ)塊級(jí)作用域(類似于函數(shù)執(zhí)行形成的私有作用域=》一般來(lái)說(shuō)基本上所有的{}都會(huì)形成塊級(jí)作用域。
包括:let,循環(huán)體,判斷體,{}。

console.log(a);//報(bào)錯(cuò)語(yǔ)法錯(cuò)誤:a is not undefined
let a=12;
console.log(window.a);//undefined

let a = 10,
    b = 20;
let fn = function () {
    console.log(a, b);//a會(huì)報(bào)語(yǔ)法錯(cuò)誤,not defined.沒(méi)有變量提升
    let a = b = 30;//let a=20,b=20
    console.log(a, b);
};
console.log(a, b);

var a=12;
if(true){
consloe.log(a);//會(huì)報(bào)錯(cuò)a is not defined
let a=13;//基于let創(chuàng)建變量會(huì)把大部分{}當(dāng)做一個(gè)私有的塊級(jí)作用域(類似函數(shù)的私有作用域),在這里也是重新檢測(cè)語(yǔ)法規(guī)范,看一下是否是基于新語(yǔ)法創(chuàng)建的變量,如果是按照新語(yǔ)法規(guī)范來(lái)解析
}
console.log(typeof a);//""undefined",在原有瀏覽器渲染機(jī)制下,基于typeof 等邏輯運(yùn)算符檢測(cè)一個(gè)未被聲明的變量,不會(huì)報(bào)錯(cuò)返回undefined
console.log(typeof a);//報(bào)錯(cuò),a is not undefined
let a=13;//如果當(dāng)前變量是基于es6語(yǔ)法處理,在沒(méi)有聲明這個(gè)變量的時(shí)候使用typeof檢測(cè)會(huì)直接報(bào)錯(cuò)不會(huì)是undefined,解決了原有的js死區(qū)。

全局變量和私有變量

var a=12,b=13,c=14;
function fn(a){//a是形參,所以a是私有變量
console.log(a,b,c);//12,undefined,14
var b=c=a=20;//var b=20;c=20;a=20
console.log(a,b,c);}//20,20,20
fn(a);
conslole.log(a,b,c);//12,13,20

var ary=[12,23];
function fn(ary){
console.log(ary);//[12,23]
ary[0]=100;
ary=[100];
ary[0]=0;
console.log(ary);//[0]
}
fn(ary);
console.log(ary);//[100,23]

在私有變量當(dāng)中,只有當(dāng)前以下兩種是私有變量“
1.帶var的
2.形參也是私有變量

  • 剩下的都不是私有變量,需要基于作用域鏈向上查找

查找上級(jí)作用域

  • 當(dāng)前函數(shù)執(zhí)行形成一個(gè)私有作用域a,a的上級(jí)作用域是誰(shuí),和他在哪執(zhí)行沒(méi)有關(guān)系,和他在哪創(chuàng)建定義的有關(guān)系,在哪創(chuàng)建的他的上級(jí)作用域就是誰(shuí)
    var a=12;
    function fn(){
    //arguments:實(shí)參集合;
    //arguments.callee:函數(shù)本身fn;
    //arguments.callee.caller:當(dāng)前函數(shù)在哪執(zhí)行的,caller就是誰(shuí)(記錄的是他執(zhí)行的宿主環(huán)境),在全局下執(zhí)行caller的結(jié)果是null

}

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,702評(píng)論 6 534
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,615評(píng)論 3 419
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,606評(píng)論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,044評(píng)論 1 314
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,826評(píng)論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,227評(píng)論 1 324
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,307評(píng)論 3 442
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,447評(píng)論 0 289
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,992評(píng)論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,807評(píng)論 3 355
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,001評(píng)論 1 370
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,550評(píng)論 5 361
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,243評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,667評(píng)論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,930評(píng)論 1 287
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,709評(píng)論 3 393
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,996評(píng)論 2 374

推薦閱讀更多精彩內(nèi)容

  • 本文為阮一峰大神的《ECMAScript 6 入門》的個(gè)人版提純! babel babel負(fù)責(zé)將JS高級(jí)語(yǔ)法轉(zhuǎn)義,...
    Devildi已被占用閱讀 2,009評(píng)論 0 4
  • [TOC] 參考阮一峰的ECMAScript 6 入門參考深入淺出ES6 let和const let和const都...
    郭子web閱讀 1,801評(píng)論 0 1
  • 三,字符串?dāng)U展 3.1 Unicode表示法 ES6 做出了改進(jìn),只要將碼點(diǎn)放入大括號(hào),就能正確解讀該字符。有了這...
    eastbaby閱讀 1,554評(píng)論 0 8
  • 什么是ES6? ECMAScript 6.0 是繼ECMAScript 5.1 之后 JavaScript 語(yǔ)...
    多多醬_DuoDuo_閱讀 1,113評(píng)論 0 4
  • 今天視頻的內(nèi)容是成長(zhǎng)型心智培養(yǎng)的重要性,這個(gè)關(guān)乎個(gè)人的成長(zhǎng),對(duì)個(gè)人未來(lái)成功有著密切關(guān)聯(lián)。作者提到目前大家的心智主要...
    淡墨非痕閱讀 477評(píng)論 0 0