js es6語法 es5的嚴格模式 es6 let const 塊級作用域 let和const和var的區別 解構賦值 物件的擴充套件 函式的擴充套件 箭頭函式
一, ECMAScript和javascript的關係
ECMAScript是一個語法核心標準,javascript是語法的一種體現 。
二, es5的嚴格模式
1, 嚴格模式:
其實就是在一定程度上把語法規定的更標準,為了規範程式碼的標準性
2, 原因:
消除javascript 一些語法的不合理,不嚴謹,減少一些怪異行為
消除程式碼中的一些不安全的地方,保證程式碼的執行安全環境
提高編譯效率,增加執行速度
為了將來的javascript的標準做準備
3, 使用方式:
將 use strict
放在所有程式碼的第一行,則整個指令碼就處於一種嚴格編譯的環境
如果這行不在整個程式碼塊的首行,沒有效果(非嚴格模式)
4, 使用範圍:
全域性範圍
"use strict"; // es5的嚴格模式啟動
a = 10;
console.log(a); // a is not define
for迴圈內的嚴格模式
"use strict";
for (i = 0; i < 5; i++) {
console.log(i);
}
console.log(i);
自執行函式
var a = 10
;(function(){
"use strict";
console.log(10);
})()
區域性範圍
function fn(){ "use strict"; // es5的嚴格模式啟動 b = 10; console.log(b); // b is not defined } fn()
5, 失效的情況:
如果嚴格模式之前有程式碼,嚴格會失效,有空格,分號都不行,但是註釋沒問題
b = 20;
"use strict";
a = 10;
console.log(a);
6, 如果使用了嚴格模式。會影響arguments
"use strict"; function fn(a){ arguments[0] = 2; console.log(a); console.log(arguments[0]); } fn(1); // 變異 "use strict"; function fn(a){ arguments[0] = 2; // 當使用alert的時候,嚴格模式失效 alert(arguments[0]); } fn(1);
7, eval()函式計算javascript字串的,並把字串當做一個指令碼執行
如果引數是一個表示式,eval()函式執行表示式,如果引數是javascript的語句,eval()函式執行這個語句
console.log(eval("var a=10"));
eval("var a=10;console.log(a)");
console.log(eval("1+2")); // 3
console.log(eval("{b:2}"));
console.log(eval("({b:2})"));
eval("mytest()");
function mytest() {
console.log(1);
}
// 嚴格模式
"use strict";
var eval = 10;
console.log(eval);
var obj = {}
obj.eval=10;
obj.a = eval;
function fn(eval){
}
8, 嚴格模式刪除系統內建屬性會報錯
"use strict";
/* console.log(Object.prototype); // __proto__
console.log(Function.prototype); */
// 內建屬性
delete Object.prototype;
9, JSON格式的資料
JSON.parse() :把字串格式的資料轉換成json物件格式的資料
JSON.stringify():把json格式的資料轉換為字串格式的資料
var arr = [1,2,3];
console.log(typeof arr);
console.log(JSON.stringify(arr));
console.log(typeof JSON.stringify(arr));
console.log('-------');
var arr1 = '[1,2,3]';
console.log(typeof arr1);
console.log(JSON.parse(arr1));
console.log(typeof JSON.parse(arr1));
// 注意:屬性名和屬性值全部要使用引號引起來
var json = '{"name":"zhangsan"}'
10, Object()擴充套件
建立一個物件
基於一個物件,建立一個新的物件,並可以對新隊形的屬性進行描述(操作)
語法:Object.create(person,decrtion);
person:原有的物件
decrtion:屬性描述 value:屬性值
writable:屬性是否可以修改新的屬性,預設值是false,不可以修改
configurable:是否可以刪除新的屬性,預設值是false,不可以刪除
ennumerable:是否可以列舉(遍歷)預設值是false,不可以列舉(遍歷)
建立一個物件:
var person = {
name:'張三',
age:20,
}
var me = Object.create(person);
me.name = '李四';
me.age = 30;
console.log(me);
操作屬性
var me = Object.create(person, {
sex: {
value: '男',
writable:true, // 可以更改屬性
configurable:true,//可以刪除
enumerable:true,// 可以遍歷(列舉)
},
sex1: {
value: '男',
}
})
// me.sex = '女';
delete me.sex;
// console.log(me.sex);
for(var attr in me){
console.log(attr);
}
Object.defineProperties(object,descriptors)
這個方法直接在一個物件上定義新的屬性或者修改現有的屬性,並返回該duixaing
object:定義或修改的屬性的物件
get:作為該屬性的getter函式,如果沒有getter結果為undefined,函式返回值將被作為屬性的值
set:作為該屬性的setter函式,如果沒有setter結果為undefined,函式返回值將被作為屬性的值
var stus = {
scores:[
{
name:'張三1',score:65,
},
{
name:'張三2',score:65,
},
{
name:'張三3',score:65,
},
{
name:'張三4',score:65,
},
{
name:'張三5',score:65,
}
]
}
Object.defineProperties(stus,{
total:{
get:function(){
// 宣告一個變數
var t = 0;
for(var i = 0; i<this.scores.length;i++){
t += this.scores[i].score;
}
return t;
},
enumerable:true, // 可以遍歷
}
})
console.log(stus.total);
三, es6簡介
1, let基本用法
es6新增了let命令,用來宣告變數,他的用法類似var,但是宣告的變數,只在let命令坐在的程式碼塊內生效
{
let a = 10;
var b = 20;
}
console.log(a); // is not defined
console.log(b);
// let宣告的變數只能在宣告的當前的作用域內被訪問
for迴圈特別適合使用let
for (let i = 0; i < 5; i++) {
console.log(i);
}
console.log(i); // is not defined
2, 使用let不存在變數提升
var a = undefined
console.log(a); // undefined
var a = 10;
console.log(b);
let b = 20; // 'b' before initialization
3, 暫時性死區
只要塊級作用域記憶體在let命令,它宣告的變數就繫結這個區域,在在受外部影響
var temp = 123; // 全域性變數
if (true) {
temp = '123';
let temp; //'temp' before initialization
}
4, 比較隱祕的死區域
// 比較隱祕的死區域
function fn(x = y, y = 2) {
return [x, y]; // 'y' before initialization
}
fn();
// 正常
function fn(x = 2,y = x){
return [x, y];
}
fn();
5, 不允許重複宣告
let b = 10;
let b = 30;
console.log(b); // 報錯 不會覆蓋
// 引數和變數重名
function fn(a){// a = 1;
let a;
}
fn(1);
四, 塊級作用域
1, 為什麼需要塊級作用域
第一種場景
var tmp = new Date();
function f(){
console.log(tmp); // 變數提升
if(false){
var tmp = 'hello world';
}
}
f();
第二種場景,用來計數的迴圈變數洩露為全域性變數
var s = 'hello';
for (var i = 0; i < 5; i++) {
console.log(i);
}
console.log(i); // 5 資料洩露
es6裡面允許作用域的任意層巢狀
{{
{{{{
let a = 10
}}}}
}}
es6裡面在內層塊級作用域可以宣告和外層的塊級作用域同名的變數
{
{
let a = 10;
{
let a = 20;
console.log(a);
}
console.log(a);
}
}
在es6裡面,塊級作用域內宣告的函式,建議或者說是最好使用字面量的方式宣告函式
if(true){
let a = function(){
}
}
if語句在嚴格模式下
"use strict"; // 全錯
if(true)
let a = 10;
if(true)
function fn(){}
2, const 基本用法
const宣告一個只讀的常量,一旦宣告,常量的值就不能在改變
不可變指的是指向值的地址不可變,而不是值不可變
for (const i = 0; i < 5; i++) {
console.log(i);
}
const obj = {
name: 'lisi',
age: 20
}
3, var let const 之間的區別
1、var有變數提升 let和const沒有變數提升
2、var沒有塊級作用域,let和const有塊級作用域
3、let和const指向的值和地址
let a = 10;
a = 20; //
console.log(a);
const b = 10;
b = 20;
console.log(b);
const實際上保證的,並不是邊量的值不得改動,而是變數的那個記憶體地址所儲存的資料不得改動。
但對於複雜資料型別來說,變數指向的記憶體地址,儲存的只是一個指向實際資料的指標,const只能保證這個指標是固定的(即總時指向另一個固定的地址)。
五, 解構賦值
es6允許按照一定的模式,將陣列或物件中的資料提取出來,賦值給變數,這個過程叫做解構賦值。
1, 陣列的解構賦值
let [a, b, c, d] = [1, 2, 3, 4]; //
console.log(a);
其他列子
let [a, b, c, d] = [1, 2, 3, 4]; //
console.log(a);
let [foo,[[bar],baz]] = [1,[[2],3]]
console.log(bar);
let [, , third] = ['foo','bar','baz'];
console.log(third);
let [head,...tail] = [1,2,3,4];
console.log(head); // 1
console.log(tail); // [2, 3, 4]
如果解構不成功,值為undefined
let [foo,foo1] = [,2];
console.log(foo); // undefined
另一種情況就是不完全解構,等號左邊的模式,只匹配第一部分等號右邊的陣列,這種情況,結構依然可以成功
let [x, y] = [1, 2, 3];
console.log(x, y);
let [a, [b], d] = [1, [2, 3], 4];
console.log(a, b, d);
解構的時候,等號右邊不是陣列,報錯
let [foo] = false;
對於set結構,也可以使用陣列解構賦值
let [x,y,z] = new Set(['a','b','c']);
console.log(typeof x);
陣列解構賦值允許指定預設值
let [foo = true] = [];
console.log(foo);
let [x,y='b'] = ['a'];
console.log(x,y);
es6內部使用嚴格相等運算子(===
)判斷一個位置是否有值,所以只有當一個數組成員嚴格等於undefined
,預設值才生效
let [x = 1] = [undefined];
console.log(x);
// 預設值是null會直接賦值
let [y = 2] = [null];
console.log(y);
2, 物件解構賦值
解構賦值不僅僅可以用於陣列,也可以用於物件
物件的解構賦值
let {foo,bar} = {foo:'a',bar:'b'};
console.log(foo);
物件的解構賦值和陣列的解構賦值不一樣,陣列的元素是依次排列的,變數的值有位置決定,而物件的屬性沒有次序,變數必須與屬性同名,才能取到值
let {baz} = {foo:'aaa',bar:'bbb'};
console.log(baz); //undefined
物件的結構賦值,可以很方便的將現有的物件的方法,賦值給某一個變數
const { log } = console;
log('hello'); //
如果變數名和屬性名不一致,必須這麼寫
// 如果變數名和屬性名不一致,必須這麼寫
let { foo: baz } = { foo: 'aaa', bar: 'bbb' };
// console.log(baz);
// 相等
let { foo: foo, bar: bar } = { foo: 'aaa', bar: 'bbb' }
console.log(bar);
與陣列一樣,物件解構也可以用於巢狀結構的物件
let obj = {
p: [
'hello',
{
y: 'world'
}
]
}
let { p: [x, { y }] } = obj;
console.log(x, y);
注意:這種情況下 p 是模式,不是變數,不會被賦值,如果 p 作為也要作為變數賦值
let obj = {
p: [
'hello',
{
y: 'world'
}
]
}
let {p, p: [x, { y }] } = obj;
console.log(x, y);
console.log(p);
物件也可以指定預設值
const { x = 3} = {};
console.log(x);
let {x,y=5} = {x:1};
console.log(x,y);
es6內部使用嚴格相等運算子(===
)判斷一個位置是否有值,所以只有當一個物件成員嚴格等於undefined
,預設值才生效
var {x = 3} = {undefined};
console.log(x);
var {x = 3} = {x:null};
console.log(x);
如果將一個已經宣告的變數用於解構賦值,使用的時候,必須得非常小心
let x;
{x} = {x : 1};
console.log(x);
// 正確方法
let x;
({x} = {x : 1});
console.log(x);
3, 函式引數的解構賦值
函式的引數也可以解構賦值
function add([x, y]) {
return x + y;
}
console.log(add([1, 2]));
[[1, 2], [3, 4]].map(([a, b]) => console.log(a + b));
引數也可以使用預設值
function add({ x = 0, y = 0 } = {}) {
return [x, y];
}
console.log(add());
console.log(add({ x: 3, y: 8 }));
// 另一種寫法
function move({ x, y } = { x: 0, y: 0 }) {
return [x, y];
}
console.log(move({ x: 3, y: 9 }));
模板字串
for (var attr = 0; attr < json.length; attr++) {
var cur = json[attr]
ul.innerHTML = `<li>
<a href="${cur.url}">${cur.title}</a>
</li>`;
}
六, 物件的擴充套件
es6允許在大括號裡面,直接寫入變數和函式,作為物件的屬性和方法,這麼寫更簡潔
const foo = 'bar';
const baz = {foo};
console.log(baz);
// 等同於
const baz = {foo:foo}
另外一種寫法
function f(x, y) {
return { x, y }
}
// 等同於
function f(x, y) {
return { x: x, y: y }
}
console.log(f(1,2)); // {x: 1, y: 2}
屬性名錶達式
Javascript定義物件的屬性,有兩種方法
// 方法一
obj.foo = true;
// 方法二
obj['a' + 'bc'] = 123;
es6裡面允許屬性名以表示式的形式存在,但是必須使用方括號[]
let propKey = 'foo';
let obj = {
[propKey]:true,
['h' + 'ello']:123
}
console.log(obj.hello);
另一種方式
let lastWorld = 'last world';
const a = {
'first world':'hello',
[lastWorld]:'world'
}
console.log(a['first world']);
console.log(a[lastWorld]);
表示式定義方法名
let obj = {
['h'+'ello'](){
return 'h';
}
}
console.log( obj.hello());
注意:屬性名錶達式和簡潔寫法,不能同時使用,會報錯
// 報錯
const foo = 'bar';
const bar = 'abc';
const baz = { [foo] };
// 正確
const foo = 'bar';
const baz = { [foo]: 'abc' }
console.log(baz); // {baz:'abc'}
屬性名錶達式是一個物件,預設情況下回將物件轉為字串[object],這個要小心
const keyA = { a: 1 };
const keyB = { b: 2 };
const myObject = {
keyA:'valueA',
keyB:'valueB'
}
console.log(myObject);
七, 函式擴充套件
es6新增了一種新的函式:ArrayFunction(箭頭函式)
es6允許使用“箭頭(=>)”定義函式
var f = v => v; // f:函式名 v:引數(形參)
// 等同於
var f = function(v){
return v;
}
如果箭頭函式不需要引數或者需要多個引數,就使用()
代表引數部分
// 沒有引數
var f = () => {return 5};
console.log(f());
// 定義引數
var sum = (num1, num2) => num1 + num2;
sum(10, 20); // 30
當代碼有兩條語句或者多餘兩條語句的時候,程式碼塊要放在{}
var sum = (num1, num2) =>{return num1 + num2};
sum(10, 20); // 30
由於大括號{}
之間的程式碼,會被解釋為程式碼塊,所以,如果箭頭函式直接返回一個物件,必須在物件的外面加上括號,否則會報錯
// 報錯
let getTemp = (id) => {
id: id,
name: 'Temp',
};
// 正確
let getTemp = (id) => ({
id: id,
name: 'Temp',
});
console.log(getTemp('box'));
// 值是undefined
let foo = () => {a:1};
console.log(foo()); //undefined