var person={ name:'小王', age:18, _pri:233 }
es5普通模式下后定义的会覆盖前面定义的,严格模式则会报错javascript
es6则无论什么模式都采用后面的覆盖前面的java
es5只能在对象字面量表达式申明之后再添加jquery
var dynamicVar="dyna"; var person={ } person[dynamicVar]='123'; console.log(person[dynamicVar])
es6则更符合使用场景,可在表达式内建立动态的成员名es6
var dynamicVar="dyna"; var person={ [dynamicVar]:'test' } console.log(person[dynamicVar])
es6中若是想使用表达式外面的变量名做为成员名,变量的值做为成员值,可进一步简写为设计模式
var dynamicVar="dyna"; var person={ dynamicVar, //这是一个语法糖,js引擎会解释为dynamicVar:'dyna' age:15 } console.log(person.dynamicVar)
注意:此时不能采用person[dynamicVar]方式访问,由于这句话js引擎会解释为person['dyna'],对象中没有dyna属性,确定就是undefined了数组
确定是不能够,new关键字后面必须是一个构造函数才行,对象字面量哪来的构造函数浏览器
对象属性描述符有两种主要形式:函数
数据描述符和存取描述符。数据描述符是一个具备值的属性,该值多是可写的,也可能不是可写的。this
存取描述符是由getter-setter函数对描述的属性。es5
Object.getOwnPropertyDescriptor()或getOwnPropertyDescriptor()-读取属性的描述
Object.definePropertype或Object.defineProperties----设置属性的描述
当属性是采用Object.definePropertype建立时,省略的描述符会拥有默认值,布尔值的字段的默认值都是false
。value
,get
和set
字段的默认值为undefined
。
var parent={} Object.defineProperty(parent,'name',{}) console.log(Object.getOwnPropertyDescriptor(parent,'name')) //{value: undefined, writable: false, enumerable: false, configurable: false}
当属性是直接是直接在对象中建立时,布尔值的字段默认都是true
var parent={ name:'parent' } console.log(Object.getOwnPropertyDescriptor(parent,'name')) //{value: "parent", writable: true, enumerable: true, configurable: true}
数据描述符:
configurable-是否能够删除某个属性或修改属性的描述,为true时可进行操做,若是该属性先定义为false,后续又定义为true的话会报错
Object.defineProperty(person,'name',{ configurable:false }) Object.defineProperty(person,'name',{ configurable:true })
Object.defineProperty(person,'name',{ writable:false }) person.name='小李'; //属性不可写,严格模式下会报错 console.log(person.name); //输出小王,说明上面一句无效
enumerable-属性是否可被枚举,默认为false,该属性主要是用来防范Object.keys()和for in的,也就是说该属性设置对于Object.getOwnPropertyNames()方法是无效的。
使用相应的枚举方法,输出的结果是一个数组,那么数组中元素的顺序是按什么规则组织的呢?
在es5中并无明确这一点,各个浏览器有本身的实现,es6中采用Object.keys()和for in方法时仍是没有明确,但采用Object.getOwnPropertyNames()方法枚举时,有了相应的标准:
最早放入数组中的是数值型的成员名,按升序排列;
其次是其它类型的,按添加的前后顺序排列
var obj={ 3:'我是1', 1:'我是1', b:'我是b', a:'我是a' } var names=Object.getOwnPropertyNames(obj); console.log(names) //["1","3","b","a"]
value
-
该属性对应的值。能够是任何有效的 JavaScript 值(数值,对象,函数等)。默认为 undefined
。
存取描述符:
get与set-读写成员时调用的函数,默认为undefined,若是只有get则表示属性值是只读的,只有set表示只能写。属性读写器最经常使用的场景就是在读取或写入属性前能够附带的作一些操做,达到更好的封装性。
Object.defineProperty(person,'pri',{ get:function(){ //作一些其它操做 console.log('准备获取_pri的值') return _pri; }, set:function(newValue){ _pri =newValue } }) person.pri='456'; console.log(person.pri);
Object.preventExtensions(),该方法用于阻止向对象添加成员,使用Object.isExtensible()判断对象是否可添加成员
Object.preventExtensions(person); //添加成员无效,非严格模式下什么都不会发生,严格模式下会报错 person.bankAccount='中国农业银行' //依然能够删除成员,证实了preventExtensions方法只能阻止添加方法 delete person.age; console.log(person.age) //undefined,代表删除成功了
Object.seal()用来阻止添加或删除成员,判断对象是不是密封的可采用Object.isSealed()
使用Object.freeze()方法后,除了不能添加删除成员,连成员的赋值都会失效,可是写入属性(上面set定义的)依然是有效
方法 | 禁止增长属性 | 禁止删除属性 | 禁止修改属性 |
---|---|---|---|
Object.preventExtensions() | 是 | 否 | 否 |
Object.seal() | 是 | 是 | 否 |
Object.freeze() | 是 | 是 | 是 |
Object.create(person)可产生一个具备继承特性的新对象,可是须要注意的是,父对象的引用类型成员是和子对象共享的,当子对象修改引用类型的成员时,父对象的该成员也会同步发生变化
var person={ name:'小王', age:18, _pri:233, gf:['豆得儿','张G','TFb'] } var child=Object.create(person); child.gf.splice(0,1); //跟豆得儿分手了 console.log(person.gf.length) //父类的gf也变成2了,父子共享女朋友,尼玛,太乱了
es6中的Object.setPrototypeOf(obj, prototype)方法可将已有的对象变成继承关系,其内部原理也跟Object.create同样,都是将子对象的prototype指向父对象,该方法实现的继承依然有父子对象共享了引用类型成员的问题
var person={ age:15 } var man={ } Object.setPrototypeOf(man,person) console.log(Object.getPrototypeOf(man)===person) //true console.log(man.age); //15
向一个子对象的属性赋值时,假如这个属性是从父对象继承下而且父对象中把该属性设置为不可写时,在严格模式下会报错,非严格模式下赋值不生效
var parent={ name:'parent' } Object.defineProperty(parent,'name',{ writable:false }) var child=Object.create(parent) child.name='child' //严格模式下报错,非严格模式下默认失败
向一个子对象的属性赋值时,假如这个属性是从父对象继承下来的而且父对象中设置了set描述符,则赋值时会触发set,若是未定义get,则没法获取属性值
'use strict' var parent={ name:'parent' } Object.defineProperty(parent,'name',{ set(val){ console.log('父元素的set被调用了') this._name = val } }) var child=Object.create(parent) child.name='child' //会触发父对象中的set console.log(child.name) //undefined,只有父对象的name属性描述符设置了get才能获取到值
直接在子对象中定义一个同名的成员便可
super关键字是es6新增的,它是一个指针,指向当前对象的原型,也就是父对象
var person={ age:15, testMethod(){ console.log('我是父类方法') } } var man={ //重写父类方法 testMethod(){ console.log('我是子类方法') super.testMethod(); } } Object.setPrototypeOf(man,person) man.testMethod();
须要注意的是,若是两个对象不是继承关系,使用super关键字会报错
jquery.extend是一个典行的对象混入,所谓对象混入,就是将n个对象(为了便于表述,直接叫作输入对象)组合成一个新对象,新对象具备各个输入对象的特征,这在软件设计模式中叫作装饰器模式,在es6之前须要本身实现,核心代码以下:
function mixins(target,sourceArr){ sourceArr.forEach(function(source){ Object.keys(source).forEach(function(item){ target[item] = source[item] }) }) return target } var obj1={ name:'123' } var obj2={ id:100 } var obj3={ meth(){ console.log('haha') } } var target=mixins(obj1,[obj2,obj3]) target.meth()
上面的代码实现了一个简易版的jquery.extend的浅拷贝模式(也就是deep参数为false时的功能),若是多个对象成员同名,则后面的会覆盖前面的,该代码若是要在正式环境使用,还须要加很多的判断代码,可是在es6中一句话就能够实现mixins()函数的功能。
var target=Object.assign(obj1,obj2,obj3)
须要注意的一点就是输入对象中使用了get修饰符,这时后会有一个转换,方法名变成了新对象的属性名,其值为get修饰符方法中的返回值
var obj1={ name:'123' } var obj2={ id:100 } var obj3={ get getMethod(){ return '123' }, meth(){ console.log('haha') } } var target=Object.assign(obj1,obj2,obj3) console.log(target.getMethod) //target.getMethod()会报错,缘由是发生了转换