ES6语法笔记(函数、数组、对象)

**以下内容均摘自ECMAScript 6 入门——阮一峰

一、函数

1.函数的默认值与解构赋值

function foo({x, y = 5}) {
  console.log(x, y);
}

foo({}) // undefined 5
foo({x: 1}) // 1 5
foo({x: 1, y: 2}) // 1 2
foo() // TypeError: Cannot read property 'x' of undefined

function foo({x, y = 5} = {}) {
  console.log(x, y);
}

foo() // undefined 5
// 写法一
function m1({x = 0, y = 0} = {}) {
  return [x, y];
}

// 写法二
function m2({x, y} = { x: 0, y: 0 }) {
  return [x, y];
}

// 函数没有参数的情况
m1() // [0, 0]
m2() // [0, 0]

// x 和 y 都有值的情况
m1({x: 3, y: 8}) // [3, 8]
m2({x: 3, y: 8}) // [3, 8]

// x 有值,y 无值的情况
m1({x: 3}) // [3, 0]
m2({x: 3}) // [3, undefined]

// x 和 y 都无值的情况
m1({}) // [0, 0];
m2({}) // [undefined, undefined]

m1({z: 3}) // [0, 0]
m2({z: 3}) // [undefined, undefined]

写法一有默认对象再对默认对象进行解构赋值,写法二只有默认对象。

2.定义了默认值的参数,应该是函数的尾参数,因为可以省略。

3.函数的length返回没有指定默认值的参数的个数。

(function (a) {}).length // 1
(function (a = 5) {}).length // 0
(function (a, b, c = 5) {}).length // 2
//如果设置了默认值的参数不是尾参数,那么length属性也不再计入后面的参数了。
(function (a, b = 1, c) {}).length // 1

4.一旦设置了参数的默认值,函数进行声明初始化时,参数会形成一个单独的作用域(context)。

var x = 1;

function f(x, y = x) {
  console.log(y);
}

f(2) // 2

5.rest 参数搭配的变量是一个数组,该变量将多余的参数放入数组中

function push(array, ...items) {
  items.forEach(function(item) {
    array.push(item);
    console.log(item);
  });
}

var a = [];
push(a, 1, 2, 3)

  rest 参数之后不能再有其他参数(即只能是最后一个参数),否则会报错。

6.ES6中指定严格模式第一种是设定全局性的严格模式,这是合法的。第二种是把函数包在一个无参数的立即执行函数里面。

  函数参数使用了默认值、解构赋值、或者扩展运算符,那么函数内部就不能显式设定为严格模式,否则会报错。

扫描二维码关注公众号,回复: 4517524 查看本文章

7.函数的name属性,返回该函数的函数名。

8.箭头函数

var f = v => v;
// 等同于
var f = function (v) {
  return v;
};

var f = () => 5;
// 等同于
var f = function () { return 5 };

var sum = (num1, num2) => num1 + num2;
// 等同于
var sum = function(num1, num2) {
  return num1 + num2;
};
//如果箭头函数的代码块部分多于一条语句,就要使用大括号将它们括起来,并且使用return语句返回。
//由于大括号被解释为代码块,所以如果箭头函数直接返回一个对象,必须在对象外面加上括号,否则会报错。
// 报错
let getTempItem = id => { id: id, name: "Temp" };

// 不报错
let getTempItem = id => ({ id: id, name: "Temp" });

*箭头函数使用注意事项

  (1)函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象。(箭头函数本身没有this,是引用的外层对象的this,是固定的)

  (2)不可以当作构造函数,也就是说,不可以使用new命令,否则会抛出一个错误。

  (3)不可以使用arguments对象,该对象在函数体内不存在。如果要用,可以用 rest 参数代替。

  (4)不可以使用yield命令,因此箭头函数不能用作 Generator 函数。

9.尾调用指某个函数的最后一步是调用另一个函数。只保留内层函数的调用帧,大大节省内存,这就叫做“尾调用优化”。

二、数组的拓展

1.拓展运算符(spread)是三个点(...)。它好比 rest 参数的逆运算,将一个数组转为用逗号分隔的参数序列。

console.log(1, ...[2, 3, 4], 5)
// 1 2 3 4 5
//由于扩展运算符可以展开数组,所以不再需要apply方法,将数组转为函数的参数了。
// ES5 的写法
function f(x, y, z) {
  // ...
}
var args = [0, 1, 2];
f.apply(null, args);

// ES6的写法
function f(x, y, z) {
  // ...
}
let args = [0, 1, 2];
f(...args);

2.扩展运算符的应用

扩展运算符提供了数组深度复制的简便写法。

const a1 = [1, 2];
// 写法一
const a2 = [...a1];
// 写法二
const [...a2] = a1;

扩展运算符提供了数组合并的简便写法。(浅拷贝)

const a1 = [{ foo: 1 }];
const a2 = [{ bar: 2 }];

const a3 = a1.concat(a2);
const a4 = [...a1, ...a2];

a3[0] === a1[0] // true
a4[0] === a1[0] // true

与结构赋值结合(只能位于最后一位)

const [first, ...rest] = [1, 2, 3, 4, 5];
first // 1
rest  // [2, 3, 4, 5]

将字符串转化为真正的数组

[...'hello']
// [ "h", "e", "l", "l", "o" ]

任何 Iterator 接口的对象,都可以用扩展运算符转为真正的数组。

 3.Array.from()将类似数组的对象(array-like object)和可遍历(iterable)的对象(包括 ES6 新增的数据结构 Set 和 Map)转为真正的数组。

  所谓类似数组的对象,本质特征只有一点,即必须有length属性。

Array.from({ length: 3 });
// [ undefined, undefined, undefined ]

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

let spans = document.querySelectorAll('span.name');

// map()
let names1 = Array.prototype.map.call(spans, s => s.textContent);

// Array.from()
let names2 = Array.from(spans, s => s.textContent)

4.Array.of()方法用于将一组值,转换为数组。

Array.of() // []
Array.of(undefined) // [undefined]
Array.of(1) // [1]
Array.of(1, 2) // [1, 2]

5.copyWithin()方法在当前数组内部,将指定位置的成员复制到其他位置(会覆盖原有成员),然后返回当前数组。

[1, 2, 3, 4, 5].copyWithin(0, 3)
// [4, 5, 3, 4, 5]

6. find() 方法找出符合条件的值(找不到返回undefined) findIndex()方法返回符合条件值的下标(找不到返回-1)。

  接受三个参数,依次为当前的值、当前的位置和原数组。

[1, 5, 10, 15].find(function(value, index, arr) {
  return value > 9;
}) // 10

[1, 5, 10, 15].findIndex(function(value, index, arr) {
  return value > 9;
}) // 2

7.fill()方法以给定值填充一个数组。

//可以接受第二个和第三个参数,用于指定填充的起始位置和结束位置。
['a', 'b', 'c'].fill(7, 1, 2)
// ['a', 7, 'c']

8.entries(),keys() 和 values()与for..of配合遍历数组

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"
// 1 "b"

9.includes()方法表示某个数组是否包含给定的值。

[1, 2, 3].includes(2)     // true
[1, 2, 3].includes(4)     // false
[1, 2, NaN].includes(NaN) // true

10.flat()方法用于拉平多维数组(默认拉平1层) flatMap()方法对原数组的每个成员执行一个函数,然后对返回值组成的数组执行flat()方法。

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

[1, 2, [3, [4, 5]]].flat(2)
// [1, 2, 3, 4, 5]
// 相当于 [[2, 4], [3, 6], [4, 8]].flat()
[2, 3, 4].flatMap((x) => [x, x * 2])
// [2, 4, 3, 6, 4, 8]

//只能展开一层
// 相当于 [[[2]], [[4]], [[6]], [[8]]].flat()
[1, 2, 3, 4].flatMap(x => [[x * 2]])
// [[2], [4], [6], [8]]

11.数组中处理空位[,,]的规则非常不统一,应避免出现空位。

三、对象

1.属性与函数的简写形式

function f(x, y) {
  return {x, y};
}

// 等同于

function f(x, y) {
  return {x: x, y: y};
}

f(1, 2) // Object {x: 1, y: 2}

const o = {
  method() {
    return "Hello!";
  }
};

// 等同于

const o = {
  method: function() {
    return "Hello!";
  }
};

2.属性名表达式。ES6 允许字面量定义对象时,用表达式作为对象的属性名,即把表达式放在方括号内。

let propKey = 'foo';

let obj = {
  [propKey]: true,
  ['a' + 'bc']: 123
};

let obj = {
  ['h' + 'ello']() {
    return 'hi';
  }
};

obj.hello() // hi

  属性名表达式与简洁表示法,不能同时使用,会报错。

3.函数的name属性,返回函数名。对象方法也是函数,因此也有name属性。

const person = {
  sayName() {
    console.log('hello!');
  },
};

person.sayName.name   // "sayName"

4.属性的遍历方法

  (1)for...in循环遍历对象自身的和继承的可枚举属性(不含 Symbol 属性)。

  (2)Object.keys(obj)返回一个数组,包括对象自身的(不含继承的)所有可枚举属性(不含 Symbol 属性)的键名。

  (3)Object.getOwnPropertyNames(obj)返回一个数组,包含对象自身的所有属性(不含 Symbol 属性,但是包括不可枚举属性)的键名。

  (4)Object.getOwnPropertySymbols(obj)返回一个数组,包含对象自身的所有 Symbol 属性的键名。

  (5)Reflect.ownKeys(obj)返回一个数组,包含对象自身的所有键名,不管键名是 Symbol 或字符串,也不管是否可枚举。

5.super关键字,指向当前对象的原型对象。

const proto = {
  foo: 'hello'
};

const obj = {
  foo: 'world',
  find() {
    return super.foo;
  }
};

Object.setPrototypeOf(obj, proto);
obj.find() // "hello"

  目前,只有对象方法的简写法可以让 JavaScript 引擎确认,定义的是对象的方法。其他方式使用super均会报错。

6.对象的解构赋值,将所有未分配,可遍历的属性分配到指定的对象上。

let { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 };
x // 1
y // 2
z // { a: 3, b: 4 }

//本质上是浅拷贝
let obj = { a: { b: 1 } };
let { ...x } = obj;
obj.a.b = 2;
x.a.b // 2

//不能复制继承自原型对象的属性
let o1 = { a: 1 };
let o2 = { b: 2 };
o2.__proto__ = o1;
let { ...o3 } = o2;
o3 // { b: 2 }
o3.a // undefined

7.对象的扩展运算符(...)用于取出参数对象的所有可遍历属性,拷贝到当前对象之中。

let z = { a: 3, b: 4 };
let n = { ...z };
n // { a: 3, b: 4 }

//扩展运算符可以用于合并两个对象。
let ab = { ...a, ...b };
// 等同于
let ab = Object.assign({}, a, b);

  如果用户自定义的属性,放在扩展运算符后面,则扩展运算符内部的同名属性会被覆盖掉。

  如果把自定义属性放在扩展运算符前面,就变成了设置新对象的默认属性值。

四、对象的拓展方法

1.Object.is()比较两个值是否严格相等

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()方法用于对象的合并

const target = { a: 1 };

const source1 = { b: 2 };
const source2 = { c: 3 };

Object.assign(target, source1, source2);
target // {a:1, b:2, c:3}

 后面对象的属性会覆盖前面对象的属性 当首参数为非对象时,会转化为对象

Object.assign方法实行的是浅拷贝

const obj1 = {a: {b: 1}};
const obj2 = Object.assign({}, obj1);

obj1.a.b = 2;
obj2.a.b // 2
//Object.assign可以用来处理数组,但是会把数组视为对象。
Object.assign([1, 2, 3], [4, 5])
// [4, 5, 3]

3.Object.getOwnPropertyDescriptor()方法会返回某个对象属性的描述对象(descriptor)

const obj = {
  foo: 123,
  get bar() { return 'abc' }
};

Object.getOwnPropertyDescriptors(obj)
// { foo:
//    { value: 123,
//      writable: true,
//      enumerable: true,
//      configurable: true },
//   bar:
//    { get: [Function: get bar],
//      set: undefined,
//      enumerable: true,
//      configurable: true } }

4.__proto__属性(前后各两个下划线),用来读取或设置当前对象的prototype对象(浏览器必须部署这个属性,其他运行环境不一定需要部署)

  Object.setPrototypeOf方法的作用与__proto__相同,用来设置一个对象的prototype对象,返回参数对象本身。它是 ES6 正式推荐的设置原型对象的方法。

  Object.getPrototypeOf用于读取一个对象的原型对象。

let proto = {};
let obj = { x: 10 };
Object.setPrototypeOf(obj, proto);

proto.y = 20;
proto.z = 40;

obj.x // 10
obj.y // 20
obj.z // 40

 5.Object.keys(),Object.values(),Object.entries() 

Object.keys方法,返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历(enumerable)属性的键名。

Object.values方法返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历(enumerable)属性的键值。

//如果Object.values方法的参数是一个字符串,会返回各个字符组成的一个数组。
Object.values('foo')
// ['f', 'o', 'o']

//由于数值和布尔值的包装对象,都不会为实例添加非继承的属性。所以,Object.values会返回空数组。
Object.values(42) // []
Object.values(true) // [

Object.entries()方法返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历(enumerable)属性的键值对数组。

Object.fromEntries()方法是Object.entries()的逆操作,用于将一个键值对数组转为对象。

const obj = { foo: 'bar', baz: 42 };
Object.entries(obj)
// [ ["foo", "bar"], ["baz", 42] ]

Object.fromEntries([
  ['foo', 'bar'],
  ['baz', 42]
])
// { foo: "bar", baz: 42 }

Object.values Object.entries会忽略Symbol 属性

Object.entries({ [Symbol()]: 123, foo: 'abc' });
// [ [ 'foo', 'abc' ] ]

猜你喜欢

转载自www.cnblogs.com/sharpall/p/10021668.html
今日推荐