文章目录

  • ES6
    • `let`
    • `const`
    • 异常处理,"try..catch"
      • 语法
      • Error 对象
      • “Throw” 运算符
      • 全局 catch
    • 模板字符串
    • 扩展运算符
    • 解构赋值
    • 函数默认值
    • 箭头函数
      • 写法
      • 特点
    • 数组新增的方法
      • 数组实例ES5的方法补充
        • Array.isArray(值)
        • forEach
        • map
        • filter
        • every
        • some
        • reduce
      • 数组ES6新增方法
        • Array.from
        • Array.of()
      • 数组实例新增的方法
        • fill
        • includes
        • flat
        • find/findIndex
    • Symbol
      • 创建
      • 标识
      • Symbol.for()
      • Symbol.keyFor()
      • Symbol 不能与其它数据进行运算
      • Symbol 作为对象属性存在
      • 遍历对象中的 Symbol 属性
      • ES6 新增 Symbol 内置方法
    • 练习

ES6

ECMAScript 2015 块级作用域

let

let 使用方式与 var 一样,作用声明块级作用域的变量

let a;
let b,c,d;
let e = 10;
let f = 20, g = "hello";

特点:

  1. 不能重复声明同一变量

    let a = 10;
    let a = "hello"; // Error: Identifier 'user1' has already been declared
    
  2. 不存在变量提升

    console.log(user); // Error: user is not defined
    let user = "李白";
    
  3. 属于块级作用域

    {var study = "学习";let subject = "前端";
    }
    console.log(study); // 学习
    console.log(subject); // Error: subject is not defined
    

    在 for 循环语句中,使用 var 声明的变量不是该循环的局部变量,而是与 for 循环处在同样的作用域中。用 let 声明的变量是语句的局部变量。

  4. 暂时性死区

    ES6 明确规定,如果区块中存在 letconst 命令,这个区块对这些命令声明的变量,从一开始就形成了封闭作用域。凡是在声明之前就使用这些变量,就会报错。这在语法上,称为“暂时性死区”(temporal dead zone,简称 TDZ)。

    var num = 10;
    if(true){console.log(num); // ReferenceErrorlet num = 10;
    }
    

const

使用方式与 var,一样,用来声明一个只读的常量。与 let 类似,只在声明所在的块级作用域内有效。一般常量的声明时使用大写

特点:

  1. 只声明,不赋值,会报错

    const Foo;
    // SyntaxError: Missing initializer in const declaration
    
  2. 变量指向的那个内存地址所保存的数据不得改动。对于复合类型的数据(主要是对象和数组),变量指向的内存地址,保存的只是一个指向实际数据的指针,因此声明需要小心。

    const Foo = {};
    Foo.name = "foo";const A = 10;
    A = 20; // TypeError: Assignment to constant variable.
    

注意:函数的参数变量是默认声明的,所以不能用letconst再次声明。

function foo(x = 5, y = 10) {let x = 1; // errorconst y = 2; // error
}

异常处理,“try…catch”

不管你多么的精通编程,有时我们的脚本总还是会有一些错误。可能是因为我们的编写出错,或是与预期不同的用户输入,或是错误的的服务端返回或者是其他种种不同的原因。

通常,一段代码会在出错的时候“死掉”(停止执行)并在控制台将异常打印出来。

但是有一种更为合理的语法结构 try..catch,它会在捕捉到异常的同时不会使得代码停止执行而是可以做一些更为合理的操作。

语法

try {// 执行此处代码
} catch(err) {// 如果发生异常,跳到这里// err 是一个异常对象
} finally {// 不管 try/catch 怎样都会执行
}

它按照以下步骤执行:

  1. 首先,执行 try {...} 里面的代码。
  2. 如果执行过程中没有异常,那么忽略 catch(err) 里面的代码,try 里面的代码执行完之后跳出该代码块。
  3. 如果执行过程中发生异常,控制流就到了 catch(err) 的开头。变量 err(可以取其他任何的名称)是一个包含了异常信息的对象。

可能会没有 catch 代码块,或者没有 finally 代码块。所以 try..catch 或者 try..finally 都是可用的。

执行下面这段代码:

try {alert( 'try' );if (confirm('Make an error?')) BAD_CODE();
} catch (e) {alert( 'catch' );
} finally {alert( 'finally' );
}

这段代码有两种执行方式:

  1. 如果对于 “Make an error?” 你的回答是 “Yes”,那么执行 try -> catch -> finally
  2. 如果你的回答是 “No”,那么执行 try -> finally

finally 语法支持任何的结束 try..catch 执行的方式,包括明确的 return

下面就是 try 代码块包含 return 的例子。在代码执行的控制权转移到外部代码之前,finally 代码块会被执行。

function func() {try {return 1;} catch (e) {/* ... */} finally {alert( 'finally' );}
}alert( func() ); // 先 alert "finally" 里面的内容,再执行这里

finally 的语法通常用在:我们在 try..catch 之前开始一个操作,不管在该代码块中执行的结果怎样,我们都想结束的时候执行某个操作。

例子:

  • 没有异常的例子:显示下面(1)和(2)中 alert 的内容:

    try {alert('Start of try runs');  // (1) <--// ...这里没有异常alert('End of try runs');   // (2) <--} catch(err) {alert('Catch is ignored, because there are no errors'); // (3)}alert("...Then the execution continues");
    
  • 包含异常的例子:显示下面(1)和(3)中 alert 的内容:

    try {alert('Start of try runs');  // (1) <--lalala; // 异常,变量未定义!alert('End of try (never reached)');  // (2)} catch(err) {alert(`Error has occured!`); // (3) <--}alert("...Then the execution continues");
    

注意:JavaScript 引擎读取然后执行代码。发生在读取代码阶段的异常被称为 “parse-time” 异常,它们不会被 try..catch 覆盖到(包括那之间的代码)。

这是因为引擎读不懂这段代码。所以,try..catch 只能处理有效代码之中的异常。这类异常被称为 “runtime errors”,有时候也称为 “exceptions”。

Error 对象

当一个异常发生之后,JavaScript 生成一个包含异常细节的对象。这个对象会作为一个参数传递给 catch

try {// ...
} catch(err) { // <-- “异常对象”,可以用其他参数名代替 err// ...
}

对于所有内置的异常,catch 代码块捕捉到的相应的异常的对象都有两个属性:

  • name

    异常名称,对于一个未定义的变量,名称是 "ReferenceError"

  • message

    异常详情的文字描述。

还有很多非标准的属性在绝大多数环境中可用。其中使用最广泛并且被广泛支持的是:

  • stack

    当前的调用栈:用于调试的,一个包含引发异常的嵌套调用序列的字符串。

例如:

try {lalala; // 异常,变量未定义!
} catch(err) {alert(err.name); // ReferenceErroralert(err.message); // lalala 未定义alert(err.stack); // ReferenceError: lalala 在... 中未定义// 可以完整的显示一个异常// 可以转化成 "name: message" 形式的字符串alert(err); // ReferenceError: lalala 未定义
}

“Throw” 运算符

throw 运算符生成异常对象。

语法如下:

throw <error object>

技术上讲,我们可以使用任何东西来作为一个异常对象。甚至可以是基础类型,比如数字或者字符串。但是更好的方式是用对象,尤其是有 namemessage 属性的对象(某种程度上和内置的异常有可比性)。

JavaScript 有很多标准异常的内置的构造器:ErrorSyntaxErrorReferenceErrorTypeError 和其他的。我们也可以用他们来创建异常对象,对于我们创建的异常,被catch捕获后name属性就是构造器的名字,message就是我们定义的参数。

他们的语法是:

let error = new Error(message);
// 或者
let error = new SyntaxError(message);
let error = new ReferenceError(message);
// ...

对于内置的异常对象(不是对于其他的对象,而是对于异常对象),name 属性刚好是构造器的名字。message 则来自于参数。

自定义一个异常:

throw new Error("这是自定的一个异常")

全局 catch

设想一下,try..catch 之外出现了一个严重的异常,代码停止执行,可能是因为编程异常或者其他更严重的异常。

那么,有没办法来应对这种情况呢?我们希望记录这个异常,给用户一些提示信息(通常,用户是看不到提示信息的),或者做一些其他操作。

虽然没有这方面的规范,但是代码的执行环境一般会提供这种机制,因为这真的很有用。例如,Node.JS 有 process.on(‘uncaughtException’) 。对于浏览器环境,我们可以绑定一个函数到 window.onerror,当遇到未知异常的时候,它就会执行。

语法如下:

window.onerror = function(message, url, line, col, error) {// ...
};
  • message

    异常信息。

  • url

    发生异常的代码的 URL。

  • line, col

    错误发生的代码的行号和列号。

  • error

    异常对象。

例如:

window.onerror = function(message, url, line, col, error) {alert(`${message}\n At ${line}:${col} of ${url}`);
};function readData() {badFunc(); // 哦,出问题了!
}readData();

window.onerror 的目的不是去处理整个代码的执行中的所有异常 —— 这几乎是不可能的,这只是为了给开发者提供异常信息。

模板字符串

模板字符串(template string)是增强版的字符串,用反引号(`)标识。它可以当作普通字符串使用,也可以用来定义多行字符串,或者在字符串中嵌入变量。

// 普通字符串
let str = `In JavaScript '\n' is a line-feed.`// 多行字符串
let strr = `In JavaScript this isnot legal.`console.log(`string text line 1
string text line 2`);// 字符串中嵌入变量
let name = "Bob", time = "today";
let text = `Hello ${name}, how are you ${time}?`// 字符串中嵌入表达式或者函数
let x = 1;
let y = 2;console.log(`${x} + ${y} = ${x + y}`); // "1 + 2 = 3"console.log(`${x} + ${y * 2} = ${x + y * 2}`); // "1 + 4 = 5"let obj = {x: 1, y: 2};
console.log(`${obj.x + obj.y}`) // "3"function fn() {return "Hello World";
}console.log(`foo ${fn()} bar`) // foo Hello World bar

扩展运算符

扩展运算符(spread)是三个点(...)。它将一个数组转为用逗号分隔的参数序列。

console.log(...[1, 2, 3]) // 1 2 3
  1. 可以将伪数组转成数组

    let dArr = [...document.querySelectorAll('div')];
    console.log(dArr); // [<div>, <div>, <div>]
  2. 克隆、合并数组

    let arr = [1, 2, 3];
    let brr = [...arr];
    let crr = [...arr, ...brr];
    console.log(crr); // [1,2,3,1,2,3]
  3. 代替 apply

    console.log(Math.max.apply(null, [1,34,56,23,67]));
    console.log(Math.max(...[1,34,56,23,67]));
  4. 分解字符串

    var str = "hello world";
    console.log(...str); // h e l l o   w o r l d
    // 将字符串改成数组
    let arr = [...str];
    console.log(arr); // ["h","e","l","l","o"," ","w","o","r","l","d"]

解构赋值

ES6 允许按照一定规则,从数组和对象中提取值,对变量进行赋值,这被称为解构。本质上,这种写法属于“模式匹配”,只要等号两边的模式相同,左边的变量就会被赋予对应的值。如果解构失败,变量的值等于 undefined

  1. 对象解构

    // 全值解构:使用对象中的key名获取对象中对应的值
    let user = {name: "李白",age: 23,hobby(){return "吟诗";}
    }
    let { name, age, hobby, tel } = user;
    console.log(name, age, hobby); // 李白 23 function...// 不全等解构
    let { name, tel, ...others } = user;
    console.log(name, tel, others); // 李白 undefined { age: 23, hobby: func..}// 更改属性名的解构,使用冒号指定新的变量名来接收值
    let { name: n, age: a } = user;
    console.log(n, a); // 李白 23
  2. 数组解构

    // 全等解构
    let f4 = ["小沈阳", "刘能", "赵四", "宋小宝"];
    let [x, l, z, s] = f4;
    console.log(x, l, z, s); // "小沈阳", "刘能", "赵四", "宋小宝"// 不全等解构
    let [a, b] = [1, 2, 3];
    console.log(a, b); // 1, 2
    let [c, ...d] = [1, 2, 3, 4, 5, 6];
    console.log(c, d); // 1  [2, 3, 4, 5, 6]// 对象数组解构
    let heros = [{ name: "亚索", skill: ["斩钢闪", "狂风绝息斩"]}, 2, 3];
    let [f, g] = heros;
    let [{ name }] = heros;
    console.log(f, g); // { ... } 2
    console.log(name); // 亚索
    
  3. 解构赋值允许使用默认值,当解构成员的值 === undefined 时,默认值生效

    let [foo = true] = [];
    let [x = 1] = [undefined];
    let [y = 1] = [null];
    // 如果默认值是一个函数的返回值,那么只有当默认值生效时函数才执行
    function f(){return 2;
    }
    let [rf = f()] = [1]; // f函数不会执行
    console.log(foo, x, y, rf); // true 1 null 1
    
  4. 嵌套解构

    let obj = {size: {width: 100,height: 200},items: ["Cake", "Donut"],extra: true
    };
    // 为了清晰起见,解构赋值语句被写成多行的形式
    let {size: { // 把 size 赋值到这里width,height},items: [item1, item2], // 把 items 赋值到这里title = "Menu" // 在对象中不存在(使用默认值)
    } = options;
    alert(title);  // Menu
    alert(width);  // 100
    alert(height); // 200
    alert(item1);  // Cake
    alert(item2);  // Donut

函数默认值

ES6 允许为函数的参数设置默认值,即直接写在参数定义的后面。

// 简单类型赋值
function log(x, y = 'World') {console.log(x, y);
}log('Hello') // Hello World
log('Hello', 'China') // Hello China
log('Hello', '') // Hello// 引用类型赋值
function sayName(obj = { name: "not have" }){console.log(obj.name);
}

如果默认参是写在语句中间的,那么我们需要传入 undefined 来使其生效

function fn(a, b = 1, c){console.log(b);
}
fn(1,2); // 2
fn(1,undefined,2); // 1

与解构赋值结合:

// 普通写法
function fn(user){console.log(user.name, user.age);
}
// 解构写法
function gn({ name, age }){console.log(name, age);
}
// 当参数为空时,给对象内容赋默认值
function kn({ name = "对象属性默认参", age }){console.log(name, age);
}
// 当参数为空对象是,给对象的属性赋默认值
function hn({ name = "对象属性默认参", age } = {}){console.log(name, age);
}

箭头函数

写法

一、一般写法

// 普通函数
function fn (){// do something...
}
function fn (a,b,c){// do something...
}
// 箭头函数的写法
var fn = () => {// do something
}
var fn = (a,b,c) => {// do something
}

二、一个参数的箭头函数

// 普通函数
function fn (a){// do something...
}
// 箭头函数的写法
var fn = a => {// do something
}

三、函数体只执行一条语句

// 普通函数
function fn (a){console.log(a);
}
// 箭头函数的写法
var fn = a => console.log(a+1);
var fn = a => a + 1; // 表示函数返回值为: a+1

特点

一、函数内部不能使用 arguments

let func = () => {console.log(arguments);
}
func(1, 2, 3, 4); // ReferenceError: arguments is not defined

二、立即执行函数写法

var fn = (() => {console.log("only thisway");
})()

三、立即执行函数不能使用 new 操作符

let Fn = () => {}
let f = new Fn(); // TypeError: Fn is not a constructor

四、不会改变 this 指向

一般函数中的 this 都指代当前执行环境的拥有者,箭头函数中的 this 指向父级环境的拥有者。例如:

let obj = {name: "obj",sayTimeOut(){setTimeout(() => console.log(this.name), 2000);}
}
var name = "window";
let sayName = () => console.log(this.name);
sayName(); // window
sayName.call(obj); // window
obj.sayTimeOut(); // objvar obj = {sing(){function fn(){console.log(this);}var gn = () => {console.log(this);}fn(); // windowgn(); // obj}
}
obj.sing();

数组新增的方法

数组实例ES5的方法补充

Array.isArray(值)

该方法可以判断某个值是否为数组,返回布尔值。

forEach

语法:[ ... ].forEach(function(item,index,array){}),该方法遍历数组,用于替代 for 语句,但是不能使用break打断循环,没有返回值。

[1,2,3,4].forEach(item, index, array){// item 代表数组中的每一项// index 代表该项对应的下标// array 代表原数组console.log(item, index, array);
}

注意:该方法接受的函数中的item参数是对原数组的每一项的浅克隆,所以简单类型值的更改不会影响原数组,但是引用类型值的更改会反映在原数组上。

map

语法:[ ... ].map(fn),接受的函数与 forEach 一样,不同的是该方法返回一个新数组,新数组的项是参数函数的返回值。

var arr = [1,2,3,4];
var arr1 = arr.map(item => item + 2);
console.log(arr); // [1,2,3,4]
console.log(arr1); // [3,4,5,6];

filter

语法:[ ... ].filter(fn),该方法返回一个数组,数组中的项是参数函数的返回值为 true 的项。一般用于数组筛选值。

var arr = [1,2,3,4,5];
var arr1 = arr.filter(item => item > 3);
var arr2 = arr.filter(item => item < 0);
console.log(arr1); // [4,5]
console.log(arr2); // []

every

语法:[ ... ].every(fn),该方法用于测试数组中的项是否都符合某个条件,当参数函数的返回值全为 true 时,该方法返回 true

var arr = [1,2,3,4,5];
var wrong = arr.every(item => item > 3);
var right = arr.every(item => item > 0);
console.log(wrong); // false
console.log(right); // true

some

语法:[ ... ].some(fn),该方法用于测试数组中的项是否有符合某个条件,当参数函数的返回值有一个为 true 时,该方法返回 true

var arr = [1,2,3,4,5];
var yes = arr.some(item => item > 3);
var no = arr.some(item => item < 0);
console.log(yes); // true
console.log(no); // false

reduce

语法:[ ... ].reduce(function(prev, curr, index, array){},[start]),该方法用于归并数组项。

函数参数:前一个值、当前值、curr项的索引和数组对象。这个函数返回的任何值都会作为第一个参数自动传给下一项。
prev 第一个值是start或者数组的索引0的元素,curr第一个值对应索引0的元素或者索引1的元素。

[1,2,3,4].reduce((prev,curr,index,array) => {console.log(prev, curr, index, array);// 1 2 1 [1, 2, 3, 4]// undefined 3 2 [1, 2, 3, 4]// undefined 4 3 [1, 2, 3, 4]
})
[1,2,3,4].reduce((prev,curr,index,array) => {console.log(prev, curr, index, array);// 8 1 0 [1, 2, 3, 4]// undefined 2 1 [1, 2, 3, 4]// undefined 3 2 [1, 2, 3, 4]// undefined 4 3 [1, 2, 3, 4]
}, 8)
[1,2,3,4].reduce((prev,curr,index,array) => {console.log(prev, curr, index, array);return 10;// 8 1 0 [1, 2, 3, 4]// 10 2 1 [1, 2, 3, 4]// 10 3 2 [1, 2, 3, 4]// 10 4 3 [1, 2, 3, 4]
}, 8)

还有一个 array.reduceRight() 方法,效果与此方法类似,但循环的方向是从数组的末尾开始的。

数组ES6新增方法

Array.from

此方法用于将 类数组对象 转为真正的数组

<ul><li>1</li><li>2</li><li>3</li><li>4</li>
</ul>
let lis = document.querySelectorAll(li);
console.log(lis);
lis = Array.from(lis);
console.log(lis);function fn(){console.log(arguments);console.log(Array.from(arguments));
}
fn(1,2,3,4);let arr = Array.from({ length: 2 });
console.log(arr); // [undefined, undefined]

也可以用来 克隆数组

var nums = [1,2,3,4];
var arr = Array.from(nums);
console.log(arr); // [1,2,3,4]
console.log("arr == nums", arr == nums); // false// 如果数组中有对象,那么克隆数组相同对象指向同一堆地址
var objLs = [{}];
var objArr = Array.from(objLs);
console.log("objArr[0] == objLs[0]", objArr[0] == objLs[0]); // true

此方法也可以接受第二个参数,作用类似于数组的map方法,用来对每个元素进行处理,将处理后的值放入返回的数组。

Array.from([1, 2, 3], (x) => x * x); // [1, 4, 9]// 获取页面所有li中的文本内容组成的数组
var lis = document.querySelectorAll("li");
var t1 = [].map.call(lis, item => item.innerText);
var t2 = Array.from(lis, item => item.innerText);
console.log(t1);
console.log(t2);

Array.of()

此方法用于将一组值转换为数组。

console.log(Array()); // []
console.log(Array(3)); // [,,,]
console.log(Array(3,4,5)); // [3,4,5]console.log(Array.of()); // []
console.log(Array.of(3)); // [3]
console.log(Array.of(3,4,5)); // [3,4,5]

数组实例新增的方法

fill

语法:[...].fill(填充的内容, [起始位置], [结束位置]),此方法使用给定的值,填充一个数组。起始位置与结束位置规定填充范围 [起始位置,结束位置)。

var arr = Array(5).fill(7);
console.log(arr); // [7,7,7,7,7]
var arr1 = [4,5,6,7].fill(9);
console.log(arr1); // [9,9,9,9]
var arr2 = [1,2,3,4,5].fill(6,2,4);
console.log(arr2); // [1,2,6,6,5];

需要注意的是如果填充的是一个引用类型值,那么填充的内容指向同一个堆地址

var arr = Array(3).fill({});
arr[0].name = "obj";
console.log(arr); // [{"name":"obj"},{"name":"obj"},{"name":"obj"}]

includes

语法:[ ... ].includes(item),查找某个项是否在数组中存在,返回布尔值。优于 indexOf 方法的地方在于使用简单,不会对 NaN 类型误判。

var arr = [1, 2, NaN];
console.log(arr.indexOf(NaN) !== -1); // false
console.log(arr.includes(NaN)); // true

flat

语法:[ ... ].flat([number]),此方法可将数组扁平化,将一个多维数组变成一维数组。参数可以指定扁平化的层数,默认为1。

console.log([1, 2, [3, [4, 5]]].flat()); // [1, 2, 3, [4, 5]]
console.log([1, 2, [3, [4, 5]]].flat(2)); // [1, 2, 3, 4, 5]

如果原数组有空位,flat() 方法会跳过空位。

console.log([1, 2, , 4, 5].flat()); // [1, 2, 4, 5]

find/findIndex

语法:array.find/findIndex(function(item,index,array)){ return 条件 }

它们的参数是一个回调函数,用于找到第一个符合条件的数组成员。如果没找到,前者返回 undefined,后者返回 -1。

var arr = [1,2,3,4,5];
var v = arr.find((item, index, array) => {console.log(item, index, array);return item > 2;
})
var undi = arr.find(item => item < 0);
console.log(v); // 3
console.log(undi); // undefined
var i = arr.findIndex(item => item > 3);
var no = arr.findIndex(item => item < 0);
console.log(i); // 3
console.log(no); // -1

Symbol

ES6 引入了一种新的原始数据类型 Symbol,表示独一无二的值。它是 JavaScript 语言的第七种数据类型,是一种类似于字符串的数据类型。

它主要用于防止对象中重复出现相同的属性名冲突的问题。比如,你使用了一个他人提供的对象,想为这个对象添加新的方法(mixin 模式),新方法的名字就有可能与现有方法产生冲突。

创建

Symbol 值通过 Symbol 函数生成,接受一个字符串作为参数,表示对 Symbol 实例的描述,主要是为了在控制台显示,或者转为字符串时,比较容易区分。

注意:Symbol 函数前不能使用 new 命令,否则会报错。这是因为生成的 Symbol 是一个原始类型的值,不是函数对象。

// 直接使用
let s = Symbol();
console.log(s, typeof s); // Symbol()  "symbol"

标识

Symbol函数接受一个可选参数,可以添加一段文本描述即将创建的Symbol,这段描述不可用于属性访问,但是建议每次创建Symbol时都添加一段描述,便于阅读代码和调试Symbol程序。

// 创建
let s = Symbol("foo");
console.log(s, typeof s); // Symbol(foo) "symbol"// 因为 Symbol 函数的参数只是表示对当前 Symbol 值的描述,所以相同参数的 Symbol 函数的返回值是不相等的。
let d = Symbol("foo");
console.log(d == s); // false

我们可以通过 symbol.description 获取对应的描述

var school = Symbol("不凡学院");
console.log(school.description); // 不凡学院

Symbol.for()

Symbol.for() 方法接受一个字符串作为参数,然后搜索有没有以该参数作为名称的 Symbol 值。如果有,就返回这个 Symbol 值,否则就新建一个以该字符串为名称的 Symbol 值,并将其注册到全局。我们可以依赖这个方法使用同一个 Symbol 值。

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

Symbol.keyFor()

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

let s1 = Symbol.for("foo");
console.log(Symbol.keyFor(s1)); // "foo"let s2 = Symbol("foo");
console.log(Symbol.keyFor(s2)); // undefined

Symbol 不能与其它数据进行运算

let s = Symbol("foo");
s + 100; // Error
s > 100; // Error
s + s; // Error

Symbol 作为对象属性存在

let obj = {};
let s = Symbol();
// 作为属性时,无法通过.来获取或者赋值
obj.s = "not symbol";
console.log(obj[s]); // undefined
console.log(obj['s']); // not symbol// 通过计算属性赋值
obj[s] = "computed";
console.log(obj[s]); // computed
console.log(obj['s']); // not symbol

遍历对象中的 Symbol 属性

作为对象的属性名存在时,该属性不会出现在 for...infor...of 循环中,也不会被Object.keys()Object.getOwnPropertyNames()JSON.stringify() 返回。

Object.getOwnPropertySymbols() 方法,可以获取指定对象的所有 Symbol 属性名。该方法返回一个数组,成员是当前对象的所有用作属性名的 Symbol 值。

const obj = {};
let a = Symbol('a');
let b = Symbol('b');obj[a] = 'Hello';
obj[b] = 'World';const objectSymbols = Object.getOwnPropertySymbols(obj);
console.log(objectSymbols); // [Symbol(a), Symbol(b)]

Reflect.ownKeys() 方法可以返回所有类型的键名,包括常规键名和 Symbol 键名。

let obj = {[Symbol('my_key')]: 1,enum: 2,nonEnum: 3
};console.log(Reflect.ownKeys(obj)); //  ["enum", "nonEnum", Symbol(my_key)]

ES6 新增 Symbol 内置方法

详见

除了定义自己使用的 Symbol 值以外,ES6 还提供了 11 个内置的 Symbol 值,指向语言内部使用的方法。

除了用户定义的 symbol,还有一些已经众所周知的内置 symbol。 内置 symbol 用来表示语言内部的行为。

以下为这些 symbol 的列表:

  • Symbol.hasInstance

    方法,会被 instanceof 运算符调用。构造器对象用来识别一个对象是否是其实例。

  • Symbol.isConcatSpreadable

    布尔值,表示当在一个对象上调用 Array.prototype.concat 时,这个对象的数组元素是否可展开。

  • Symbol.iterator

    方法,被 for-of 语句调用。返回对象的默认迭代器。

  • Symbol.match

    方法,被 String.prototype.match 调用。正则表达式用来匹配字符串。

  • Symbol.replace

    方法,被 String.prototype.replace 调用。正则表达式用来替换字符串中匹配的子串。

  • Symbol.search

    方法,被 String.prototype.search 调用。正则表达式返回被匹配部分在字符串中的索引。

  • Symbol.species

    函数值,为一个构造函数。用来创建派生对象。

  • Symbol.split

    方法,被 String.prototype.split 调用。正则表达式来用分割字符串。

  • Symbol.toPrimitive

    方法,被 ToPrimitive 抽象操作调用。把对象转换为相应的原始值。

  • Symbol.toStringTag

    方法,被内置方法 Object.prototype.toString 调用。返回创建对象时默认的字符串描述。

  • Symbol.unscopables

    对象,它自己拥有的属性会被 with 作用域排除在外。

练习

1、对下面数组进行求和(要求小于0的数不参与求和 比如下面的-1 -3就不参与求和运算)

var arr = [1,2,3,-1,2,0,6,-3,-5,9,4,-2]

2、提取数组中的非零值

var arr = [4,0,7,9,0,0,2,6,0,3,1,0];
var noZero = [arr的所有非零值];

3、更换性别的数字表现形式为汉字 0 -> 男 1 -> 女

var users = [{ name: "如花", sex: 1 },{ name: "李白", sex: 0 },{ name: "鲁智深", sex: 0 },{ name: "貂蝉", sex: 1 },{ name: "林冲", sex: 0 }
]

4、求数组中所有成员年龄的和

var arr = [{ name: "李白", age: 20 },{ name: "王安石", age: 30 },{ name: "李清照", age: 26 },{ name: "苏轼", age: 18 },{ name: "汪伦", age: 15 },{ name: "如烟", age: 36 }
]

5、使用解构赋值的方式实现两个变量值的交换

var a = 20;
var b = 40;
// 交换操作 --
console.log(a); // 40
console.log(b); // 20

6、给定一个员工的薪资对象,得到对象中最高薪资的人的姓名

let salaries = {libai: 300,sushi: 600,wangwei: 900,dufu: 20,wangbo: 150
}

【ES6】ES6简介,ES6常用操作,let 、var和const的区别,看完我写的ES6,马上会的,你就是高手相关推荐

  1. Var let const 的区别

    Var let const 的区别 变量提升 var 存在变量提升 变量可以在声明之前调用 但是值为undefined. let ,const 不存在变量提升.他们声明的变量必须在声明后调用 如果在之 ...

  2. 前端开发:JS中let、var和const的区别详解

    前言 前端开发过程中,JS声明变量的关键字想必开发者都不陌生,而且使用的频率在前端开发过程中也是数一数二的.JS中声明变量的关键字有三个let.var和const,但是三者的使用对比和区别也是非常重要 ...

  3. js中定义变量之②var let const的区别

    var 上一篇文章有讲过,是js定义变量的关键词. 但是在es6中,新添加了两个关键词,用于变量声明的关键词:let 和const 接下来就说一下var let 和const的区别: 首先说var 用 ...

  4. Js中var,let,const的区别

    一:区别: 1.var声明的变量属于函数作用域,而let和const声明的变量属于块级作用域:(js作用域在上篇文章) 2.var声明的变量存在变量提升,而let和const没有 3.var声明的变量 ...

  5. 这篇看完我得理解ES6中中常见语法

    目录 前言 1let篇 1.1作用域 1.2变量提升 1.3相同作用域赋值 2const篇 3模板字符串篇 3.1传统 3.2模板字符串复制 4扩展运算符篇 4.1传统赋值 4.2扩展字符串复制 前言 ...

  6. Gnuplot的简介与常用操作

    Gnuplot 简介 ​ Gnuplot是一个命令行的交互式绘图工具(command-driven interactive function plotting program). ​ 用户通过输入命令 ...

  7. tableau入门简介和常用操作

    目录  1.tableau的介绍    1)tableau的优势    2)维度和指标    3)展现形式    4)设计形式    5)设计流程  2.数据导入.数据浏览  3.调整tableau中 ...

  8. 常用排序:冒泡排序与快速排序详解,看完这篇就够了!风马博客

    常用排序:冒泡排序与快速排序详解. 在排序算法中,冒泡排序和快速排序可以算是排序算法入门必会的两种排序了,今天和大家来分析一下如何快速理解并掌握这两种排序.首先冒泡排序是初学者最常用的排序,所以我们先 ...

  9. Python常用基础语法知识点大全合集,看完这一篇文章就够了

    介绍 Python 是一门独特的语言,快速浏览一下他的要点: 面向对象:每一个变量都是一个类,有其自己的属性(attribute)与方法(method). 语法块:用缩进(四个空格)而不是分号.花括号 ...

  10. 微信小程序var,let,const的区别

    var 用var的方式声明的变量,为全局变量 let 声明块级变量,即局部变量 const 用于声明常量,也具有块级作用域 const PI=3.14;

最新文章

  1. 领域驱动设计:软件核心复杂性应对之道
  2. linux存储--linux内存分配图(九)
  3. 非MFC工程中使用MFC库
  4. 最大熵学习笔记(六)优缺点分析
  5. 大牛书单|安全技术方向好书分享
  6. 说说 JavaScript 计时器的工作原理
  7. NET防SQL注入方法
  8. Android 系统(146)----Android进程保活招数概览
  9. vue页面乱码_项目部署到weblogic后页面乱码问题
  10. java cygwin 乱码_Cygwin中文乱码的解决方案
  11. java编程思想--协变返回类型
  12. Java入门书籍推荐
  13. html注释js,JavaScript 注释
  14. 阿里云短信验证码+Java开发
  15. 【CAN总线学习01】CAN网络概述
  16. java基于uni-app框架的民宿客房预订系统 小程序
  17. 浙江工商大学计算机研究生院,浙江工商大学研究生院
  18. Python美股量化交易填坑记录——14c.W底交易机器人(实盘记录)
  19. s盒c语言算法,AES加密算法中的S盒及其C语言实现
  20. CmsWing源码分析(8) 栏目

热门文章

  1. 软考-嵌入式系统设计师-笔记:历年专业英语题
  2. 大数据是什么 有哪些价值
  3. Foxmail设置的学习
  4. Makefile--如何将当前文件下的所有*.cpp文件与*.c文件全部生成相应的可执行文件
  5. springboot 解决 woff2、ttf 跨域无法解析问题
  6. squid代理服务器的应用
  7. html embed如何禁止自动播放,html embed用法
  8. java 实现三角函数边长计算完整代码
  9. 概率论中的一些基础知识——条件概率 先验概率 后验概率 似然 概率分布函数 概率密度函数
  10. 汕头大学计算机专业就业,汕头大学毕业生最后怎样了?17%进入世界和中国500强,月薪5185元...