ECMAScript
Posted coderlin_
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ECMAScript相关的知识,希望对你有一定的参考价值。
ECMAScript
ECMAScirpt与js的关系
- ECMAScript是一个脚本语言规范,通常看作是js的标准规范,但是js其实是ES的扩展语言。
- 在ES钟,只是提供了最基本的语法,停留在语言层面。而js是实现了ES的标准,并且在基础之上实现了其他的功能。
- 在浏览器中,js = ES + webApis(BOM,DOM)
- 在node中,js = ES+nodeApis(fs,net,etc…)
模版函数
const name = 'test';
const myFuntag = (strings, name) =>
console.log('strings', strings);
console.log('name', name);
return 123123;
;
const test1 = myFuntag`hello $name!`;
console.log('test1', test1);
//
strings [ 'hello ', '!' ]
name test
test1 123123
在模版字符串前面的函数,可以用来加强模版字符串的功能。
他接受参数个数都模版字符串中的变量个数决定。
- 第一个参数,是以变量分割的,如上,name分割了hello和!,打印出来就是[hello !]。
- 其他参数就是变量的参数,并且,他的返回值会作为模版字符串的返回值。
Proxy
对象属性读写使用Object.defineProperty进行属性的读取拦截。
proxy对整个对象做代理。
const person =
name: 'test',
age: 20,
;
const personProxy = new Proxy(person,
get(target, property)
return target[property];
,
set(target, property, value)
if (property === 'age')
target[property] = value > 20 ? 20 : value;
else
target[property] = value;
,
);
console.log(personProxy.age);
personProxy.age = 19;
console.log(personProxy.age);
personProxy.age = 23;
console.log(personProxy.age);
Proxy vs Object.defineproperty
- defineproperty只能监听对象属性的读写操作。
- Proxy能够监视到更多对象操作
const personProxy = new Proxy(person,
get(target, property)
return target[property];
,
set(target, property, value)
if (property === 'age')
target[property] = value > 20 ? 20 : value;
else
target[property] = value;
,
// 删除监听
deleteProperty(target, property)
if (property === 'age')
console.log('age不能删除');
delete target[property];
,
has() , //监听in
defineProperty() , // Object.defineProperty触发
setPrototypeOf() , // Object.setPrototypeOf触发
...
);
delete personProxy.age; //age不能删除
- proxy更好的支持数组对象的监视。
像vue2监听数组的时候,比如往数组添加属性等等,采用的是重写数组的操作方法
const list = [];
const proxyList = new Proxy(list,
set(target, property, value)
console.log(target, property, value);
target[property] = value;
return true; //表示设置成功
,
);
proxyList.push(100); // 调用两次set,第一次是增加值,第二次是设置length为1
console.log(proxyList);
// 打印
[] 0 100
[ 100 ] length 1
[ 100 ]
- Proxy以非侵入的方式监管整个对象的读写。一个定义好的对象不需要对对象做任何操作,就可以监视到他内部的读写。Object.defineProperty()就需要用特定的方式,单独去定义对象当中那些需要被监视的属性,对于一个已经存在的对象,需要对它做很多额外的操作
Reflect(静态类)
- 统一的对象操作API
- Reflect成员方法就是Proxy处理对象的默认实现。
const person =
name: 'test',
age: 20,
;
const personProxy = new Proxy(person, );
const personProxy1 = new Proxy(person,
get(target, property)
return Reflect.get(target, property);
,
);
如上,new Proxy的默认就是调用了Relfect上面的方法。
为什么要有Reflect?
- 统一提供一套用于操作对象的API
console.log('name' in person);
console.log(delete person.name);
console.log(proson['age']);
console.log(Reflect.get('age'));
console.log(Reflect.has('name'));
console.log(Reflect.deleteProperty('name'));
功能一样的,仔细比对,下面的明显合理一点。
Symbol
- Symbol出现之前,对象的键只支持字符串,那么字符串就可能导致键一样从而改写了原来的内容
- 对象的键支持Symbol,他是一个独一无二的值,使用Symbol之后不会出现重复现象。
- 对象私有成员,外界若无法访问到Symbol的具体地址,那么将无法真正获取对象上该属性的值。如
const test = Symbol('test');
const person =
name: 'test',
age: 20,
[test]: 10,
;
console.log(person[Symbol('test')]); // undefined
const s1 = Symbol('foo');
const s2 = Symbol('foo');
console.log(s1 === s2); // false
const s1 = Symbol('foo');
const s2 = Symbol('foo');
console.log(s1 === s2); // true
Symbol.for维护了一个全局注册表
在Symbol类型当中还提供了很多内置的Symbol常量,用来作为内部方法的标识。这些标识符可以让自定义对象实现一些js当中内置的接口
console.log(Symbol.iterator)
console.log(Symbol.hasInstance)
如定义对象的toString
const obj =
//如果使用字符串标签去添加标识符,有可能会和内部的成员产生重复,ECMAScript要求我们使用Symbol去实现这个的一个接口
[Symbol.toStringTag]:"xObject"
console.log(obj.toString())//[object xObject]
Symbol.Iterator接口
- ES2015提出了一种Iterable接口,可迭代的。
- 实现了Symbol.Iterator接口的对象,都可以被for of遍历
如
const obj =
a: 1,
b: 2,
c: 3,
[Symbol.iterator]()
let index = 0;
const arr = Object.keys(obj);
return
next()
return done: index > arr.length, value: obj[arr[index++]] ; // 迭代结果
,
;
,
;
for (let i of obj)
console.log('i-------', i);
// 打印结果
i------- 1
i------- 2
i------- 3
i------- undefined
迭代器模式
const todos =
life: ['吃饭', '睡觉'],
learn: ['js', 'vue'],
work: ['摸鱼'],
;
for (let a of todos.learn)
for (let a of todos.life)
for (let a of todos.work)
想要遍历todos的所有内容必须事先知道它的属性方法,不够合理,
改造
const todos =
life: ['吃饭', '睡觉'],
learn: ['js', 'vue'],
work: ['摸鱼'],
each(callback)
const all = [...this.learn, ...this.life, ...this.work];
for (const item of all)
callback(item);
,
;
todos.each((item)=>)
对外暴露一个each方法,就可以遍历到所有属性。
使用迭代器模式:
const todos =
life: ['吃饭', '睡觉'],
learn: ['js', 'vue'],
work: ['摸鱼'],
each(callback)
const all = [...this.learn, ...this.life, ...this.work];
for (const item of all)
callback(item);
,
[Symbol.iterator]()
const all = [...this.learn, ...this.life, ...this.work];
let index = 0;
return
next()
return
value: all[index++],
done: index > all.length,
;
,
;
,
;
for (let i of todos)
console.log(i);
//结果
js
vue
吃饭
睡觉
摸鱼
外部使用的时候直接使用for of就行。迭代器模式的关键就是对外统一遍历的接口,让外部不用关心数据的结构。each方法只适用于这个对象,而Symbol.iterator是在语言层面上的,适用于所有数据结构。
使用生成器实现Symbol.iterator
//实现iterator
const todos1 =
life: ['吃饭', '睡觉'],
learn: ['js', 'vue'],
work: ['摸鱼'],
[Symbol.iterator]: function* ()
const all = [...this.learn, ...this.life, ...this.work];
for (const item of all)
yield item;
,
;
for (const item of todos1)
console.log(item);
强类型与弱类型
- 强类型语言不允许任意的隐士类型转换
- 弱类型则允许。
静态类型与动态类型
- 静态类型,一个变量声明的时候类型就已经确定了,并且之后不能修改。
- 动态类型,一个变量只有运行的时候才知道是什么类型,并且之后可以任意更高。
以上是关于ECMAScript的主要内容,如果未能解决你的问题,请参考以下文章