ES6的冷知识(上)

本文详细介绍了TypeScript中的类、箭头函数和解构赋值等高级特性,包括类的访问修饰符(public、private、protected、static、abstract)、箭头函数的特例、解构赋值在数组、对象、字符串、布尔值和数值中的应用,以及解构赋值的默认值和嵌套。此外,还探讨了解构赋值的规则和注意事项。
摘要由CSDN通过智能技术生成

一、类(class)

class Man {
  constructor(name) {
    this.name = 'Kepler';
  }
  console() {
    console.log(this.name);
  }
}
const man = new Man('Kepler');
man.console(); // Kepler

1、public:可以继承、实例化

// public可以继承、实例化
class Person {
	public name: string;
	constructor(thename: string) {
		this.name = thename;
	}
}
class Jack extends Person {
	age: number;
	constructor(name: string, age: number) {
		super(name)
		this.age = age;
	}
	say() {
		console.log(`my name is ${this.name}, age ${this.age}`);
	}
}
let p1 = new Person('tom');
console.log(p1.name); // tom
let j1 = new Jack('Kepler', 10);
j1.say(); // my name is Kepler age 10

2、private 私有属性只能在基类中访问,不能在实例、派生类中访问

class Person {
	private name: string;
	constructor(thename: string) {
		this.name = thename;
	}
	sayname() {
		console.log(`my name is ${this.name}`);
	}
}
class Jack extends Person {
	age: number;
	constructor(name: string, age: number) {
		super(name)
		this.age = age;
	}
	say() {
		// 只能在Person中访问
		// console.log(`my name is ${this.name}, age ${this.age}`); // error
	}
}
let p1 = new Person('tom');
p1.sayname(); // tom
// console.log(p1.name); // tom // error 只能在Person中访问
let j1 = new Jack('Kepler', 10);
j1.sayname(); //Kepler

3、protected 受保护的,可以被继承,在派生类中可以访问,子类、父类都不能直接实例访问

class Person {
	protected name: string;
	constructor(thename: string) {
		this.name = thename;
	}
	sayname() {
		console.log(`my name is ${this.name}`);
	}
}
class Jack extends Person {
	constructor(name: string) {
		super(name)
	}
	say() {
		// 只能在Person中访问
		console.log(`my name is ${this.name}`);
	}
}
let p1 = new Person('tom');
p1.sayname(); // tom
console.log(p1.name); // tom // error 只能在Person、子类中访问
let j1 = new Jack('Kepler');
j1.say(); //Kepler
console.log(j1.name); // error 只能在Person、子类中访问

4、static 只能通过基类、子类访问,实例不能直接访问

class Person {
	static myName: string;
	constructor(name: string) {
		Person.myName = name;
	}
	sayname() {
		return Person.myName;
	}
}
class Jack extends Person {
	constructor() {
		super('Kepler');
	}
}
let p1 = new Person('tom');
p1.myName; // error Person上不存在myName属性
console.log(p1.sayname());// tom
// 在类的外部访问
console.log(Person.myName); // tom
let j1 = new Jack();
// 子类实例访问基类方法
console.log(j1.sayname()); //Kepler
j1.myName // error Jack 上不存在myName属性
// 子类访问静态属性
console.log(Jack.myName); //Kepler

5、abstract 抽象类中的抽象方法不包含具体实现,并且只能在派生类中实现

abstract class Person {
	sayname() {
		console.log('my name is sayname');
	}
	// 抽象方法不具体实现
	abstract say(): void;
}
class Jack extends Person {
	// 子类必须实现父类抽象方法
	say() {
		console.log('my name is Kepler');
	}
}
// let p1 = new Person(); // 抽象类不可以被实例化
let j1 = new Jack();
j1.sayname();
j1.say();

二、箭头函数

1、箭头函数不支持重名参数

function foo(a, a) {
    console.log(a, arguments); // 2 Arguments(2) [1, 2, callee: ƒ, Symbol(Symbol.iterator): ƒ]
}

var boo = (a, a) => { // 直接报错:Uncaught SyntaxError: Duplicate parameter name not allowed in this context 
//此上下文中不允许重复的参数名称
    console.log(a);
};
foo(1, 2);
boo(1, 2);

2、箭头函数的解析顺序相对靠前

let callback;

callback = callback || function() {}; // ok

callback = callback || () => {};      
// Uncaught SyntaxError: Malformed arrow function parameter list
//格式错误的箭头函数参数列表

callback = callback || (() => {});    // ok

三、 解构赋值

1、数组的解构赋值

/*
	对于数组的解构赋值,其实就是获得数组的元素,而我们一般情况下获取数组元素的方法是通过下标获取,例如:
		let arr = [1,2,3];
		let a = arr[0];
		let b = arr[1];
		let c = arr[2];
	而数组的解构赋值给我们提供了极其方便的获取方式,如下:
*/

	let arr0 = [1,2,3];
	let [a,b,c] = arr0;
	console.log(a,b,c);//1,2,3
	

(1)模式匹配解构赋值

let [foo, [[bar], baz]] = [1, [[2], 3]];
console.log(foo,bar,baz);//1,2,3

(2)省略解构赋值

let [,,a,,b] = [1,2,3,4,5];
console.log(a,b);//3,5

(3)含剩余参数的解构赋值

let [a,...reset] = [1,2,3,4,5];
console.log(a,reset);//1,[2,3,4,5]

其转成ES5的原理如下:

var a = 1,
    reset = [2, 3, 4, 5];
console.log(a,reset);//1,[2,3,4,5]

注意:如果剩余参数是对应的值为undefined,则赋值为[],因为找不到对应值的时候,是通过slice截取的,如下:

let [a,...reset] = [1];
console.log(a,reset);//1,[]

其转成ES5的原理如下:

var _ref = [1],
    a = _ref[0],
    reset = _ref.slice(1);
console.log(a,reset);//1,[]

(4)非数组解构成数组

一条原则:要解构成数组的前提:如果等号右边,不是数组(严格地说,不是可遍历的解构),则直接报错,例如:

let [foo] = 1;//报错
let [foo1] = false;//报错
let [foo2] = NaN;//报错
let [foo3] = undefined;//报错
let [foo4] = null;//报错

转成ES5看下原理:

var _ = 1,
	foo = _[0];//报错
var _false = false,
	foo1 = _false[0];//报错
var _NaN = NaN,
	foo2 = _NaN[0];//报错
var _undefined = undefined,
	foo3 = _undefined[0];//报错
var _ref= null;
	foo4 = _ref[0];//报错

(5)Set的解构赋值

先执行new Set()去重,然后对得到的结果进行解构
let [a,b,c] = new Set([1,2,2,3]);
console.log(a,b,c);//1,2,3

总结1:只要某种数据结构具有 Iterator 接口,都可以采用数组形式的解构赋值。

(6)解构赋值的默认值

当变量严格等于undefined的时候,会读取默认值,所谓的严格等于,就是“===”



----------


let [a,b = 'default'] = [1];
console.log(a,b);//1,'default'


----------


let [c = 'default'] = [undefined];
console.log(c);//'default'


----------


function f() {
  console.log('aaa');
}

let [x = f()] = [1];
console.log(x);//1


----------
function f() {
  console.log('aaa');//'aaa'
}

let [a,x = f()] = [1];
console.log(a,x);//1,undefined

总结2:如果不使用默认值,则不会执行默认值的函数

2、对象的解构赋值

(1)解构赋值的举例:

	let p1 = {
		"name":"Kepler",
		"age":25
	}
	let {name,age} = p1;//注意变量必须为属性名
	console.log(name,age);//"Kepler",25

其转成es5的原理则为:

	var _p1 = p1,
	name = _p1.name,
	age = _p1.age;
	console.log(name,age);//"Kepler",25

(2)解构赋值的别名

如果使用别名,则不允许再使用原有的解构出来的属性名,看以下举例则会明白:

	let p1 = {
		"name":"Kepler",
		"age":25
	}
	let {name:aliasName,age:aliasAge} = p1;//注意变量必须为属性名
	console.log(aliasName,aliasAge);//"Kepler",25
	console.log(name,age);//Uncaught ReferenceError: age is not defined

转成es5后的原理:

	var _p1 = p1,
		aliasName = _p1.name,
		aliasAge = _p1.age;
	console.log(aliasName,aliasAge);//"Kepler",25
	console.log(name,age);//所以打印name和age会报错——“Uncaught ReferenceError: age is not defined”,但是为何只报错age,不报错name呢?

只报错age,不报错name,这说明其实name是存在的,那么根据js的解析顺序,当在当前作用域name无法找到时,会向上找,直到找到window下的name,而我们打印window可以发现,其下面确实有一个name,值为“”,而其下面并没有属性叫做age,所以在这里name不报错,只报age的错。类似name的属性还有很多,比如length等。

(3)解构赋值的默认值

有些情况下,我们解构出来的值并不存在,所以需要设定一个默认值,例如:

	let obj = {
		name:"Kepler"
	};
	let {name,age} = obj;
	console.log(name,age);//"Kepler",undefined

我们可以看到当age这个属性并不存在于obj的时候,解构出来的值为undefined,那么为了避免这种尴尬的情况,我们常常会设置该属性的默认值,如下:

	let obj = {
		name:"Kepler"
	};
	let {name,age = 18} = obj;
	console.log(name,age);//"Kepler",18

当我们取出来的值不存在,即为undefined的时候,则会取默认值(假设存在默认值),ES6的默认值是使用**“变量=默认值”**的方式。
注意:只有当为undefined的时候才会取默认值,null等均不会取默认值

	let obj = {
		name:"Kepler",
		age:27,
		gender:null,//假设未知使用null
		isFat:false
	}
	let {name,age = 18,gender = 'man',isFat = true,hobbies = 'study'} = obj;
	console.log(name,age,gender,isFat,hobbies);//"Kepler",27,null,false,"study"

(4)解构赋值的省略赋值

当我们并不是需要取出所有的值的时候,其实可以省略一些变量,这就是省略赋值,如下
	let arr = [1,2,3];
	let [,,c] = arr;
	console.log(c);//3

注意:省略赋值并不存在与对象解构,因为对象解构,明确了需要的属性

	let obj = {
		name:"Kepler",
		age:27,
		gender:"man"
	}
	let {age} = obj;
	console.log(age);//27

(5)解构赋值的嵌套赋值

	let obj = {},
		arr = [];

	({ foo: obj.prop, bar: arr[0] } = { foo: 123, bar: true });
	console.log(obj,arr);//{prop:123},[true]

(6)空解构

按照之前写的,解构赋值,左边则为解构出来的属性名,当然,在这里,我们也可以不写任何属性名称,也不会又任何的语法错误,即便这样没有任何意义,如下:

({} = [true, false]);
({} = 'abc');
({} = []);

(7)解构成对象的原则

如果解构成对象,右侧不是undefined即可!

之前说过,要解构成数组,右侧必须是可迭代对象,但是如果解构成对象,右侧不是null或者undefined即可!

3、字符串的解构赋值

	const [a, b, c, d, e] = 'hello';
	console.log(a,b,c,d,e);//'h','e','l','l','o'

转成es5的原理如下:

	var _hello = 'hello',
    a = _hello[0],
    b = _hello[1],
    c = _hello[2];

	console.log(a, b, c);

注意:字符串有一个属性length,也可以被解构出来,但是要注意,解构属性一定是对象解构

	let {length} = 'hello';
	console.log(length);//5

4、布尔值和数值的解构

布尔值和数值的解构,其实就是对其包装对象的解构,取的是包装对象的属性

{toString:s} = 123;
console.log(s);//s === Number.prototype.toString

{toString:s} = true;
console.log(s);//s === Boolean.prototype.toString

总结:解构赋值的规则是:

>1. 解构成对象,只要等号右边的值不是对象或数组,就先将其转为对象。由于undefined无法转为对象,所以对它们进行解构赋值,都会报错。   
>2. 解构成数组,等号右边必须为可迭代对象

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值