对象:一些属性和方法和无序集合。
无序意味着内部没有Symbol.iterator。不可以使用for of 迭代。
对象定义
传统:
let obj = {
name:'gjq',
sayName:function(){
console.log(this.name);
}
}
ES6:
let ageKey = "age"
let jobKey = "job"
function setKey(key){
return `${key}+1`;
}
let obj = {
name:'gjq',
sayName(){
console.log(this.name); //这里值为函数的属性可以简写,但仍然属于此对象的作用域
},
[age]:27, 新增的可计算属性,[]里面首先进行js表达式求值,然后返回值作为key
[setKey(jobKey)]:15 因为[]会进行js求值,所以可以嵌入函数表达式,但是这样性能会降低
}
访问对象属性
传统:
obj.name
ES6
var prototy=name;
obj[prototy]; 1.可以通过变量访问对象
obj["na"+"me"] 2.可以通过字符串拼接访问
描述对象的属性特征:访问器属性和数据属性(这是属性具有的属性)
数据属性:
- [[configurable]]:是否可删除属性,是否可以修改特性,是否可以改为访问器属性
- [[enumerable]]:是否可枚举,即for-in。
- [[writable]]:是否可修改
- [[value]]:值
默认都为true
访问器属性:
- [[configurable]]
- [[enumerable]]
- [[get]]:获取属性值,默认undefined,可以重写getter函数
- [[set]]:设置属性值,默认undefined,重写getter函数
定义属性的方法:Object.defineProperty(obj,"属性",{writable:...})
批量操作:Object.defineProperties(obj,{"属性",{writable:...}},{})
获取属性描述的方法:Object.getOwnPropertyDescriptor(obj,"属性")
批量操作:Object.getOwnPropertyDescriptors(obj)
对象的合并(Object.assign())
Object.assgin()接受一个目标对象和多个源对象作为参数,将源对象中的可枚举属性和自有属性(Object.hasOwnProperty())浅复制到目标对象。
过程:调用源对象可复制属性的get方法,然后在目标对象中调用set方法。多个目标对象相同属性会被覆盖。
问题:因为是浅复制,所以引用类型地址相同
对象相等的判定
-
俩个对象的判断:ES6的Object.is(obj1,obj2)
多个对象:
function equal(x,...arg){ return Object.is(x,arg[0])&&(arg.length<2||equal(...arg)) }
-
递归比较俩个对象的key,value是否一致
-
JSON.stringfy()转化为字符串比较。问题:对于key顺序不同的对象结果为false
编程思路:比较是不是都是对象。比较长度是否一致,比较key是否相同,递归比较嵌套的key值
对象的解构
ES6新增对象解构语法,就是使用与对象匹配的结构来实现对象属性的赋值
let person = {
name:'gjq',
sex:"man"
}
let {name,sex="wonmen"} = person;
console.log(name); //'gjq'
console.log(sex); //"man"
解构赋值:在一个类似于对象字面量的方式中声明多个变量,实现同时执行多个赋值的操作
注意:
-
与数组的解构赋值不同,对象因为是无序的集合,赋值时会去匹配key值相同的变量进行赋值,而数组则是按顺序赋值。
-
赋值的过程实际是:先找到同名属性,然后将值赋给对应的变量,真正被赋值的是后者
let {name:baz,sex:bar}={name:'gjq',sex:"man"} name:name is not defined; baz:'gjq' sex:sex is not defined; bar:"man" 真正被赋值的变量是baz和bar,而不是key
-
对于匹配不到的属性,值为默认值||undefined(设置默认值时应该用sex="man",而不是sex:"man")
创建对象的方式
new Object
let obj = new Object();
obj.name = 'gjq';
obj.age = 15;
obj.sayName = function(){
console.log(this.name)
}
对象字面量
let obj1 = {
name:'gjq',
age:15,
sayName:function(){
console.log(this.name);
}
}
工厂函数
function person(name,age){
let o = new Object();
o.name = name;
o.age = age;
o.sayName = function(){
console.log(this.name)
}
return o;
}
构造函数模式
function Person(name,age){
this.name = name;
this.age= age;
this.sayName = function(){
console.log(this.name);
}
}
问题 : 个对象创建时都要创建一个新的sayName,浪费内存
初步解决 : 将sayName、放在全局环境中,这样所有的对象共享全局环境的那个sayName。
问题 : 污染了全局环境,没有体现封装性。
原型模式
function Person(){}
Person.prototype = {
constructor:Person,
name:'gjq', //属性值是死的
age:15,
sayName:function(){
console.log(this.name)
},
friends:['rcw,wzh'] //问题所在,所有实例共享引用类型的内存地址
}
组合使用原型和构造函数
function Person(name,age){
this.name = name;
this.age= age;
this.friends = ['rcw,wzh']; //引用类型放在构造函数体内
}
Person.prototype = {
constructor:Person,
sayName:function(){ //公有的属性和方法放在原型中
console.log(this.name);
}
}
原型使用注意点:当改变了构造函数的prototype属性时,以前创建的对象仍然使用以前的prototype,新创建的对象使用新的prototype