Object 对象
重要通知
类目简介
基本概况
创建对象
- Object.create、new Object
Object.create()方法创建一个新对象,使用现有的对象来提供新创建的对象的__proto__ 返回一个新对象,带着指定的原型对象和属性。 如果propertiesObject参数是 null 或非原始包装对象,则抛出一个 TypeError 异常。
const obj = Object.create(
proto, // 新创建对象的原型对象
[propertiesObject] // 可选。需要传入一个对象,该对象的属性类型参照Object.defineProperties()的第二个参数。
);
let man1 = Object.create(null);
let man2 = new Object(null);
let man3 = null;
console.log(man1); // {} No properties
console.log(man2); // {} [[Prototype]]: Object
console.log(man3); // null
let Students = { sex: '女', name: '大美女', count: 100, list: [] };
let women1 = Object.create(Students);
let women2 = new Object(Students);
let women3 = Students;
console.log(women1);
console.log(women2);
console.log(women3);
// 判断该对象是否具有Students对象的相关属性
console.log(women1.hasOwnProperty('name')); // false
console.log(women2.hasOwnProperty('name')); // true
console.log(women3.hasOwnProperty('name')); // true
// 判断该对象是否在Students对象的原型链上
console.log(Students.isPrototypeOf(women1)); // true
console.log(Students.isPrototypeOf(women2)); // false
console.log(Students.isPrototypeOf(women3)); // false
创建空对象
该空对象没有继承 Object.prototype 原型链上的属性或者方法。
let student = Object.create(null);
console.log(student); // {} No properties
删除对象属性
const user = { name: "Charlie", id: 123 };
Reflect.deleteProperty(user, 'id');
console.log(user); // { name: "Charlie" }
JSON对象
JSON.stringify缺陷: https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify
console.info(JSON.parse()); // SyntaxError
console.info(JSON.parse(null)); // null
console.info(JSON.parse(undefined)); // SyntaxError
console.info(JSON.parse(0)); // 0
console.info(JSON.parse(true)); // true
console.info(JSON.parse('')); // SyntaxError
console.info(JSON.parse([])); // SyntaxError
console.info(JSON.parse({})); // SyntaxError
console.info(JSON.parse(Symbol(''))); // SyntaxError
基本属性
基本方法
属性
Object.constructor:返回 Object 的构造函数
基础方法
Object.create():创建一个新对象,使用现有的对象来提供新创建的对象的__proto__。 [object].hasOwnProperty(key):判断对象是否包含指定属性。 [obejct].isPrototypeOf(object):判断对象的原型链上是否包含指定对象。 Object.setPrototypeOf():设置一个指定的对象的原型 ( 即, 内部[[Prototype]]属性)到另一个对象或 null。[严重影响性能] Object.getPrototypeOf():返回指定对象的原型(内部[[Prototype]]属性的值)。 [object].propertyIsEnumerable(key):判断指定属性在对象中是否可枚举。 [object].toLocaleString([locales [, options]]):返回一个该对象的字符串表示。 [object].toString():返回一个表示该对象的字符串。 [object].valueOf():返回指定对象的原始值。
function Students() {}
const zhangsan = new Students();
const students = {name: '李明', principal: '李大钊', address: '北京市', history: {}};
students.sex = '男';
const dog = {};
const zoo = Object.create(dog);
console.log(students.hasOwnProperty('name')); // true
console.log(Students.prototype.isPrototypeOf(zhangsan)); // true
console.log(Object.setPrototypeOf({}, null)); // [Object: null prototype] {}
console.log(Object.getPrototypeOf(zoo) === dog); // true
console.log(students.propertyIsEnumerable('name')); // true
console.log(students.toString()); // [object Object]
console.log(students.valueOf()); // { name: '李明', principal: '李大钊', address: '北京市', history: {}, sex: '男' }
核心方法
bject.assign(target, ...sources):用于将所有可枚举属性的值从一个或多个源对象分配到目标对象。
Object.defineProperties():直接在一个对象上定义新的属性或修改现有属性,并返回该对象。
Object.defineProperty():直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。
Object.entries(object):返回一个给定对象自身可枚举属性的键值对数组
Object.keys(object):返回一个给定对象自身可枚举属性的键数组
返回对象 o 自身包含(不包括原型中)的所有可枚举属性的名称的数组。
- Object.values(object):返回一个给定对象自身可枚举属性的值数组
- Object.freeze(object):冻结对象的属性描述符
- Object.isFrozen(object):
- Object.seal(object):封闭对象的属性描述符(当前属性的值只要原来是writable可写的就可以改变)
- Object.isSealed(object):判断一个对象是否被冻结。
- Object.fromEntries(maps):把键值对列表转换为一个对象
- Object.getOwnPropertyDescriptor(object, property):返回指定对象上一个自有属性对应的属性描述符。(自有属性指的是直接赋予该对象的属性,不需要从原型链上进行查找的属性)
- Object.getOwnPropertyDescriptors(object):获取一个对象的所有自身属性的描述符
- Object.getOwnPropertyNames():返回一个由指定对象的所有自身属性的属性名(包括不可枚举属性但不包括Symbol值作为名称的属性)组成的数组
- Object.getOwnPropertySymbols(object):返回一个给定对象自身的所有 Symbol 属性的数组。
- Object.is(value1, value2):判断两个值是否为同一个值。
- Object.isExtensible(object):判断一个对象是否是可扩展
- Object.preventExtensions(object):让一个对象变的不可扩展,也就是永远不能再添加新的属性。
const students = {name: '李明', principal: '李大钊', address: '北京市', history: {}};
students[Symbol('a')] = '标志';
const entries = new Map([
['sex', '男']
]);
console.log(Object.fromEntries(entries)); // { sex: '男' }
console.log(Object.getOwnPropertySymbols(students)); // [ Symbol(a) ]
console.log(Object.getOwnPropertyNames(students)); // [ 'name', 'principal', 'address', 'history' ]
console.log(Object.getOwnPropertyDescriptors(students)); // { name: { value: '李明', writable: true, enumerable: true, configurable: true }, ... }
console.log(Object.getOwnPropertyDescriptor(students, 'name')); // { value: '李明', writable: true, enumerable: true, configurable: true }
- Object.assign(target...):用于将源对象的所有可枚举属性复制到目标对象中
如果目标对象和源对象有同名属性,或者多个源对象有同名属性,则后面的属性会覆盖前面的属性 如果该函数只有一个参数,当参数为对象时,直接返回该对象;当参数不是对象时,会先将参数转为对象然后返回 因为 null 和 undefined 不能转化为对象,所以会报错 当参数不止一个时,null 和 undefined 不放第一个,即不为目标对象时,会跳过 null 和 undefined ,不报错
- Object.is(value1, value2):用来比较两个值是否严格相等,与(===)基本类似 console.log(Object.is(1, '1')); //false
// 合并对象,后者覆盖前者键值
let Students = {name: '李明', principal: '李大钊', address: '北京市', history: {}};
console.log({...Students, name: ''}); // { name: '', principal: '李大钊', address: '北京市', history: {} }
console.log(Object.assign(Students, { name: 2 })); // { name: 2, principal: '李大钊', address: '北京市', history: {} }
Object.is('foo', 'foo'); // true
Object.is(window, window); // true
Object.is('foo', 'bar'); // false
Object.is([], []); // false
var foo = { a: 1 };
var bar = { a: 1 };
Object.is(foo, foo); // true
Object.is(foo, bar); // false
Object.is(null, null); // true
// 特例
Object.is(0, -0); // false
Object.is(0, +0); // true
Object.is(-0, -0); // true
Object.is(NaN, 0/0); // true
- Object.hasOwn()
旨在取代 Object.prototype.hasOwnProperty()。
const example = {};
Object.hasOwn(example, "prop"); // false——目标对象的属性 'prop' 未被定义
example.prop = "exists";
Object.hasOwn(example, "prop"); // true——目标对象的属性 'prop' 已被定义
example.prop = null;
Object.hasOwn(example, "prop"); // true——目标对象本身的属性存在,值为 null
example.prop = undefined;
Object.hasOwn(example, "prop"); // true——目标对象本身的属性存在,值为 undefined
- hasOwnProperty():指示对象自身属性中是否具有指定的属性(也就是,是否有指定的键)
const SCHOOL = { students: 67332 };
SCHOOL.position = '北京市海淀区西三环';
console.log(SCHOOL.hasOwnProperty('students')); // true
console.log(SCHOOL.hasOwnProperty('position')); // true
// 防止迭代的时候进入到对象的原型属性中
for (var name in object) {
if (object.hasOwnProperty(name)) {
// do something with name
}
}
- in:如果指定的属性在指定的对象或其原型链中,则in 运算符返回true。
const car = { make: 'Honda', model: 'Accord', year: 1998 };
console.log('make' in car); // true
- instanceof:检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上。
function Car(make, model, year) {
this.make = make;
this.model = model;
this.year = year;
}
const auto = new Car('Honda', 'Accord', 1998);
console.log(auto instanceof Car); // true
- Object.entries | Object.keys | Object.values
let Person = { name: '张三', sex: '男', run() { console.log('赶紧跑'); } };
// 遍历取得键与值的数组
console.log(Object.entries(Person)); // [ [ 'name', '张三' ], [ 'sex', '男' ], [ 'run', [Function: run] ] ]
for (let [key, value] of Object.entries(Person)) {
console.log(`${key}: ${value}`);
}
// 遍历取得键的数组
console.log(Object.keys(Person)); // [ 'name', 'sex', 'run' ]
for (let i of Object.keys(Person)) {
console.log(`${i}`);
}
// 遍历取得值得数组
console.log(Object.values(Person)); // [ '张三', '男', [Function: run] ]
for (let i of Object.values(Person)) {
console.log(`${i}`);
}
- Object.freeze | Object.isFrozen
//冻结一个对象。一个被冻结的对象再也不能被修改;
//冻结了一个对象则不能向这个对象添加新的属性,不能删除已有属性,不能修改该对象已有属性的可枚举性、可配置性、可写性,以及不能修改已有属性的值。
//此外,冻结一个对象后该对象的原型也不能被修改。
let student = {name: '李四', age: 37, grade: '初一', class: '二班'};
Object.freeze(student);
student.position = '三好学生';
console.log(student); // { name: '李四', age: 37, grade: '初一', class: '二班' }
// 判断该对象是否为冻结对象
console.log(Object.isFrozen(student)); //true
- Object.seal | Object.isSealed
let student = {name: '李四', age: 37, grade: '初一', class: '二班'};
//封闭一个对象,阻止添加新属性、阻止删除属性,及增删改不生效
Object.seal(student);
console.log(student); // { name: '李四', age: 37, grade: '初一', class: '二班' }
student['height'] = 100;
console.log(student); // { name: '李四', age: 37, grade: '初一', class: '二班' }
delete student.class;
console.log(student); // { name: '李四', age: 37, grade: '初一', class: '二班' }
//判断一个对象是否被密封
console.log(Object.isSealed(student)); // true
- Object.observe:非标准,禁止在生产环境使用
var obj = {};
Object.observe(obj, function (changes) {
changes.forEach(function (change) {
console.log('变化的属性: ' + change.name);
console.log('变化的类型?: ' + change.type);
console.log('旧值: ' + change.oldValue);
console.log('新值: ' + change.object[change.name]);
});
});
Object.defineProperty
缺陷:无法通过下标方式修改数组数据或者给对象新增属性
Object.defineProperty(
obj, // 要定义属性的对象
prop, // 要定义或修改的属性的名称或 Symbol
descriptor // 要定义或修改的属性描述符。
)
// descriptor
{
value: any, // [undefined] 该属性对应的值。可以是任何有效的 JavaScript 值(数值,对象,函数等)。
configurable: Boolean, // [false] 当且仅当该属性的 configurable 键值为 true 时,该属性的描述符才能够被改变,同时该属性也能从对应的对象上被删除。
enumerable: Boolean, // [false] 当且仅当该属性的 enumerable 键值为 true 时,该属性才会出现在对象的枚举属性中。
writable: Boolean, // [false] 当且仅当该属性的 writable 键值为 true 时,属性的值,也就是上面的 value,才能被赋值运算符 (en-US)改变。
get: Function, // [undefined]
set: Function, // [undefined]
}
代码示例
async function Value() {
let School = Object.create({name: '北京大学', principal: '李大钊', address: '北京市', history: {}});
Object.defineProperty(School, 'name', {
value: '张家顺',
writable: false
});
School.name = "李思凯";
console.log(School.name); //张家顺
}
// 属性描述符是否允许可写?
async function Writable() {
let School = Object.create({name: '北京大学', principal: '李大钊', address: '北京市', history: {}});
Object.defineProperty(School, 'name', {
value: '张家顺',
writable: false
});
try {
School.name = "李思凯";
} catch(e) {
console.log(e);
}
console.log(School.name); //张家顺
}
// 属性是否允许出现在对象的枚举属性中?例如在 for...in 循环和 Object.keys() 中被枚举
async function Enumerable() {
let School = Object.create({name: '北京大学', principal: '李大钊', address: '北京市', history: {}});
Object.defineProperty(School, 'name', {
value: '张家顺',
writable: true,
enumerable: false
});
for (let i in School) {
console.log(i + '=' + School[i]);
//principal=李大钊
//address=北京市
//history=[object Object]
}
//如果对象的键-值都不可枚举,那么将返回由键组成的数组
console.log(Object.keys(School));
}
// 表示对象的属性是否可以被删除?
async function Configuration() {
let School = Object.create({name: '北京大学', principal: '李大钊', address: '北京市', history: {}});
Object.defineProperty(School, 'name', {
value: '张家顺',
configuration: false
});
try {
Object.defineProperty(School, 'name', {
value: 'iu哦申达股份'
});
} catch(e) {
console.log(e);
//TypeError: Cannot redefine property: name
}
delete School.name;
console.log(School);
}
// 自定义 Setters 和 Getters
async function SettersGetters() {
let School = Object.create({name: '北京大学', principal: '李大钊', address: '北京市', history: {}});
let student = {};
Object.defineProperty(student, 'name', {
get() {
return document.getElementById('container').innerHTML;
},
set(value) {
document.getElementById('container').innerHTML = value;
}
});
student.name = "张三";
window.setTimeout(()=> {
student.name = "李斯";
}, 3000);
}
async function Structure() {
let Students = {};
Object.defineProperty(Students, 'name', {
value: '', //<String>
writable: true, //<Boolean>
enumerable: true, //<Boolean>
configuration: true, //<Boolean>
set(value) {
Students.name = value;
},
get() {
return Students;
}
});
Object.defineProperty(Student, 'name', {
value: '张家顺', //设置后不能设置get和set
writable: true, //当且仅当该属性的writable为true时,value才能被赋值运算符改变
enumerable: true, //是否可枚举?
configuration: true //可被改变或删除?
});
}
- Object.defineProperties
let Nation = {};
Object.defineProperties(Nation, {
'province': {
value: '贵州省',
writable: true,
enumerable: true,
configurable: true
},
'city': {
value: '毕节市',
writable: true,
enumerable: true,
configurable: true
},
'country': {
enumerable: true,
configurable: true,
set(value) {
console.log('县: ' + value);
},
get() {
return '大方县';
}
}
});
console.log(Nation);
console.log(Nation.country);
Nation.country = '织金县';
- Object.is(): 比较两个值是否相同。所有 NaN 值都相等(这与==和===不同)。
Object.is('foo', 'foo'); // true
Object.is(window, window); // true
Object.is('foo', 'bar'); // false
Object.is([], []); // false
var foo = { a: 1 };
var bar = { a: 1 };
Object.is(foo, foo); // true
Object.is(foo, bar); // false
Object.is(null, null); // true
// 特例
Object.is(0, -0); // false
Object.is(0, +0); // true
Object.is(-0, -0); // true
Object.is(NaN, 0/0); // true
- Set与Map的区别
set是一种关联式容器,其特性如下:
set以RBTree作为底层容器 所得元素的只有key没有value,value就是key 不允许出现键值重复 所有的元素都会被自动排序 不能通过迭代器来改变set的值,因为set的值就是键
map和set一样是关联式容器,它们的底层容器都是红黑树,区别就在于map的值不作为键,键和值是分开的。它的特性如下:
map以RBTree作为底层容器 所有元素都是键+值存在 不允许键重复 所有元素是通过键进行自动排序的 map的键是不能修改的,但是其键对应的值是可以修改的
ES6
- GitHub:https://github.com/bevacqua/es6
- 网站:http://www.runoob.com/w3cnote_genre/es6
- http://caibaojian.com/es6/
- ES6 教程:https://www.runoob.com/w3cnote/es6-tutorial.html
ES6内容
let 与 const 解构赋值 Symbol Map 与 Set Reflect 与 Proxy 字符串 数值 对象 数组 函数 迭代器 Class 类 模块 Promise 对象 Generator 函数 async 函数 for...of...
迭代器(Iterators)
生成器(generator)
/**
* 迭代器(Iterators)
* 迭代器允许每次访问数据集合的一个元素,当指针指向数据集合最后一个元素是,迭代器便会退出。它提供了 next() 函数来遍历一个序列,这个方法返回一个包含 done 和 value 属性的对象。
* ES6 中可以通过 Symbol.iterator 给对象设置默认的遍历器,无论什么时候对象需要被遍历,执行它的 @@iterator 方法便可以返回一个用于获取值的迭代器。
* 可以通过 [Symbol.iterator]() 自定义一个对象的迭代器
*/
var arr = [11,12,13];
var itr = arr[Symbol.iterator]();
itr.next(); // { value: 11, done: false }
itr.next(); // { value: 12, done: false }
itr.next(); // { value: 13, done: false }
itr.next(); // { value: undefined, done: true }
/**
* 生成器( generator)
* 语法:function *generatorName() {yield 1; ...; yield n;}
* 功能:返回一个迭代器的函数;
* obj.next().value:获取值;
* obj.next().done:判断是否已停止提供值。
*/
function *createIterator() {
yield 1;
yield 2;
yield 3;
}
let iterator = createIterator();
console.log(iterator.next().value); // 1
console.log(iterator.next().done); //false
console.log(iterator.next().value); // 3
console.log(iterator.next().value); // undefined
console.log(iterator.next().done); //true
Map与WeakMap
存储键值对
Map: https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Map
WeakMap: https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/WeakMap
Maps 和 Objects 的区别
一个 Object 的键只能是字符串或者 Symbols,但一个 Map 的键可以是[任意值]。
Map 中的键值是有序的(FIFO 原则),而添加到对象中的键则不是。
Map 的键值对个数可以从 size 属性获取,而 Object 的键值对个数只能手动计算。
Object 都有自己的原型,原型链上的键名有可能和你自己在对象上的设置的键名产生冲突。
- 劣势:增删改查的性能
当数据量不高于百万级别时,使用Map处理数据,性能会更好;
当数据量大于百万级别时,使用Object处理数据,性能会更好。
Map对象
map.clear() – 移除 Map 对象的所有键/值对 。 map.set() – 设置键值对,返回该 Map 对象。 map.get() – 返回键对应的值,如果不存在,则返回 undefined。 map.has() – 返回一个布尔值,用于判断 Map 中是否包含键对应的值。 map.delete() – 删除 Map 中的元素,删除成功返回 true,失败返回 false。 map.size – 返回 Map 对象键/值对的数量。 map.keys() - 返回一个 Iterator 对象, 包含了 Map 对象中每个元素的键 。 map.values() – 返回一个新的Iterator对象,包含了Map对象中每个元素的值 。
const map = new Map();
map.set('name', 'zhangsan'); // 设置键值
console.log(map.get('name')); // 获取键值
console.log(map.size); // 获取键长度
console.log(map.has(key)); // 查找键名
- Map 对象的操作
Map 与 Array的转换
var kvArray = [["key1", "value1"], ["key2", "value2"]];
// Map 构造函数可以将一个 二维 键值对数组转换成一个 Map 对象
var myMap = new Map(kvArray);
// 使用 Array.from 函数可以将一个 Map 对象转换成一个二维键值对数组
var outArray = Array.from(myMap);
- Map 的克隆
var myMap1 = new Map([["key1", "value1"], ["key2", "value2"]]);
var myMap2 = new Map(myMap1);
console.log(original === clone);
// 打印 false。 Map 对象构造函数生成实例,迭代出新的对象。
- Map 的合并
var first = new Map([[1, 'one'], [2, 'two'], [3, 'three'],]);
var second = new Map([[1, 'uno'], [2, 'dos']]);
// 合并两个 Map 对象时,如果有重复的键值,则后面的会覆盖前面的,对应值即 uno,dos, three
var merged = new Map([...first, ...second]);
WeakMap
作为弱引用的Map, WeakMap 中的东西垃圾回收时不考虑,使用它不用担心内存泄漏问题。且不可枚举
delete(key),has(key),get(key) 和set(key, val)
WeakMap 的所有 key 必须是对象
const wk = new WeakMap();
目的:传统对象添加了值后形成了引用,一旦不再需要这两个对象,必须手动删除这个引用,否则垃圾回收机制不会释放,造成内存溢出。
应用场景:举个例子,在一个带分页table列表里,每一列的查看功能需要向后端请求数据并显示,我们需要对这个点击操作做缓存,但又需要当翻页后或者离开页面,即列表里的数据消失时就清除掉这些缓存,方式缓存过多造成内存浪费。那么这个时候我们用weakMap就是最好的选择。
- Map与WeakMap的区别?
与Map的API区别在于没有key(),entries(),clear()和size
new Proxy
Proxy 对象用于创建一个对象的代理,从而实现基本操作的拦截和自定义(如属性查找、赋值、枚举、函数调用等)。
/**
* 资源
* https://www.runoob.com/w3cnote/es6-reflect-proxy.html
* https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Proxy
*
* 定义基本操作的自定义行为(如属性查找,赋值,枚举,函数调用等)
*/
// 结构
let proxy = new Proxy({}, {
set(Target, Property, Value) {},
get(Target, Property) {}
});
let p = new Proxy(Target, Handler);
/**
* Target:目标对象(可以是任何类型的对象,包括原生数组,函数,甚至另一个代理)
* Handler:一个对象,声明了代理 target 的指定行为, 其属性是当执行一个操作时定义代理的行为的函数。
*/
set(Target, Property, Value)
get(Target, Property)
// 示例
let proxy = new Proxy({}, {
set(Target, Property, Value) {
console.log(Target); // {}
console.log(Property); // name
console.log(Value); // Ysun
},
get(Target, Property) {
console.log(Target); // {}
console.log(Property); // name
}
});
proxy.name = 'Ysun';
proxy.name;
get(target, propKey, receiver);
let proxy = new Proxy({}, {
get(target, propKey, receiver) {
// 实现私有属性读取保护
if(propKey[0] === '_'){
throw new Erro(`Invalid attempt to get private "${propKey}"`);
}
console.log('Getting ' + propKey);
return target[propKey];
}
});
let obj = Object.create(proxy);
obj.name
// Getting name
set(target, propKey, value, receiver)
let validator = {
set: function(obj, prop, value) {
if (prop === 'age') {
if (!Number.isInteger(value)) {
throw new TypeError('The age is not an integer');
}
if (value > 200) {
throw new RangeError('The age seems invalid');
}
}
// 对于满足条件的 age 属性以及其他属性,直接保存
obj[prop] = value;
}
};
let proxy= new Proxy({}, validator)
proxy.age = 100;
proxy.age // 100
proxy.age = 'oppps' // 报错
proxy.age = 300 // 报错
// Proxy 代理对象,自定义代理对象属性与行为,即拦截对象
let Students = new Proxy({}, {
set: function(target, key, value) {
console.log('Set');
},
get: function(target, key, value) {
console.log('Get');
}
});
Students.total = 10000; //Set
console.log(Students.total); //Get
ES6
变量声明let和const
let:声明变量,并拥有块级作用域; const:声明常量,并拥有块级作用域。
const {
name,
sex: otherSex
} = object;
类class
class Block {
constructor() {
this.name = '区块链';
}
add() {
console.log('添加账本');
}
}
// 继承
class Line extends Point {
// ES6 要求,子类的构造函数必须执行一次 super 函数,否则会报错
constructor() {
// 子类 constructor 方法中必须有 super ,且必须出现在 this 之前。
super();
console.log(super); // super指向父类this
console.log(this); // this指向子类
}
}
继承常规对象
let Point = {};
Object.setPrototypeOf(Child.prototype, Point);
模板字符串
字符串格式化:${}
let name = `12345`;
console.log(`hello ${name}`);
拼接字符串:``
let template = `<div>
<span>123456</span>
</div>`
console.log(template);
函数-默认带参数
功能:定义函数时便初始化了这个参数,以便在参数没有被传递进去时使用;
function action(a = 100) {
console.log(a);
}
action(); //100
action(10); //10
箭头函数
当你的函数有且仅有一个参数的时候,是可以省略掉括号的。当你函数返回有且仅有一个表达式的时候可以省略{};
console.log([0, 2, 7].map((key) => { return key > 2 }));
console.log([0, 2, 7].map((key) => key > 2 ));
- 对象-键值对重名
function getData() {
retrun {
name,
age
}
}
- 对象-省略冒号与 function 关键字
let add = {
name: 'zhang',
get() {
console.log(this.name);
}
};
add.get(); //zhang
- 数据访问--解构
let people = {
total: 30,
boy: 12,
girl: 18,
change (x) {
return x * 1;
}
};
const {total, boy} = people;
console.log(`${total} --- ${boy}`);
const color = ['red', 'blue']
const [first, second] = color;
console.log(first); //'red'
console.log(second); //'blue'
- Spread Operator 展开运算符...
组装数组
const color = ['red', 'yellow'];
const colorful = [...color, 'green', 'pink'];
console.log(colorful); //['red', 'yellow', 'green', 'pink']
组装对象
const alp = { fist: 'a', second: 'b'};
const alphabets = {...alp, third: 'c'};
console.log(alphabets); //{ "fist": "a", "second": "b", "third": "c"}
获取数组除了前几项或者除了某几项的其他项
const number = [1,2,3,4,5]
const [first, ...rest] = number;
console.log(rest); //[2,3,4,5]
获取对象除了前几项或者除了某几项的其他项
const user = {
username: 'lux',
gender: 'female',
age: 19,
address: 'peking'
}
const {username, ...rest} = user;
console.log(rest); //{gender: "female", age: 19, address: "peking"}
组合成新的 Object,如果有重复的属性名,右边覆盖左边
const first = {
a: 1,
b: 2,
c: 6,
};
const second = {
c: 3,
d: 4
};
const total = {...first, ...second};
console.log(total); //{a: 1, b: 2, c: 3, d: 4}
- Rest 操作符
当被用于函数传参时,是一个 Rest 操作符
function foo(...args) {
console.log(args);
}
foo( 1, 2, 3, 4, 5); // [1, 2, 3, 4, 5]
- 对象词法扩展
ES6 允许声明在对象字面量时使用简写语法,来初始化属性变量和函数的定义方法,并且允许在对象属性中进行计算操作
module.exports = {
name,
add
}
- 模板语法和分隔符
let name = `hello ${name} world`;
- babel-polyfill
import Promise from 'promise-polyfill';
// To add to window 解决promise 在ie中未定义的问题
if (!window.Promise) {
window.Promise = Promise;
}
require("babel-polyfill");
import "babel-polyfill";
module.exports = {
entry: ["babel-polyfill", "./app/js"]
};
- Symbol
ES6 中提出 symbol 的目的是为了生成一个唯一的标识符,不过你访问不到这个标识符 Symbol 是一种新的数据类型,它的值是唯一的,不可变的
var sym = Symbol( "some optional description" );
console.log(typeof sym); // symbol
Object.getOwnPropertySymbols(o) 获取对象 symbol 属性
Set与WeakSet
Set 对象是一组不重复的值,重复的值将被忽略,值类型可以是原始类型和引用类型
无重复值的有序列表
- https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Set
- https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/WeakSet
创建对象
let set new Set();
基础语法
添加元素:set.add(VALUE);
删除指定序列元素:set.delete(index);
清空元素:set.clear();
查找值是否存在:set.has(VALUE);
数组去重
let array = [0,3,1,3];
let queue = new Set(array);
console.log([...queue]); //0,3,1
- 类型转换
Array
- Array 转 Set
var mySet = new Set(["value1", "value2", "value3"]);
- 用...操作符,将 Set 转 Array
var myArray = [...mySet];
String 转 Set
var mySet = new Set('hello'); // Set(4) {"h", "e", "l", "o"}
注:Set 中 toString 方法是不能将 Set 转换成 String
Set转换为Array
Array.from(array);
Array转换为Set
new Set(Array);
遍历
for (let item of queue.keys()) {
console.log();
}
for (let item of queue.values()) {
console.log();
}
for (let item of queue.entries()) {
console.log();
}
WeakSet
类似于 WeakMap,WeakSet 对象可以让你在一个集合中保存对象的弱引用,在 WeakSet 中的对象只允许出现一次
Weak Set构造器不接受基本类型数据,只接受对象。同样的可以使用可迭代的对象如数组,来作为构造器参数,来创建Weak Set
WeakSet与Set之间的差异
对于Weak Set实例,若调用了add()方法时传入了非对象的参数,则会抛出错误。如果在has()或者delete()方法中传入了非对象的参数则会返回false;
Weak Set不可迭代,因此不能用于for-of循环;
Weak Set 无法暴露出任何迭代器(例如 keys() 与 values() 方法) ,因此没有任何编程手段可用于判断 Weak Set 的内容;
Weak Set没有forEach()方法;
Weak Set没有size属性;
Set 对象
Set 对象允许你存储任何类型的唯一值,无论是原始值或者是对象引用
Set 中的特殊值:Set 对象存储的值总是唯一的,所以需要判断两个值是否恒等。有几个特殊值需要特殊对待
+0 与 -0 在存储判断唯一性的时候是恒等的,所以不重复;
undefined 与 undefined 是恒等的,所以不重复;
NaN 与 NaN 是不恒等的,但是在 Set 中只能存一个,不重复。
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);
mySet.add({a: 1, b: 2});
- Set(5) {1, 5, "some text", {…}, {…}}
- 这里体现了对象之间引用不同不恒等,即使值相同,Set 也能存储
Set 对象作用
数组去重
var mySet = new Set([1, 2, 3, 4, 4]);
[...mySet]; // [1, 2, 3, 4]
并集
var a = new Set([1, 2, 3]);
var b = new Set([4, 3, 2]);
var union = new Set([...a, ...b]); // {1, 2, 3, 4}
交集
var a = new Set([1, 2, 3]);
var b = new Set([4, 3, 2]);
var intersect = new Set([...a].filter(x => b.has(x))); // {2, 3}
差集
var a = new Set([1, 2, 3]);
var b = new Set([4, 3, 2]);
var difference = new Set([...a].filter(x => !b.has(x))); // {1}
Symbol
ES6 引入了一种新的原始数据类型 Symbol ,表示独一无二的值,最大的用法是用来定义对象的唯一属性名; Symbol 函数栈不能用 new 命令,因为 Symbol 是原始数据类型,不是对象。可以接受一个字符串作为参数,为新创建的 Symbol 提供描述,用来显示在控制台或者作为字符串的时候使用,便于区分。
- https://developer.mozilla.org/zh-CN/docs/Glossary/Symbol
作为属性名
由于每一个 Symbol 的值都是不相等的,所以 Symbol 作为对象的属性名,可以保证属性不重名。
Symbol 值作为属性名时,该属性是公有属性不是私有属性,可以在类的外部访问。 但是不会出现在 for...in 、 for...of 的循环中,也不会被 Object.keys() 、 Object.getOwnPropertyNames() 返回。 如果要读取到一个对象的 Symbol 属性,可以通过 Object.getOwnPropertySymbols() 和 Reflect.ownKeys() 取到。
let sy = Symbol("key1");
let syObject = {};
syObject[sy] = "kk";
console.log(syObject); // {Symbol(key1): "kk"}
let syObject = {};
Object.defineProperty(syObject, sy, {value: "kk"});
console.log(syObject); // {Symbol(key1): "kk"}
定义常量
const COLOR_RED = Symbol("red");
const COLOR_YELLOW = Symbol("yellow");
const COLOR_BLUE = Symbol("blue");
- Symbol.for():类似单例模式,首先会在全局搜索被登记的 Symbol 中是否有该字符串参数作为名称的 Symbol 值,如果有即返回该 Symbol 值,若没有则新建并返回一个以该字符串参数为名称的 Symbol 值,并登记在全局环境中供搜索。
let yellow = Symbol("Yellow");
let yellow1 = Symbol.for("Yellow");
yellow === yellow1; // false
let yellow2 = Symbol.for("Yellow");
yellow1 === yellow2; // true
- Symbol.keyFor():返回一个已登记的 Symbol 类型值的 key ,用来检测该字符串参数作为名称的 Symbol 值是否已被登记。
let yellow1 = Symbol.for("Yellow");
Symbol.keyFor(yellow1); // "Yellow"
Reflect
Reflect 是一个内置的对象,它提供拦截 JavaScript 操作的方法。
注意事项
Reflect不是一个函数对象,因此它是不可构造的。
ES6 中将 Object 的一些明显属于语言内部的方法移植到了 Reflect 对象上(当前某些方法会同时存在于 Object 和 Reflect 对象上),未来的新方法会只部署在 Reflect 对象上。 Reflect 对象对某些方法的返回结果进行了修改,使其更合理。 Reflect 对象使用函数的方式实现了 Object 的命令式操作。
Reflect.get(target, name, receiver)
target:目标对象 name:属性 receiver:当 target 对象中存在 name 属性的 getter 方法, getter 方法的 this 会绑定 receiver 示例
let exam = {
name: "Tom",
age: 24,
get info() {
return this.name + this.age;
}
}
console.log(Reflect.get(exam, 'name')); //Tom
// 当 target 对象中存在 name 属性的 getter 方法, getter 方法的 this 会绑定 // receiver
let receiver = {
name: "Jerry",
age: 20
}
console.log(Reflect.get(exam, 'info', receiver)); //Jerry20
Reflect.set(target, name, value, receiver)
将 target 的 name 属性设置为 value。返回值为 boolean ,true 表示修改成功,false 表示失败。当 target 为不存在的对象时,会报错。 当 target 对象中存在 name 属性 setter 方法时,setter 方法中的 this 会绑定 // receiver , 所以修改的实际上是 receiver 的属性
let exam = {
name: "Tom",
age: 24,
set info(value){
return this.age = value;
}
}
let receiver = {
age: 18
}
let result = Reflect.set(exam, 'info', 1, receiver);
console.log(result); // true
- Reflect.has()
用于查找 name 属性在 obj 对象中是否存在。返回值为 boolean
let exam = {
name: "Tom",
age: 24
}
Reflect.has(exam, 'name'); // true
Reflect.deleteProperty(obj, property)
是 delete obj[property] 的函数化,用于删除 obj 对象的 property 属性,返回值为 boolean。如果 obj 不是对象则会报错 TypeError
let exam = {
name: "Tom",
age: 24
}
Reflect.deleteProperty(exam , 'name'); // true
exam // {age: 24}
# property 不存在时,也会返回 true
Reflect.deleteProperty(exam , 'name'); // true
Reflect.construct(obj, args)
等同于 new target(...args)
function exam(name){
this.name = name;
}
Reflect.construct(exam, ['Tom']); // exam {name: "Tom"}
Reflect.getPrototypeOf(obj)
用于读取 obj 的 proto 属性。在 obj 不是对象时不会像 Object 一样把 obj 转为对象,而是会报错
class Exam{}
let obj = new Exam()
Reflect.getPrototypeOf(obj) === Exam.prototype // true
Reflect.setPrototypeOf(obj, newProto)
用于设置目标对象的 prototype
let obj ={}
Reflect.setPrototypeOf(obj, Array.prototype); // true
Reflect.apply(func, thisArg, args)
等同于 Function.prototype.apply.call(func, thisArg, args) func 表示目标函数;thisArg 表示目标函数绑定的 this 对象;args 表示目标函数调用时传入的参数列表,可以是数组或类似数组的对象。 若目标函数无法调用,会抛出 TypeError 。
Reflect.apply(Math.max, Math, [1, 3, 5, 3, 1]); // 5
Reflect.defineProperty(target, propertyKey, attributes)
于为目标对象定义属性。如果 target 不是对象,会抛出错误
let myDate= {}
Reflect.defineProperty(MyDate, 'now', {
value: () => Date.now()
}); // true
const student = {};
Reflect.defineProperty(student, "name", {value: "Mike"}); // true
student.name; // "Mike"
Reflect.getOwnPropertyDescriptor(target, propertyKey)
用于得到 target 对象的 propertyKey 属性的描述对象。在 target 不是对象时,会抛出错误表示参数非法,不会将非对象转换为对象。
var exam = {}
Reflect.defineProperty(exam, 'name', {
value: true,
enumerable: false,
})
Reflect.getOwnPropertyDescriptor(exam, 'name'); //{ configurable: false, enumerable: false, value: true, writable: false}
// propertyKey 属性在 target 对象中不存在时,返回 undefined
Reflect.getOwnPropertyDescriptor(exam, 'age') // undefined
Reflect.isExtensible(target)
用于判断 target 对象是否可扩展。返回值为 boolean 。如果 target 参数不是对象,会抛出错误。
let exam = {}
Reflect.isExtensible(exam) // true
Reflect.preventExtensions(target)
用于让 target 对象变为不可扩展。如果 target 参数不是对象,会抛出错误。
let exam = {}
Reflect.preventExtensions(exam) // true
Reflect.ownKeys()
返回对象所有的属性,不管属性是否可枚举,包括 Symbol 用于返回 target 对象的所有属性,等同于 Object.getOwnPropertyNames 与Object.getOwnPropertySymbols 之和
var exam = {
name: 1,
[Symbol.for('age')]: 4
}
let result = Reflect.ownKeys(exam); // ["name", Symbol(age)]
for (let i of result) {
console.log(i);
}
- 为不具备 Iterator 接口的对象提供遍历方法
function* objectEntries(obj) {
const propKeys = Reflect.ownKeys(obj);
for (const propKey of propKeys) {
yield [propKey, obj[propKey]];
}
}
const jane = { first: 'Jane', last: 'Doe' };
for (const [key,value] of objectEntries(jane)) {
console.log(`${key}: ${value}`);
}