一.ECMAScript和JavaScript的关系:
ECMAScript是JavaScript的规格,JavaScript是ECMAScript的一种实现(另外的 ECMAScript 方言还有 Jscript 和 ActionScript)。
日常场合,这两个词是可以互换的。
二.ES6与不同版本:
ES6 既是一个历史名词,也是一个泛指,含义是 5.1 版以后的 JavaScript 的下一代标准,涵盖了 ES2015、ES2016、ES2017 等等,而 ES2015 则是正式名称,特指该年发布的正式版本的语言标准。 ES6,一般是指 ES2015 标准,但有时也是泛指“下一代 JavaScript 语言”
三.Babel(Traceur是另外一个ES6转换器):
1.定义:
将ES6的代码转换成ES5的代码,从而在现有的环境中运行,让我们能用下一代JS(即ES6)编写前端代码
2.如何在webpack中使用babel:
(1)安装babel:
npm install --save-dev babel-loader babel-core
(2)在webpack中配置babel-loader:
module: {
rules: [
{ test: /\.js$/, exclude: /node_modules/, loader: "babel-loader" }
]
}
(3)创建.babelrc配置文件:
安装预设:
npm install babel-preset-env --save-dev
在.bashrc中配置这些预设:
{
"presets": ["env"]
}
3.注意:
在babel 6中,将babel拆分成两个包:babel-cli和babel-core。如果你想要在CLI(终端或REPL)使用babel就下载babel-cli,如果想要在node中使用就下载babel-core
四.let和const:
1.let:
作用域只限于当前代码块,TDZ: 暂时性死区;
使用let申明的变量作用域不会被提升
在相同作用域不能申明相同变量,不存在变量提升;
for循环体现let的父子作用域(es5中var申明时用闭包解决该问题)
2.const:
只在当前代码块中有效
作用域不能被提升
不能重复申明
申明的常量必须赋值(注意:常量为复合类型的数据时可以修改)
Object.freeze()可以将对象冻结,彻底不能修改
五.ES6中六种声明变量的方法:
var、function、let、const、import和class
var命令和function命令声明的全局变量,依旧是顶层对象的属性;
另一方面规定,let命令、const命令、class命令声明的全局变量,不属于顶层对象的属性
全局变量将逐步与顶层对象的属性脱钩
六.变量的解构赋值:
1.数组的解构赋值:
(1)解构:ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值
(2)ES6 允许写成下面这样:
let [a, b, c] = [1, 2, 3];
(3)解构赋值允许指定默认值:
let [x, y = 'b'] = ['a']; // x='a', y='b'
let [x, y = 'b'] = ['a', undefined]; // x='a', y='b'
注意:ES6 内部使用严格相等运算符(===),判断一个位置是否有值。
所以,只有当一个数组成员(===)严格等于undefined,默认值才会生效,为null时不生效
let [x = 1] = [undefined];
x // 1
let [x = 1] = [null];
x // null
2.对象的解构赋值:
(1)对象的解构与数组有一个重要的不同。数组的元素是按次序排列的,变量的取值由它的位置决定;
而对象的属性没有次序,变量必须与属性同名,才能取到正确的值
let { bar, foo } = { foo: "aaa", bar: "bbb" };
foo // "aaa"
bar // "bbb"
(2) 和下面这种方法一样:
let { foo: foo, bar: bar } = { foo: "aaa", bar: "bbb" };
3.字符串的解构赋值:
const [a, b, c, d, e] = 'hello';
4.数值和布尔值的解构赋值:
(1)解构赋值时,如果等号右边是数值和布尔值,则会先转为对象;
由于undefined和null无法转为对象,所以对它们进行解构赋值
(2)示例:
let {toString: s} = 123;
s === Number.prototype.toString // true
let {toString: s} = true;
s === Boolean.prototype.toString // true
5.函数参数的解构赋值:
函数参数的解构也可以使用默认值
6.圆括号问题:
(1)不能使用圆括号的情况:
变量声明语句
函数参数
赋值语句的模式
(2)可以使用圆括号的情况:
只有一种:赋值语句的非模式部分,可以使用圆括号
7.解构赋值的用途:
(1)交换变量的值
(2)从函数返回多个值
(3)函数参数的定义
(4)提取json数据
(5)函数参数的默认值
(6)遍历Map结构
(7)输入模块的制定方法
七.字符串的扩展:
1.字符的 Unicode 表示法:
JavaScript 允许采用\uxxxx形式表示一个字符,其中xxxx表示字符的 Unicode 码点
比如:
"\u0061"
// "a"
2.codePointAt方法:
能够正确处理 4 个字节储存的字符,返回一个字符的码点
codePointAt方法会正确返回 32 位的 UTF-16 字符的码点。对于那些两个字节储存的常规字符,它的返回结果与charCodeAt方法相同
3.tring.fromCodePoint():
可以识别大于0xFFFF的字符,弥补了String.fromCharCode方法的不足。在作用上,正好与codePointAt方法相反
4.字符串的遍历器接口:
ES6 为字符串添加了遍历器接口,使得字符串可以被for…of循环遍历
for (let codePoint of 'foo') {
console.log(codePoint)
}
5.normalize():
用来将字符的不同表示方法统一为同样的形式,这称为 Unicode 正规化;
'\u01D1'.normalize() === '\u004F\u030C'.normalize()
6.includes(), startsWith(), endsWith():
字符串查找:str.includes(要找的东西) 返回true/false
str.indexof(要找的东西) 返回索引位置,没找到返回-1
(1)includes():返回布尔值,表示是否找到了参数字符串;
(2)startsWith():返回布尔值,表示参数字符串是否在原字符串的头部;
(3)endsWith():返回布尔值,表示参数字符串是否在原字符串的尾部。
这三个方法都支持第二个参数,表示开始搜索的位置
let s = 'Hello world!';
s.startsWith('world', 6) // true
s.endsWith('Hello', 5) // true
s.includes('Hello', 6) // false
7.repeat():
repeat方法返回一个新字符串,表示将原字符串重复n次;
'na'.repeat('3') // "nanana"
'hello'.repeat(2) // "hellohello"
8.padStart(),padEnd() :
ES2017 有了字符串补全长度功能。如果某个字符串不够指定长度,会在头部或尾部补全。
padStart()用于头部补全,padEnd()用于尾部补全;
padStart()和padEnd()一共接受两个参数,第一个参数是字符串补全生效的最大长度,第二个参数是用来补全的字符串
'x'.padStart(5, 'ab') // 'ababx
'x'.padEnd(5, 'ab') // 'xabab'
9.matchAll():
返回一个正则表达式在当前字符串的所有匹配
10.模板字符串:
模板字符串(template string)是增强版的字符串,用反引号(`)标识。
它可以当作普通字符串使用,也可以用来定义多行字符串,或者在字符串中嵌入变量
${ 变量或者函数或者字符串 }
11.标签模板:
模板字符串可以紧跟在一个函数名后面,该函数将被调用来处理这个模板字符串。称为“标签模板”
12.String.raw():
用来充当模板字符串的处理函数,返回一个斜杠都被转义(即斜杠前面再加一个斜杠)的字符串,对应于替换变量后的模板字符串
作为处理模板字符串的基本方法,它会将所有变量替换,而且对斜杠进行转义,方便下一步作为字符串来使用
作为正常的函数使用。这时,它的第一个参数,应该是一个具有raw属性的对象,且raw属性的值应该是一个数组
八.数值的扩展:
1.Number.isFinite(), Number.isNaN():
Number.isFinite()用来检查一个数值是否为有限的(finite),即不是Infinity;
Number.isNaN()用来检查一个值是否为NaN
Number.isFinite()对于非数值一律返回false,
Number.isNaN()只有对于NaN才返回true,非NaN一律返回false
2.Number.parseInt(), Number.parseFloat():
ES6 将全局方法parseInt()和parseFloat(),移植到Number对象上面,行为完全保持不变
3.Number.isInteger():
Number.isInteger()用来判断一个数值是否为整数
4.Number.EPSILON:
它表示 1 与大于 1 的最小浮点数之间的差;
是 JavaScript 能够表示的最小精度
5.安全整数和 Number.isSafeInteger():
(1)JavaScript 能够准确表示的整数范围在-253到253之间(不含两个端点),超过这个范围,无法精确表示这个值
(2)ES6 引入了Number.MAX_SAFE_INTEGER和Number.MIN_SAFE_INTEGER这两个常量,用来表示这个范围的上下限
(3)Number.isSafeInteger()则是用来判断一个整数是否落在这个范围之内;
6.Math 对象的扩展:
(1)Math.trunc():用于去除一个数的小数部分,返回整数部分;
(2)Math.sign():用来判断一个数到底是正数、负数、还是零。对于非数值,会先将其转换为数值。
它会返回五种值:
参数为正数,返回+1;
参数为负数,返回-1;
参数为 0,返回0;
参数为-0,返回-0;
其他值,返回NaN。
(3)Math.cbrt():用于计算一个数的立方根
(4)Math.clz32():返回一个数的 32 位无符号整数形式有多少个前导 0;
(5)Math.imul():返回两个数以 32 位带符号整数形式相乘的结果,返回的也是一个 32 位的带符号整数。
(6)Math.fround():返回一个数的32位单精度浮点数形式
(7)Math.hypot():返回所有参数的平方和的平方根
(8)Math.expm1():Math.expm1(x)返回 ex - 1,即Math.exp(x) - 1
(9)Math.log1p():Math.log1p(x)方法返回1 + x的自然对数,即Math.log(1 + x)。如果x小于-1,返回NaN。
(10)Math.log10():Math.log10(x)返回以 10 为底的x的对数。如果x小于 0,则返回 NaN;
(11)Math.log2():返回以 2 为底的x的对数。如果x小于 0,则返回 NaN;
(12)ES6 新增了 6 个双曲函数方法:
Math.sinh(x) 返回x的双曲正弦(hyperbolic sine)
Math.cosh(x) 返回x的双曲余弦(hyperbolic cosine)
Math.tanh(x) 返回x的双曲正切(hyperbolic tangent)
Math.asinh(x) 返回x的反双曲正弦(inverse hyperbolic sine)
Math.acosh(x) 返回x的反双曲余弦(inverse hyperbolic cosine)
Math.atanh(x) 返回x的反双曲正切(inverse hyperbolic tangent)
7.指数运算符:
指数运算符(**)
九.函数的扩展:
1.函数参数的默认值:
ES6 允许为函数的参数设置默认值,即直接写在参数定义的后面;
2.可与解构赋值默认值结合使用:
3.参数默认值的位置:
通常情况下,定义了默认值的参数,应该是函数的尾参数
4.函数的 length 属性:
指定了默认值以后,函数的length属性,将返回没有指定默认值的参数个数
5.作用域:
一旦设置了参数的默认值,函数进行声明初始化时,参数会形成一个单独的作用域(context)。
等到初始化结束,这个作用域就会消失
6.rest参数:
(1)ES6 引入 rest 参数(形式为…变量名),用于获取函数的多余参数,这样就不需要使用arguments对象了。
rest 参数搭配的变量是一个数组,该变量将多余的参数放入数组中。
例子:
function add(...values) {
let sum = 0;
for (var val of values) {
sum += val;
}
return sum;
}
add(2, 5, 3) // 10
(2)与arguments的区别:
arguments对象不是数组,而是一个类似数组的对象。所以为了使用数组的方法,必须使用Array.prototype.slice.call先将其转为数组
rest 参数,它就是一个真正的数组,数组特有的方法都可以使用
(3)rest 参数之后不能再有其他参数(即只能是最后一个参数),否则会报错
(4)函数的length属性,不包括 rest 参数
7.name属性:
函数的name属性,返回该函数的函数名
8.箭头函数:
(1)ES6 允许使用“箭头”(=>)定义函数
var f = v => v;
// 等同于
var f = function (v) {
return v;
};
(2)箭头函数的一个用处是简化回调函数:
// 正常函数写法
[1,2,3].map(function (x) {
return x * x;
});
// 箭头函数写法
[1,2,3].map(x => x * x);
(3) rest 参数与箭头函数结合的例子:
const numbers = (...nums) => nums;
numbers(1, 2, 3, 4, 5)
(4)箭头函数有几个使用注意点:
函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象;
不可以当作构造函数,也就是说,不可以使用new命令,否则会抛出一个错误;
不可以使用arguments对象,该对象在函数体内不存在。如果要用,可以用 rest 参数代替;
不可以使用yield命令,因此箭头函数不能用作 Generator 函数
this对象的指向是可变的,但是在箭头函数中,它是固定的;this总是指向函数定义生效时所在的对象
由于箭头函数没有自己的this,所以当然也就不能用call()、apply()、bind()这些方法去改变this的指向
(5)不应该使用箭头函数场合:
第一个场合是定义函数的方法,且该方法内部包括this;
第二个场合是需要动态this的时候,也不应使用箭头函数
9.双冒号运算符:
(1)函数绑定运算符是并排的两个冒号(::),双冒号左边是一个对象,右边是一个函数。该运算符会自动将左边的对象,作为上下文环境(即this对象),绑定到右边的函数上面。
用来取代call、apply、bind调用
foo::bar(...arguments);
// 等同于
bar.apply(foo, arguments);
(2)如果双冒号左边为空,右边是一个对象的方法,则等于将该方法绑定在该对象上面
(3)如果双冒号运算符的运算结果,还是一个对象,就可以采用链式写法
10.尾调用优化:
(1)尾调用(Tail Call):指某个函数的最后一步是调用另一个函数
function f(x){
return g(x);
}
(2)尾调用优化:只保留内层函数的调用帧。如果所有函数都是尾调用,那么完全可以做到每次执行时,调用帧只有一项,这将大大节省内存
(3)注意:只有不再用到外层函数的内部变量,内层函数的调用帧才会取代外层函数的调用帧,否则就无法进行“尾调用优化”
11.尾递归:
(1)函数调用自身,称为递归。如果尾调用自身,就称为尾递归
(2)对于尾递归来说,由于只存在一个调用帧,所以永远不会发生“栈溢出”错误。
function factorial(n, total) {
if (n === 1) return total;
return factorial(n - 1, n * total);
}
factorial(5, 1) // 120
(3)递归函数的改写:
a.在尾递归函数之外,再提供一个正常形式的函数。
function tailFactorial(n, total) {
if (n === 1) return total;
return tailFactorial(n - 1, n * total);
}
function factorial(n) {
return tailFactorial(n, 1);
}
factorial(5) // 120
b.采用 ES6 的函数默认值:
function factorial(n, total = 1) {
if (n === 1) return total;
return factorial(n - 1, n * total);
}
factorial(5) // 120
(4)尾调用优化发生时,函数的调用栈会改写,因此上面两个变量就会失真。
严格模式禁用这两个变量,所以尾调用模式仅在严格模式下生效
(5)在非严格模式下也可以实现尾递归:采用“循环”换掉“递归”
12.函数参数的尾逗号:
ES2017 允许函数的最后一个参数有尾逗号
十.数组的扩展:
1.扩展运算符:
(1)三个点(…),它好比 rest 参数的逆运算,将一个数组转为用逗号分隔的参数序列;
console.log(1, ...[2, 3, 4], 5)
// 1 2 3 4 5
[...document.querySelectorAll('div')]
// [<div>, <div>, <div>]
(2)该运算符主要用于函数调用
(3)该运算符主要用于函数调用
function f(x, y, z) {
// ...
}
var args = [0, 1, 2];
f.apply(null, args);
// ES5 的写法
// ES6的写法
function f(x, y, z) {
// ...
}
let args = [0, 1, 2];
f(...args);
(4)扩展运算符的应用:
a.复制数组:
const a1 = [1, 2];
const a2 = [...a1];
b.合并数组:
const arr1 = ['a', 'b'];
const arr2 = ['c'];
const arr3 = ['d', 'e'];
[...arr1, ...arr2, ...arr3]
// [ 'a', 'b', 'c', 'd', 'e' ]
c.与解构赋值结合:
扩展运算符可以与解构赋值结合起来,用于生成数组
const [first, ...rest] = [1, 2, 3, 4, 5];
first // 1
rest // [2, 3, 4, 5]
d.字符串:
扩展运算符还可以将字符串转为真正的数组
[...'hello']
// [ "h", "e", "l", "l", "o" ]
[...'hello'].reverse().join('')
e.实现了Iterator接口:
任何 Iterator 接口的对象,都可以用扩展运算符转为真正的数组
let nodeList = document.querySelectorAll('div');
let array = [...nodeList];
f.Map 和 Set 结构,Generator 函数:
扩展运算符内部调用的是数据结构的 Iterator 接口,因此只要具有 Iterator 接口的对象,都可以使用扩展运算符
2.Array.from():
(1)Array.from方法用于将两类对象转为真正的数组:类似数组的对象(array-like object)和可遍历(iterable)的对象。
包括 ES6 新增的数据结构 Set 和 Map
let arrayLike = {
'0': 'a',
'1': 'b',
'2': 'c',
length: 3
};
let arr2 = Array.from(arrayLike); // ['a', 'b', 'c']
(2)只要是部署了 Iterator 接口的数据结构,Array.from都能将其转为数组。
Array.from('hello')
// ['h', 'e', 'l', 'l', 'o']
(3)任何有length属性的对象,都可以通过Array.from方法转为数组,而此时扩展运算符就无法转换
(4)Array.from还可以接受第二个参数,作用类似于数组的map方法,用来对每个元素进行处理,将处理后的值放入返回的数组。
Array.from([1, 2, 3], (x) => x * x)
// [1, 4, 9]
(5)Array.from()的另一个应用是,将字符串转为数组,然后返回字符串的长度
3.Array.of():
(1)Array.of方法用于将一组值,转换为数组
(2)Array.of基本上可以用来替代Array()或new Array(),并且不存在由于参数不同而导致的重载。它的行为非常统一
(3)Array.of总是返回参数值组成的数组。如果没有参数,就返回一个空数组
4.数组实例的 copyWithin():
(1)在当前数组内部,将指定位置的成员复制到其他位置(会覆盖原有成员),然后返回当前数组。
也就是说,使用这个方法,会修改当前数组。
(2)Array.prototype.copyWithin(target, start = 0, end = this.length)
它接受三个参数。
target(必需):从该位置开始替换数据。如果为负值,表示倒数。
start(可选):从该位置开始读取数据,默认为 0。如果为负值,表示倒数。
end(可选):到该位置前停止读取数据,默认等于数组长度。如果为负值,表示倒数。
这三个参数都应该是数值,如果不是,会自动转为数值
[1, 2, 3, 4, 5].copyWithin(0, 3)
// [4, 5, 3, 4, 5]
5.数组实例的 find() 和 findIndex():
(1)数组实例的find方法,用于找出第一个符合条件的数组成员。它的参数是一个回调函数,所有数组成员依次执行该回调函数,直到找出第一个返回值为true的成员,然后返回该成员。
如果没有符合条件的成员,则返回undefined
[1, 5, 10, 15].find(function(value, index, arr) {
return value > 9;
}) // 10
find方法的回调函数可以接受三个参数,依次为当前的值、当前的位置和原数组。
(2)findIndex方法的用法与find方法非常类似,返回第一个符合条件的数组成员的位置,如果所有成员都不符合条件,则返回-1。
[1, 5, 10, 15].findIndex(function(value, index, arr) {
return value > 9;
}) // 2
(3)这两个方法都可以接受第二个参数,用来绑定回调函数的this对象;
(4)这两个方法都可以发现NaN,弥补了数组的indexOf方法的不足:
indexOf方法无法识别数组的NaN成员,但是findIndex方法可以借助Object.is方法做到
[NaN].indexOf(NaN)
// -1
[NaN].findIndex(y => Object.is(NaN, y))
// 0
6.数组实例的fill():
(1)fill方法使用给定值,填充一个数组;
fill方法用于空数组的初始化非常方便。数组中已有的元素,会被全部抹去。
['a', 'b', 'c'].fill(7)
// [7, 7, 7]
(2)fill方法还可以接受第二个和第三个参数,用于指定填充的起始位置和结束位置
['a', 'b', 'c'].fill(7, 1, 2)
// ['a', 7, 'c']
7.数组实例的 entries(),keys() 和 values():
(1)entries(),keys()和values()用于遍历数组。它们都返回一个遍历器对象,可以用for…of循环进行遍历;
唯一的区别是keys()是对键名的遍历、values()是对键值的遍历,entries()是对键值对的遍历。
(2)示例代码:
for (let index of ['a', 'b'].keys()) {
console.log(index);
}
// 0
// 1
for (let elem of ['a', 'b'].values()) {
console.log(elem);
}
// 'a'
// 'b'
for (let [index, elem] of ['a', 'b'].entries()) {
console.log(index, elem);
}
// 0 "a"
8.数组实例的 includes():
(1)该方法返回一个布尔值,表示某个数组是否包含给定的值
(2)该方法的第二个参数表示搜索的起始位置,默认为0。如果第二个参数为负数,则表示倒数的位置,如果这时它大于数组长度(比如第二个参数为-4,但数组长度为3),则会重置为从0开始。
(3)Map 和 Set 数据结构有一个has方法,需要注意与includes区分。
Map 结构的has方法,是用来查找键名的,比如Map.prototype.has(key)、WeakMap.prototype.has(key)、Reflect.has(target, propertyKey)。
Set 结构的has方法,是用来查找值的,比如Set.prototype.has(value)、WeakSet.prototype.has(value)。
9.数组实例的 flat(),flatMap():
(1)Array.prototype.flat()用于将嵌套的数组“拉平”,变成一维的数组。该方法返回一个新数组,对原数据没有影响
[1, 2, [3, 4]].flat()
// [1, 2, 3, 4]
(2)flat()默认只会“拉平”一层,如果想要“拉平”多层的嵌套数组,可以将flat()方法的参数写成一个整数,表示想要拉平的层数,默认为1。
[1, 2, [3, [4, 5]]].flat()
// [1, 2, 3, [4, 5]]
[1, 2, [3, [4, 5]]].flat(2)
// [1, 2, 3, 4, 5]
(3)如果不管有多少层嵌套,都要转成一维数组,可以用Infinity关键字作为参数。
[1, [2, [3]]].flat(Infinity)
// [1, 2, 3]
(4)flatMap()方法对原数组的每个成员执行一个函数(相当于执行Array.prototype.map()),然后对返回值组成的数组执行flat()方法。该方法返回一个新数组,不改变原数组
// 相当于 [[2, 4], [3, 6], [4, 8]].flat()
[2, 3, 4].flatMap((x) => [x, x * 2])
// [2, 4, 3, 6, 4, 8]
10.数组的空位:
ES6 则是明确将空位转为undefined
十一.对象的扩展:
1.属性的简洁表示法:
直接写入变量和函数,作为对象的属性和方法
const baz = {foo: foo};
2.属性名表达式:
(1)ES6 允许字面量定义对象时,用方法二(表达式)作为对象的属性名,即把表达式放在方括号内
(2)代码示例:
let propKey = 'foo';
let obj = {
[propKey]: true,
['a' + 'bc']: 123
};
3.方法的name属性:
(1)函数的name属性,返回函数名。对象方法也是函数,因此也有name属性
(2)如果对象的方法使用了取值函数(getter)和存值函数(setter),则name属性不是在该方法上面,而是该方法的属性的描述对象的get和set属性上面,返回值是方法名前加上get和set
(3)有两种特殊情况:
bind方法创造的函数,name属性返回bound加上原函数的名字;
Function构造函数创造的函数,name属性返回anonymous
4.属性的可枚举性和遍历:
(1)可枚举性:
对象的每个属性都有一个描述对象(Descriptor),用来控制该属性的行为。Object.getOwnPropertyDescriptor方法可以获取该属性的描述对象
let obj = { foo: 123 };
Object.getOwnPropertyDescriptor(obj, 'foo')
// {
// value: 123,
// writable: true,
// enumerable: true,
// configurable: true
// }
描述对象的enumerable属性,称为”可枚举性“,如果该属性为false,就表示某些操作会忽略当前属性
(2)有四个操作会忽略enumerable为false的属性:
for…in循环:只遍历对象自身的和继承的可枚举的属性。
Object.keys():返回对象自身的所有可枚举的属性的键名。
JSON.stringify():只串行化对象自身的可枚举的属性。
Object.assign(): 忽略enumerable为false的属性,只拷贝对象自身的可枚举的属性。
(3)属性的遍历:
a. for…in
for…in循环遍历对象自身的和继承的可枚举属性(不含 Symbol 属性)。
b. Object.keys(obj)
Object.keys返回一个数组,包括对象自身的(不含继承的)所有可枚举属性(不含 Symbol 属性)的键名。
c. Object.getOwnPropertyNames(obj)
Object.getOwnPropertyNames返回一个数组,包含对象自身的所有属性(不含 Symbol 属性,但是包括不可枚举属性)的键名。
d. Object.getOwnPropertySymbols(obj)
Object.getOwnPropertySymbols返回一个数组,包含对象自身的所有 Symbol 属性的键名。
e. Reflect.ownKeys(obj)
Reflect.ownKeys返回一个数组,包含对象自身的所有键名,不管键名是 Symbol 或字符串,也不管是否可枚举。
以上的 5 种方法遍历对象的键名,都遵守同样的属性遍历的次序规则:
首先遍历所有数值键,按照数值升序排列。
其次遍历所有字符串键,按照加入时间升序排列。
最后遍历所有 Symbol 键,按照加入时间升序排列。
5.super关键字:
(1)ES6 又新增了另一个类似this的关键字super,指向当前对象的原型对象
(2)super关键字表示原型对象时,只能用在对象的方法之中,用在其他地方都会报错
(3)JavaScript 引擎内部,super.foo等同于Object.getPrototypeOf(this).foo(属性)或Object.getPrototypeOf(this).foo.call(this)(方法)
6.扩展运算符:
对象的扩展运算符(…)用于取出参数对象的所有可遍历属性,拷贝到当前对象之中
十二.对象的新增方法:
1.Object.is():
(1)ES5 比较两个值是否相等,只有两个运算符:相等运算符()和 严格相等运算符(=)。
它们都有缺点,前者会自动转换数据类型,后者的NaN不等于自身,以及+0等于-0
(2)Object.is就是部署这个算法的新方法。它用来比较两个值是否严格相等,与严格比较运算符(===)的行为基本一致;
不同之处只有两个:一是+0不等于-0,二是NaN等于自身
Object.is('foo', 'foo') // true
Object.is({}, {}) // false
+0 === -0 //true
NaN === NaN // false
Object.is(+0, -0) // false
Object.is(NaN, NaN) // true
2.Object.assign():
(1)Object.assign方法用于对象的合并,将源对象(source)的所有可枚举属性,复制到目标对象(target)
Object.assign方法的第一个参数是目标对象,后面的参数都是源对象
const target = { a: 1 };
const source1 = { b: 2 };
const source2 = { c: 3 };
Object.assign(target, source1, source2);
target // {a:1, b:2, c:3}
(2)如果目标对象与源对象有同名属性,或多个源对象有同名属性,则后面的属性会覆盖前面的属性
(3)浅拷贝:
Object.assign方法实行的是浅拷贝,而不是深拷贝。
也就是说,如果源对象某个属性的值是对象,那么目标对象拷贝得到的是这个对象的引用
(4)同名属性的替换:
对于这种嵌套的对象,一旦遇到同名属性,Object.assign的处理方法是替换,而不是添加。
const target = { a: { b: 'c', d: 'e' } }
const source = { a: { b: 'hello' } }
Object.assign(target, source)
// { a: { b: 'hello' } }
(5)数组的处理:
Object.assign可以用来处理数组,但是会把数组视为对象
Object.assign([1, 2, 3], [4, 5])
// [4, 5, 3]
(6)取值函数的处理:
Object.assign只能进行值的复制,如果要复制的值是一个取值函数,那么将求值后再复制
(7)常见用途:
a.为对象添加属性
class Point {
constructor(x, y) {
Object.assign(this, {x, y});
}
}
b.为对象添加方法
c.克隆对象
d.合并多个对象
e.为属性添加默认值
3.Object.getOwnPropertyDescriptors():
(1)ES5 的Object.getOwnPropertyDescriptor()方法会返回某个对象属性的描述对象(descriptor)。
ES2017 引入了Object.getOwnPropertyDescriptors()方法,返回指定对象所有自身属性(非继承属性)的描述对象
(2)该方法的引入目的,主要是为了解决Object.assign()无法正确拷贝get属性和set属性的问题
(3)Object.getOwnPropertyDescriptors()方法配合Object.defineProperties()方法,就可以实现正确拷贝
(4)配合Object.create()方法,将对象属性克隆到一个新对象。这属于浅拷贝
(5)Object.getOwnPropertyDescriptors()方法可以实现一个对象继承另一个对象。以前,继承另一个对象
4.__proto__属性,Object.setPrototypeOf(),Object.getPrototypeOf():
(1)JavaScript 语言的对象继承是通过原型链实现的。ES6 提供了更多原型对象的操作方法
(2)__proto__属性(前后各两个下划线),用来读取或设置当前对象的prototype对象;
(3)Object.setPrototypeOf方法的作用与__proto__相同,用来设置一个对象的prototype对象,返回参数对象本身。它是 ES6 正式推荐的设置原型对象的方法。
(4)Object.getPrototypeOf()与Object.setPrototypeOf方法配套,用于读取一个对象的原型对象
5.Object.keys(),Object.values(),Object.entries():
(1)Object.keys方法,返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历(enumerable)属性的键名
var obj = { foo: 'bar', baz: 42 };
Object.keys(obj)
// ["foo", "baz"]
(2)Object.values方法返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历(enumerable)属性的键值
const obj = { foo: 'bar', baz: 42 };
Object.values(obj)
// ["bar", 42]
(3)Object.entries()方法返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历(enumerable)属性的键值对数组
const obj = { foo: 'bar', baz: 42 };
Object.entries(obj)
// [ ["foo", "bar"], ["baz", 42] ]
6.Object.fromEntries():
(1)Object.fromEntries()方法是Object.entries()的逆操作,用于将一个键值对数组转为对象
Object.fromEntries([
['foo', 'bar'],
['baz', 42]
])
// { foo: "bar", baz: 42 }
(2)该方法的主要目的,是将键值对的数据结构还原为对象,因此特别适合将 Map 结构转为对象
(3)该方法的一个用处是配合URLSearchParams对象,将查询字符串转为对象
Object.fromEntries(new URLSearchParams('foo=bar&baz=qux'))
// { foo: "bar", baz: "qux" }
&spm=1001.2101.3001.5002&articleId=84947095&d=1&t=3&u=a3b9543f74bc465c811d49bdc4625b78)
2354

被折叠的 条评论
为什么被折叠?



