Map对象
Map对象 和 Objects 的区别
Map 对象保存键值对。任何值(对象或者原始值) 都可以作为一个键或一个值。
一个 Object 的键只能是字符串或者 Symbols,但一个 Map 的键可以是任意值。
get 和 set方法
const print = console.log
var map1 = new Map()
var keyString = 'a string'
map1.set(keyString, "和键'a string'关联的值")
const a1 = map1.get(keyString) // "和键'a string'关联的值"
const a2 = map1.get('a string') // "和键'a string'关联的值"
//print('a1-2:', a1, a2)
Set对象
Set 对象允许你存储任何类型的唯一值,无论是原始值或者是对象引用。
Set 对象存储的值总是唯一的,所以需要判断两个值是否恒等。
add方法
let mySet = new Set()
mySet.add(1) // Set(1) {1}
mySet.add(5) // Set(2) {1, 5}
mySet.add(5) // Set(2) {1, 5} 这里体现了值的唯一性
mySet.add('some text') // Set(3) {1, 5, "some text"} 这里体现了类型的多样性
var o = { a: 1, b: 2 }
mySet.add(o) //Set(4) { 1, 5, 'some text', { a: 1, b: 2 } }
//console.log(mySet)
mySet.add({ a: 1, b: 2 }) // Set(5) { 1, 5, 'some text', { a: 1, b: 2 }, { a: 1, b: 2 } }
// 这里体现了对象之间引用不同不恒等,即使值相同,Set 也能存储
解构
//数组解构
let [a, b, c] = [1, 2, 3] // a = 1 b = 2 c = 3
let [e, , g] = [1, 2, 3] // e = 1 g = 3
//对象解构
let { foo, bar } = { foo: 'aaa', bar: 'bbb' } // foo = 'aaa' bar = 'bbb'
//注意下面不是逗号,是冒号
let { x: y } = { x: 'x1' } // y='x1'
let { v: w } = { vv: 'v1' } // undefined
// console.log(y) //打印x会报错 x1
// console.log(w) //打印v会报错 undefined
Proxy
可以对目标对象的读取、函数调用等操作进行拦截,然后进行操作处理。它不直接操作对象,而是像代理模式,通过对象的代理对象进行操作,在进行这些操作时,可以添加一些需要的额外操作。
一个Proxy对象由两个部分组成,构造函数生成实例需target目标对象 和 handler对象(声明代理target的指定行为)
get 、 set、 construct、 has
let target = {
name: 'Tom',
age: 20
}
let handler = {
get: (target, key) => {
console.log('get: ' + key)
return target[key] // 不是target.key
},
set: (target, key, value) => {
console.log('set: ' + key)
target[key] = value
}
}
let proxy = new Proxy(target, handler)
//console.log(target, proxy) //2个相等 { name: 'Tom', age: 20 } { name: 'Tom', age: 20 }
proxy.name // 实际执行 handler.get //打印get: name
proxy.age = 25 // 实际执行 handler.set //打印set: age
通过构造函数新建实例时其实是对目标对象进行了浅拷贝,因此目标对象与代理对象会互相影响
Reflect
可以用于获取目标对象的行为,它与 Object 类似,但是更易读,
为操作对象提供了一种更优雅的方式。它的方法与 Proxy 是对应的
get 、 set、 construct、 has
//Reflect.get(target, name, receiver)
let exam = {
name: 'Tom',
age: 24,
get info() {
return this.name + this.age
}
}
const res = Reflect.get(exam, 'name')
//console.log('res:', res) //res: Tom
// 当target对象中存在name属性的getter方法,getter方法的this会绑定,参数3:obj
let obj = {
name: 'Jerry',
age: 20
}
const r0 = Reflect.get(exam, 'info') // Tom24
const r1 = Reflect.get(exam, 'info', obj) // Jerry20
// 当 name 为不存在于 target 对象的属性时,返回 undefined
const r2 = Reflect.get(exam, 'birth') // undefined
//const r3 = Reflect.get(1, 'name') // 会报错,因为target不是对象
字符串
includes和模板字符串
const print = console.log
let string = 'apple,banana,orange'
print(string.includes('banana')) // true 判断是否找到参数字符串
print(string.startsWith('apple')) // true 判断参数字符串是否在原字符串的头部
print(string.endsWith('apple')) // false 判断参数字符串是否在原字符串的尾部
这三个方法只返回布尔值,如果需要知道子串的位置,还是得用 indexOf
模板字符串:字符串插入变量、表达式、调用函数
let namea = 'Mike'
let age = 27
let info = `My Name is ${namea},I am ${age + 1} years old next year.`
function f() {
return 'have fun!'
}
let string2 = `Game start,${f()}`
console.log(string2) // Game start,have fun!
对象object
Object.assign() 与 Object.is()
let age = { age: 15, city: 'beijing' }
let names = { names: 'Amy', age: 18 }
let person2 = { ...age, ...names } //{ age: 18, city: 'beijing', names: 'Amy' } 同名的属性将被覆盖掉
Object.assign(target, source_1, ···)
用于将源对象的所有可枚举属性复制到目标对象中。
let target = { a: 1 }
let object2 = { b: 2 }
let object3 = { c: 3 }
Object.assign(target, object2, object3) // 第一个参数是目标对象,后面的参数是源对象
console.log(target) //{ a: 1, b: 2, c: 3 }
target = { ...target, ...object2, ...object3 }
console.log(target) //{ a: 1, b: 2, c: 3 }
//如果该函数只有一个参数,当参数为对象时,直接返回该对象;
//当参数不是对象时,会先将参数转为对象然后返回。
const objx = Object.assign(3)
console.log(objx, typeof objx) // [Number: 3] object
Object.is(value1, value2) 用来比较两个值是否严格相等,与(===)基本类似。
Object.is('q', 'q') // true
Object.is(1, 1) // true
Object.is([1], [1]) // false
Object.is({ q: 1 }, { q: 1 }) // false
数组
Array.of()、Array.from()
console.log(Array.of(1, 2, 3, 4)) // [1, 2, 3, 4]
console.log(Array.of(1, '2', true)) // [1, '2', true] // 参数值可为不同类型
console.log(Array.of()) // [] // 参数为空时返回空数组
Array.from() 将类数组对象或可迭代对象转化为数组。
console.log(Array.from([1, 2])) // [1, 2] 参数为数组,返回与原数组一样的数组
console.log(Array.from([1, , 3])) // [1, undefined, 3] 参数含空位
//第2可选参数:map 函数、第3可选参数:thisArg(用于指定 map 函数执行时的 this 对象)
let map = {
do: (n) => {
return n * 2
}
}
let arrayLike = [3, 4, 5]
const res = Array.from(
arrayLike,
function (n) {
return this.do(n)
},
map
)
console.log(res) // [ 6, 8, 10 ]
类"数组对象" 转数组
一个类数组对象必须含有 length 属性,且元素属性名必须是数值或者可转换为数值的字符。
let arr = Array.from({
0: '1',
1: '2',
2: 3,
length: 3
})
console.log(arr) // ['1', '2', 3]
map转数组、set转数组、字符串转数组
let map = new Map()
map.set('key0', 'value0')
map.set('key1', 'value1')
console.log(Array.from(map)) // [['key0', 'value0'],['key1', 'value1']]
let arr = [1, 2, 3]
let set = new Set(arr)
console.log(Array.from(set)) // [1, 2, 3]
let str = 'abc'
console.log(Array.from(str)) // ["a", "b", "c"]
函数
箭头函数有几个使用注意点。
(1)箭头函数没有自己的this对象
(2)不可以当作构造函数,也就是说,不可以对箭头函数使用new命令,否则会抛出一个错误
(3)不可以使用arguments对象,该对象在函数体内不存在。如果要用,可以用 rest 参数代替
(4)不可以使用yield命令,因此箭头函数不能用作 Generator 函数
对于普通函数来说,内部的this指向函数运行时所在的对象
var Person = {
age: 18,
sayHello: function (v) {
//由于setTimeout异步,函数运行时所在的对象是setTimeout
setTimeout(function () {
console.log('this:', this) //this: Timeout {...}
console.log('age:', this.age) //age: undefined
}, 1000)
return v * 2
}
}
console.log('x:', Person.sayHello(2)) // x:4
箭头函数则不一样,它没有自己的this对象,内部的this就是定义时上层作用域中的this
var Person1 = {
age: 18,
sayHello: function (v) {
//箭头函数上层作用域中的this,就是Person1对象
setTimeout(() => {
console.log('this:', this) // this: { age: 18, sayHello: [Function: sayHello] }
console.log('age:', this.age) //age: 18
}, 1000)
return v * 2
}
}
console.log('y:', Person1.sayHello(2)) // y:4
箭头函数不可以当作构造函数
function fun1(a, b) {
console.log('new 函数,则函数是构造函数:', a + b)
}
const a1 = new fun1(1, 2)
const fun2 = (a, b) => {
console.log('new 箭头函数,会报错:', a + b)
}
//const a2 = new fun2(1, 2) //会报错
class类
ES6 的类,完全可以看作构造函数的另一种写法。
JS是用构造函数来充当”类“,TS类才是类似其他后端语言的类
class Point {
// ...
}
console.log(typeof Point) // "function"
console.log(Point === Point.prototype.constructor) // true
下面代码中的三个方法,其实都是定义在Point.prototype上面。
class Point2 {
constructor() {}
toString() {}
toValue() {}
}
// 等同于
Point2.prototype = {
constructor() {},
toString() {},
toValue() {}
}
封装与继承
get和set
class Example {
constructor(a, b) {
console.log('构造函数')
this.a = a // 实例化时调用 set 方法
this.b = b
}
// get 函数名 和 属性同名 才会触发
get a() {
console.log('get-a')
//return this.a //这样也会不断循环,
return this._a
}
get b() {
console.log('get-b')
return this.b
}
set a(v) {
console.log('set-a:', v)
//this.a = a //自身递归调用,不断循环,最终导致 RangeError
this._a = v
}
set b(v) {
console.log('set-b:', v)
}
}
let exam = new Example(1, 2) //构造函数 set-a: 1 set-b: 2
console.log(exam.a) //get-a 1
class Father1 {
constructor() {}
get a() {
return this._a
}
set a(v) {
this._a = v
}
}
class Child1 extends Father1 {
constructor() {
super()
}
}
let test1 = new Child1()
test1.a = 2
console.log(test1.a) // 2
模块
ES6 的模块化分为导出(export) @与导入(import)两个模块
模块中可以导入和导出各种类型的变量,如函数,对象,字符串,数字,布尔值,类等
每个模块都有自己的上下文,每一个模块内声明的变量都是局部变量,不会污染全局作用域
每一个模块只加载一次(是单例的), 若再去加载同目录下同文件,直接从内存中读取
导出的函数声明与类声明必须要有名称(export default 命令另外考虑)
export 命令可以出现在模块的任何位置,但必需处于模块顶层
Generator 函数
ES6新引入了Generator函数,可以通过yield关键字,把函数的执行流挂起,
为改变执行流程提供了可能,从而为异步编程提供解决方案。 基本用法
Generator 有两个区分于普通函数的部分:
一是在 function 后面,函数名之前有个 *
函数内部有 yield 表达式。
其中 * 用来表示函数为 Generator 函数,yield 用来定义函数内部的状态。
function* func() {
console.log('one')
yield '1'
console.log('two')
yield '2'
console.log('three')
return '3'
}
//调用 Generator 函数和调用普通函数一样,在函数名后面加上()即可,
//但是 Generator 函数不会像普通函数一样立即执行,而是返回一个指向内部状态对象的指针
const f = func() //不会立即执行,返回指针
console.log(f.next()) //one { value: '1', done: false }
console.log(f.next()) //two { value: '2', done: false }
console.log(f.next()) //three { value: '3', done: true }
console.log(f.next()) // { value: undefined, done: true }
console.log(f.next()) // { value: undefined, done: true }
//如果执行第三步时,没有 return 语句的话,就直接返回 { value: undefined, done: true }
网友评论