文享日志

ES6的一些代码示例(一)

JavaScript

发表于2017年12月24日23:10:44

更新于2018年02月06日20:47:30

0条评论 426次阅读

为函数参数设置默认值

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

log('Hello') // Hello World
log('Hello', 'China') // Hello China
log('Hello', '') // Hello

这样不用在函数体中写类似y = y | 'world'这样的语句,并且可以防止用户传入参数,但参数布尔值为false的情况。


对象解构与默认值

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()  //undefined 5

这里注意最后这个函数调用,如果函数参数那里没有 ={}将会报错。


函数参数的作用域

var x = 1;
function foo(x, y = function() { x = 2; }) {
  var x = 3;
  y();
  console.log(x);
}

foo() // 3
x // 1

var x = 1;
function foo(x, y = function() { x = 2; }) {
  x = 3;
  y();
  console.log(x);
}

foo() // 2
x // 1

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

foo() // undefined
console.log(x) // 1

        第一个函数中函数foo的参数形成一个单独作用域(函数体的父作用域)。这个作用域里面,首先声明了变量x,然后声明了变量y,y的默认值是一个匿名函数。这个匿名函数内部的变量x,指向同一个作用域的第一个参数x。函数foo内部又声明了一个内部变量x,该变量与第一个参数x由于不是同一个作用域,所以不是同一个变量,因此执行y后,内部变量x和外部全局变量x的值都没变。

        第二个函数体中的x执行的是参数作用域中的x,并为其赋值,而y函数的x也指向参数中的x。


rest参数

参数排序函数

// arguments变量的写法
function sortNumbers() {
  return Array.prototype.slice.call(arguments).sort();
}

// rest参数的写法
const sortNumbers = (...numbers) => numbers.sort();

rest参数可用来代替arugments对象。它是一个真正的数组,数组的所有方法都能用。


箭头函数

var f = v => v;

var sum = (num1, num2) => num1 + num2;

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

// 不报错(直接返回对象,需要加括号)
let getTempItem = id => ({ id: id, name: "Temp" });

//不需要返回值
let fn = () => void doesNotReturn();

使用箭头函数注意一下几点:(1)函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象。(2)不可以当作构造函数,也就是说,不可以使用new命令,否则会抛出一个错误。(3)不可以使用arguments对象,该对象在函数体内不存在。如果要用,可以用 rest 参数代替。(4)不可以使用yield命令,因此箭头函数不能用作 Generator 函数。


箭头函数可以让this指向固定化,这种特性很有利于封装回调函数。

var handler = {
  id: '123456',

  init: function() {
    document.addEventListener('click',
      event => this.doSomething(event.type), false);
  },

  doSomething: function(type) {
    console.log('Handling ' + type  + ' for ' + this.id);
  }
};

init函数中this始终指向定义时的handler对象,而不是click触发的DOM对象。this实际使用的是外层函数中的this,自己内部不含有this。除了this,以下三个变量在箭头函数之中也是不存在的,指向外层函数的对应变量:arguments、super、new.target。

详细请点击:ES6入门《函数的扩展》


函数尾调用

function f(x) {
  if (x > 0) {
    return m(x)
  }
  return n(x);
}

函数内部需要返回另一个函数调用结果时,最好写成尾调用形式。原因


转化为数组

常见的数组转化有将部署遍历器接口对象比如NodeLists,函数参数对象arguments等转化。还有类似数组的对象(包括set与map结构)也可以进行数组转化。

常见的数组转化写法有利用slice函数:

function ss(){
	let aa = {
		'0':0,
		'1':1,
		'2':2,
		'length':3
	}
	console.log(Array.prototype.slice.call(aa))		//[0,1,2]
	console.log(Array.prototype.slice.call(arguments));		//[1,2,3,4]
}
ss(1,2,3,4);

ES6中为我们又提供了两种写法,一种是利用扩展运算符  ...  , 一种是利用Array.from方法。

扩展运算符只能转化类数组对象。用法如下:

let  myarr = [...arraylike];        //arraylike是类数组对象

而Array.from方法除了能转化类数组对象,还支持将可遍历的对象转化为数组。

function ss(){
	let aa = {
		'0':0,
		'1':1,
		'2':2,
		'length':3
	}
	console.log(Array.from(aa))
	console.log(Array.from(arguments));
}
ss(1,2,3,4);

此外,Array.from函数有第二个参数,功能类似于map

function ss(){
	let aa = {
		'0':0,
		'1':1,
		'2':2,
		'length':3
	}	console.log(Array.from(aa,function(obj){
		return obj+1;
	}))		//[1,2,3]}
ss(1,2,3,4);

此外ES6还为我们提供了

Array.of函数用于将一组值转化为数组,

fill函数用于填充数组,

find和findIndex用于查找数组中的第一个符合条件的值,

includes函数用于查找数组中包含的某个值,


方法简写与属性简写

属性简写:

function ss(x,y,z){
	let aa = {x,y,z};     //相当于{x:x , y:y , z:z}
	return Object.keys(aa);
}
console.log(ss(1,2,3));		//['x','y','z']

方法简写:

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

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

实际例子:

let birth = '2000/01/01';

const Person = {

  name: '张三',

  //等同于birth: birth  birth,

  // 等同于hello: function ()...  hello() { console.log('我的名字是', this.name); }};


属性名表达式

可以将属性名以字面量的形式来书写。

1、

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

obj.hello() // hi

2、

let lastWord = 'last word';

const a = {
  'first word': 'hello',
  [lastWord]: 'world'
};

a['first word'] // "hello"
a[lastWord] // "world"
a['last word'] // "world"


Object.is方法

该方法用于比较两个值是否相等。与===类似。只是===会将+0与-0判定为相等,将NaN于NaN判定为不等。而Object.is方法不会。其余特性与===保持一致。


Object.assign方法

该方法用于为对象添加属性。Object.assign方法用于对象的合并,将源对象(source)的所有可枚举属性,复制到目标对象(target)。

const target = { a: 1 };

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

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

扩展用法:

为对象添加属性

class Point {
  constructor(x, y) {
    Object.assign(this, {x, y});        //注意这里的属性简写
  }
}
console.log(new Point('a','b'));	//[x:'a',y:'b']

为对象添加方法

Object.assign(SomeClass.prototype, {
  someMethod(arg1, arg2) {
    ···
  },
  anotherMethod() {
    ···
  }
});

// 等同于下面的写法
SomeClass.prototype.someMethod = function (arg1, arg2) {
  ···
};
SomeClass.prototype.anotherMethod = function () {
  ···
};

克隆对象

function clone(origin) {
  let originProto = Object.getPrototypeOf(origin);
  return Object.assign(Object.create(originProto), origin);
}


Super关键字

指向对象的原型对象

const proto = {
  foo: 'hello'
};

const obj = {
  find() {
    return super.foo;
  }
};

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


// 报错
const obj = {
  foo: super.foo
}

// 报错
const obj = {
  foo: () => super.foo
}

// 报错
const obj = {
  foo: function () {
    return super.foo
  }
}

super关键字表示原型对象时,只能用在对象的方法之中,用在其他地方(包括箭头函数中)都会报错。目前,只有对象方法的简写法可以让 JavaScript 引擎确认,定义的是对象的方法

Object.setPrototypeof用来设置对象原型(不推荐使用__proto__属性)。

于此对应的还有Object.getPrototypeof()用于读取对象的原型

还有Object.create()方法,生成一个继承了原型的空对象。


Symbol

Symbol是引入的第七种数据类型。用来标识独一无二的值。

对象属性除了用字符串标识,也可以用Symbol值来标识。

let mySymbol = Symbol();

// 第一种写法
let a = {};
a[mySymbol] = 'Hello!';

// 第二种写法
let a = {
  [mySymbol]: 'Hello!'};

// 第三种写法
let a = {};
Object.defineProperty(a, mySymbol, { value: 'Hello!' });
上面代码通过方括号结构和Object.defineProperty,将对象的属性名指定为一个 Symbol 值。


// 以上写法都得到同样结果
a[mySymbol]   // "Hello!",这里注意调用方法,不能用点运算符


Set结构

Set结构类似于数组,但是成员的值都是唯一的,没有重复的值。

// 例一
const set = new Set([1, 2, 3, 4, 4]);
[...set]
// [1, 2, 3, 4]

// 例二
const items = new Set([1, 2, 3, 4, 5, 5, 5, 5]);
items.size // 5

// 例三
function divs () {
  return [...document.querySelectorAll('div')];
}

const set = new Set(divs());
set.size // 56

// 类似于
divs().forEach(div => set.add(div));
set.size // 56

Set 结构的实例有以下属性。
Set.prototype.constructor:构造函数,默认就是Set函数。
Set.prototype.size:返回Set实例的成员总数。


Set 实例的方法分为两大类:操作方法(用于操作数据)和遍历方法(用于遍历成员)。

四个操作方法。
add(value):添加某个值,返回 Set 结构本身。
delete(value):删除某个值,返回一个布尔值,表示删除是否成功。
has(value):返回一个布尔值,表示该值是否为Set的成员。
clear():清除所有成员,没有返回值。


四个遍历方法.

  • keys:返回键名的遍历器        //set结构中的类数组,键名与键值一样。

  • values:返回键值的遍历器

  • entries:返回键值对的遍历器

  • forEach:使用回调函数遍历每个成员

let a = new Set([1, 2, 3]);
let b = new Set([4, 3, 2]);

// 并集
let union = new Set([...a, ...b]);
// Set {1, 2, 3, 4}

// 交集
let intersect = new Set([...a].filter(x => b.has(x)));
// set {2, 3}

// 差集
let difference = new Set([...a].filter(x => !b.has(x)));
// Set {1}


Map结构

ES6 提供了 Map 数据结构。它类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键。也就是说,Object 结构提供了“字符串—值”的对应,Map 结构提供了“值—值”的对应,是一种更完善的 Hash 结构实现。解决了获取到DOM节点设置为对象键的问题。

const m = new Map();
const o = {p: 'Hello World'};

m.set(o, 'content')               //以对象为键
m.get(o) // "content"

m.set({}, 'content')           //这里注意设置对象为键与获取的对象应为同一个。
m.get({}); // undefined

m.has(o) // true
m.delete(o) // true
m.has(o) // false

Map 的键实际上是跟内存地址绑定的,只要内存地址不一样,就视为两个键。

任何具有 Iterator 接口、且每个成员都是一个双元素的数组的数据结构都可以当作map构造函数的参数。这就是说,Set和Map都可以用来生成新的 Map。

const set = new Set([
  ['foo', 1],
  ['bar', 2]
]);
const m1 = new Map(set);
m1.get('foo') // 1

const m2 = new Map([['baz', 3]]);
const m3 = new Map(m2);
m3.get('baz') // 3












👍 3  👎 0
共有0条评论

发表新评论

提交

广告展示

腾讯云推广 阿里云推广