Js进阶25-ES6 新增1

1. let 和 const

let 和 const 是 ES6 新增的2个声明符,let 用于声明变量,const 用于声明常量。

{
  var a = 10;
  let b = 20;
  const c = 30;//常量:不能被修改的量
  c = 40;    
  //Uncaught TypeError:Assignment to constant variable.(未捕获的类型错误:赋值给常量变量)
}
console.log(a); // 10
console.log(b); // b is not defined
console.log(b = c); // c is not defined

在一个大括号中用 let 和 const 声明的变量在外部不可访问了,每个大括号都是独立的作用域。

用 var 声明一个变量是存在变量提升的,这是JS中的一个缺陷所在, 但是现在的 let 不存在变量提升。

ES6 规定在某个区块中, 一旦用 let 或 const 声明一个变量,那么这个区块就变成块级作用域,用 let 或者 const 声明的变量即为该区块绑定, 该变量不受任何变量影响。 在该变量使用 let 声明前不可以用。在语法上,我们叫这种情况为:暂时性死区 (temporal dead zone,简称 TDZ)。

使用 const 声明的变量为常量,常量不可以被修改。

console.log(Math.PI); // 3.141592653589793
Math.PI = 4;
console.log(Math.PI); // 3.141592653589793
const arr = [2,3,4,5];
// arr = [3,4,4,6];
// 不能修改数组或对象的引用,但是可以通过 API 去修改内部结构
arr.push(6,7);
console.log(arr); // [2, 3, 4, 5, 6, 7]

2. 扩展运算符

扩展运算符(spread)为三个点号(…),功能是把数组或类数组对象展开成一系列用逗号隔开的值。

var arr = [1,2,3,4,5];
console.log(arr); // Array(5)
console.log(...arr); // 1 2 3 4 5 // console.log 不会显示逗号,中间其实是有逗号的
var foo = function(a, b, c) {
  console.log(a); // 1
  console.log(b); // 2
  console.log(c); // 3
}
var arr = [1, 2, 3];
// 传统写法
foo(arr[0], arr[1], arr[2]);
// 使用扩展运算符
foo(...arr);

3. 剩余运算符

剩余运算符(rest)也是三个点号(…),不过其功能与扩展运算符恰好相反,把逗号隔开的值序列组合成一个数组。

// 主要用于不定参数,所以 ES6 开始可以不再使用 arguments 对象
var bar = function(a, ...args) {
  console.log(a); // 1
  console.log(args); // [ 2, 3, 4 ]
}
bar(1, 2, 3, 4);

4. 字符串扩展

字符串的 Unicode 表示,规则为\u + 四位十六进制。

console.log("\u0061"); // a 

这种新的字符表示方式只能表示 \u0000 ~ \uffff 之间的字符,如果超出范围必须用双字节表示。

console.log("\uD842\uDFB6"); // 

如果不按照规则书写,例如 console.log("\uD842\uDFB69"),这个9是多余字符,那么则认为这段字符是 \uD842\uDFB6 + 9 所以打印结果是 ₻9。

如果想要一次性表示超出范围的字符那么我们可以使用 {} 来表示。

console.log("\u20BB9"); // ₻9
console.log("\u{20BB9}"); // 

5. 字符串模板扩展

ES6 中存在一种新的字符串, 这种字符串是以 反引号(波浪线上的那个字符 ` )括起来表示的。

通常拼接一个带有标签的字符串, 是用这样的方式:

variate + " 这是一个文字" + obj.name + " " + variate 

但是有了 ES6 模板字符串一切都变得非常简单了,用 ${变量名} 括住变量让拼接变得非常容易:

`${variate} 这是一个文字${obj.name}${variate} `

在字符串中使用反引号的时候我们需要进行转义:

console.log(`\`Yo\` World!`); // `Yo` World!

模板还可以调用函数:

function fn() {
  return "Hello World";
}
console.log(`foo ${fn()} bar`); // foo Hello World bar

6. for of

一种新的遍历方式,遍历数组的所有元素。

tip:可以用于遍历字符串:

var s = "abc";
for(let b of s) {
  console.log(b); // "a"  "b"  "c"
}

for of 不能用于遍历对象。

7. 箭头函数

一个常规函数如下:

const test = function (x) {
  return x + 2;
}

使用箭头函数:

const test = (x) => {
  return x + 2;
};

const 函数名 = (参数列表) => { 函数体 }。

如果箭头函数只有一个形参,那么可以省略小括号。

const test = x => {
  return x + 2;
};

如果函数体只有一条语句,那么可以省略大括号:

const foo = str => console.log(str);

如果只有一条语句,并且这条语句就是return语句,可以省略 return 关键字:

 

const test = x => x + 2;

箭头函数会自动绑定 this(箭头函数没有自己的this)。

缺陷:

(1) 箭头函数是不能 new 的,它的设计初衷就跟构造函数不太一样;

(2) 箭头函数如果要返回一个 JSON 对象,必须用小括号包起来。如 var test = () => ({ id: 3, val: 20 })。

document.querySelector("button").onclick = function () {
  setTimeout(() => {
    console.log(this); // 
  },1000);
};

箭头函数和普通函数的区别:

(1) 写法不一样,箭头函数更简洁;

(2) 普通函数存在变量提升;

f(); // hello
function f(){
  console.log("hello");
}

g(); //报错:Uncaught ReferenceError: g is not defined
const g = () => console.log("hello");

(3) this指向不同,箭头函数没有自己的 this,指向外层作用域的 this;

(4) 箭头函数没有自己的 arguments,箭头函数的 arguments 指向它的父级函数所在作用域的arguments;

(5) 箭头函数不能作为构造函数;

(6) 箭头函数没有new.target。

8. 解构赋值

// 对象解构
var obj = {name:"lisi", age:80, gender: "female"};
var {age, name, gender="male"} = obj;
console.log(age, name, gender); // 80 'lisi' 'female'
            
var json = [
  {name:"lisi", age:80, gender: "female"},
  {name:"liwu", age:70, gender: "male"},
  {name:"liliu", age:60, gender: "female"}
]
var [{age},{name},{gender}] = json;
// var {name} = b;
console.log(name, age, gender); // liwu 80 female


// 数组解构
let [a, b, c] = [1, 2, 3];
console.log(a); // 1
console.log(b); // 2
console.log(c); // 3

解构赋值就是把数据结构分解,然后给变量进行赋值。

如果解构不成功,变量跟数值个数不匹配的时候,变量的值为 undefined。

数组解构用中括号([])包裹,多个变量用逗号隔开,对象解构用花括号({})包裹,多个变量用逗号隔开。

 

利用解构赋值能够方便的去取数组的元素,对象的属性和方法。

9. symbol 类型

symbol 类型是第6种基本数据类型。

Symbol 函数会生成一个唯一的值。可以理解为 symbol 类型跟字符串是接近的。但每次生成唯一的值,也就是每次都不相等,至于它等于多少,并不重要。这对于一些字典变量比较有用。 

var s1 = Symbol();
var s2 = Symbol();
var s3 = Symbol("abc");
var s4 = Symbol("abc");
//s1不等于s2
//s3不等于s4

在通过 Symbol 生成独一无二的值时可以设置一个标记,这个标记仅仅用于区分, 没有其它任何含义。

注意点:

(1) symbol 是基本数据类型!!!!不要加 new 哦;

(2) 后面括号可以传入一个字符串,只是一个标记,方便我们阅读,没有任何意义;

(3) 类型转化的时候不可转化为数值;

// 只能转化为字符串和布尔值
const name = Symbol('name');
console.log(String(name)); // Symbol(name)
console.log(Boolean(name)); // true
console.log(Number(name)); // 报错:Cannot convert a Symbol value to a number


(4) 不能做任何运算;

(5) Symbol 生成的值作为属性或者方法的时候,一定要保存下来,否则后续无法使用;

let name=Symbol('name');
let obj={
  // name:'lnj',
  [Symbol('name')]:'lbj'
};
console.log(obj.name);  // 访问不到,因为 [Symbol('name')] 又是一个新的值,和上面的 name 不是同一个

(6) for循环遍历对象的时候是无法遍历出 symbol 的属性和方法的,需要使用

Object.getOwnPropertySymbols。
let name=Symbol('name');
let obj={
  [name]:'lnj',
    age:12,
    teacher:'wyx'
};
for (let key in obj) {
    console.log(key);   //只能打印出 age 和 teacher
}
//这个方法可以单独取出Symbol(name)
console.log(Object.getOwnPropertySymbols(obj));

Symbol的使用场景:

(1) 作为对象的属性名

对象的属性默认是字符串,所以不加引号(‘’,"")也可以,如果需要类型为 symbol,需要使用中括号([])括起来。

不可以用点(.)来访问,因为点运算符后面总是字符串。

Symbol 值作为属性名时,该属性还是公开属性,不是私有属性。

// 后面的括号可以给 symbol 做上标记便于识别
let name = Symbol('name');
let say = Symbol('say');
let obj = {
  // 如果想使用变量作为对象属性的名称,必须加上中括号,.运算符后面跟着的都是字符串
  [name]: 'lnj',
  [say]: function () {
    console.log('say');
  }
};
obj.name = 'it666';
obj[Symbol('name')] = 'it666';
console.log(obj);

(2) 消除魔术字符串

魔术字符串:在代码之中多次出现、与代码形成强耦合的某一个具体的字符串或者数值。风格良好的代码,应该尽量消除魔术字符串,改由含义清晰的变量代替。

const gender = {
  //这样就说明man就是一个独一无二的值,不用再 man:'man'   
  man: Symbol(),
  woman: Symbol(),
};
function isMan(gender) {
  switch (gender) {
    case gender.man:
      console.log('男性');
      break;
    case gender.woman:
      console.log('女性');
      break;
    }
}
isMan(gender.man);  //男性

(3) 为对象定义一些非私有的但又希望只用于内部的方法

由于以 Symbol 值作为键名,不会被常规方法遍历得到。我们可以利用这个特性,为对象定义一些非私有的、但又希望只用于内部的方法。

注意:symbol 并不能实现真正的私有变量的效果,只是不能通过常规的遍历方法拿到 symbol 类型的属性而已。

对象的遍历方法:

(1) for (let xx in obj): xx 代表 key;

(2) for (let xx of obj):xx 代表 value;

(3) Object.keys(obj): 返回包含 key 的数组;

(4) Object.values(obj): 返回包含 value 的数组;

(5) Object.getOwnPropertyNames():返回包含 key 的数组。

上述的所有方法都是遍历不到 symbol 类型的(注意,是遍历时取不到 symbol,并不是说我们访问不到对象的 symbol 类型)。

可以遍历到 symbol 的方法:

(1) Object.getOwnPropertySymbols:返回对象中只包含 symbol 类型 key 的数组;

(2) Reflect.ownKeys:返回对象中所有类型 key 的数组(包含 symbol)。

Symbol 自带的方法:

(1) Symbol.for(str)

因为 symbol 类型的值都是独一无二的,但有时,我们希望重新使用同一个 Symbol 值,Symbol.for 方法可以做到这一点。它接受一个字符串作为参数,然后搜索有没有以该参数作为名称的 Symbol 值。如果有,就返回这个 Symbol 值,否则就新建一个以该字符串为名称的 Symbol 值,并将其注册到全局。

let s1 = Symbol.for('foo');
let s2 = Symbol.for('foo');s1 === s2 // true

(2) Symbol.keyFor()

由于 Symbol 写法没有登记机制,所以每次调用都会返回一个不同的值。

Symbol.keyFor 方法返回一个已登记的 symbol 类型值的 key。

let s1 = Symbol.for("foo");
Symbol.keyFor(s1) // "foo"

let s2 = Symbol("foo");
Symbol.keyFor(s2) // undefined

你可能感兴趣的:(Js进阶,javascript,前端,es6)