对象字面量的扩展方法
1属性初始值的简写
案例一 (在e5版本)
function createPerson(name,age){
return {
name:name,
age:age
}
}
//案例二 (es6版本) 在此代码中函数创建了一个对象,其属性名与函数的参数相同,在返回的结果中,name和age重复了两遍,当对象的属性和本地变量名称一致时,简单的只写属性名即可
function createPerson(name,age){
return{
name,
age
}
}
2.对象方法的简写语法
es5 在es5中,如果为对象添加方法,必须通过指定的名称并完整的定义函数,类似以下案例
var person={
name:'Xiaoming',
sayName:function(){
console.log(this.name)
}
}
在es6中,语法更简洁,消除了冒号和function关键字
var person={
name:'Xiaoxi',
sayName(){
console.log(this.name)
}
}
//在这个案例中person.sayName.name的值为‘sayName’
console.log(person.sayName.name);
3.可计算属性名
//在es5中,如果想通过计算得到属性名,就需要用方括号来代替点的记法有些包括某些字符串字面量会作为标识符会出错,其和变量放到方括号是被允许的
//案例一
var person={
}
person["frist name"]="Xiaoxi";
person['lastname']="XiaoDong";
console.log( person["frist name"],person['lastname'])//Xiaoxi XiaoDong
在es6中,可在对象字面量中使用可计算属性名称,其语法与引用对象实例的可计算属性名称相同,
也是使用方括号
//案例一
let lastname='last name'
let person={
'frist name':'Xiaoxi',
[lastname]:'XiaoDong'
}
console.log(person['frist name']);//Xiaoxi
console.log(person[lastname]);//XiaoDong
//案例二
var suffix=' name';
var person1={
['first'+suffix]:'XiaoXi',
['last'+suffix]:'XiaoDong'
}
console.log(person1['first name']);
console.log(person1['last name'])
4.新增方法
4.1 Object.is()
//es5 之前我们比较值的时候喜欢用相等运算符(==)或全等运算符(===),许多开发者喜欢用全等运算符,从而避免在比较时强制类型转换的行为。
//即使全等运算符也不完准确,举个例子,+0和-0在js引擎中被表示为两个完全不同的实体,如果使用===对两者进行比较,得到的结果、是两者相等
//同一,NaN===NaN的返回值为false,需要使isNaN()方法才可以正确检测NaN
//es6引入了Object.is()方法来弥补全等运算符的不准确运算
//案例一
console.log(+0===-0);//true
console.log(+0==-0);//true
console.log(Object.is(+0,-0));//false
console.log(NaN==NaN);//false
console.log(NaN===NaN);//false
console.log(Object.is(NaN,NaN));//true
console.log(5==5);//true
console.log(5=='5');//true
console.log(5===5);//true
console.log(5==='5');//false
console.log(Object.is(5,5));//true
console.log(Object.is(5,'5'));//false
//Object
4.2 Object.assign();方法
//混合(Minxin)是js中实现对象组合最流行的一种模式,在一个mixin方法中,一个对象接收来自另一个对象的属性和方法,
//许多js库中都有类似的mixin方法,下面的案例是遍历supplier的自有属性并复制到receiver里(此处为浅复制);
//此时receiver不通过继承可以得到新的属性
//案例一
function Minxin(receiver,supplier){
Object.keys(supplier).forEach(function(key){
receiver[key]=supplier[key]
})
return receiver;
}
//案例二
//在这段代码中,myObject接收EventTarget.prototype对象的所有行为,从而使myObject可以分别通过emit()方法发布事件;
//mixin方法类似于Object.assign()
function EventTarget(){
}
EventTarget.prototype={
constructor:EventTarget,
emit:function(){},
on:function(){}
}
var myObject={};
mixin(myObject,EventTarget.prototype);
myObject.emit('somethingChanged');
//语法Object.assign(target, …sources) target: 目标对象,sources: 源对象
//用于将所有可枚举属性的值从一个或多个源对象复制到目标对象,Object.assign()方法可以接受任意数量的源对象,并按照指定的顺序将属性复制到接收对象中。
//如果多个源对象具有同名属性,则排位靠后的源对象会覆盖排位靠前的
//案例一
const target={a:'a',b:'b'};
const source={b:'b1',c:'c'};
Object.assign(target, source);
console.log(target)//{a: "a", b: "b1",c: "c"}
5自有属性枚举顺序
//es5中未定义对象属性的枚举顺序,由js厂商自行决定。然而,es6严格规定了对象的自有属性被枚举时返回顺序,这会影响到
//Object.getOwnPropertyNames()方法和Reflect.ownkeys返回属性的方式,Object.assign()方法数据属性的顺序也将之改变
//自有属性的规则是:
//1.所有的数字键按升序的排序
//2.所有字符串键按照它们被加入对象的顺序排序
//3.所有的symbol键按照它们被加入对象的顺序排序
//由于并非所有的厂商都遵循相同的实现方式因此仍未明确指定枚举顺序;二
//Object.keys()方法和 JSON.stringify()方法都指明和for-in使用形容的枚举顺序,因此他们的枚举顺序目前也不明晰
var obj={
a:1,
0:1,
c:1,
2:1,
b:1,
1:1
}
console.log(Object.getOwnPropertyNames(obj).join(','));//0,1,2,a,c,b
6.改变对象的原型
//Object.setPrototypeOf()来设置对象原型,它接受两个参数:被改变原型的对象替代第一个参数指定原型的对象
//案例一
//这段代码中定义了两个基对象:person和dog;二者都有getGreeting()方法,都返回一个字符串。friend对象先继承person对象,调用getGreeting()
//方法输出'hello';当原型被变更为dog对象时,原先与person对象的关联被解除,调用friend.getGreeting()方法输出‘Woof’;
//对象原型的真是值被存储在内部专用属性[Prototype]中,调用Object.getPrototypeOf()方法返回储存的值,调用
//Object.setPrototypeOf()方法改变其中的值。然而,这不是操作Prototype的唯一方法
let person={
getGreeting(){
return 'Hello'
}
}
let dog={
getGreeting(){
return 'Woof'
}
}
let friend=Object.create(person);
console.log(friend.getGreeting());//hello
console.log(Object.getPrototypeOf(friend)===person);//true
//将原型设置为dog
Object.setPrototypeOf(friend,dog);
console.log(friend.getGreeting());//Woof
console.log(Object.getPrototypeOf(friend)===dog);true
7.简化原型访问的Super引用 es6引入了Super引用特性,使用它可以更便捷地访问对象原型
//案例二 在这个案例中,friend对象的getGreeting()方法调用了同名的原型方法。Object.getPrototypeOf()方法可以确保正确的原型
//后面的.call(this)可以确保正确设置原型方法中的this
let person={
getGreeting(){
return 'Hello';
}
}
let dog={
getGreeting(){
return "Woof"
}
}
let friend={
getGreeting(){
return Object.getPrototypeOf(this).getGreeting.call(this)+'Hi';
}
}
Object.setPrototypeOf(friend,person);
console.log(friend.getGreeting());
console.log(Object.getPrototypeOf(friend)==person);//true
Object.setPrototypeOf(friend,dog);
console.log(friend.getGreeting());
console.log(Object.getPrototypeOf(friend)===dog)
//要准确记得如何使用Object.getPrototypeOf()方法和.call(this)方法来调用原型上的方法比较复杂,es6的Super引用相当于指向对象原型的指针
//实际上也就是Object.getPrototypeOf(this)的值,我们可以将这个案例简化下
//案例三
//super.getGreeting()相当于 Object.getPrototypeOf(this).getGreeting.call(this)
let person={
getGreeting(){
return 'Hello';
}
}
let dog={
getGreeting(){
return "Woof"
}
}
let friend={
getGreeting(){
return super.getGreeting()+'Hi';
}
}
Object.setPrototypeOf(friend,person);
console.log(friend.getGreeting());
console.log(Object.getPrototypeOf(friend)==person);//true
Object.setPrototypeOf(friend,dog);
console.log(friend.getGreeting());
console.log(Object.getPrototypeOf(friend)===dog);
//通过Super引用对象原型上所有其他的方法。当然,必须要在使用简写方法的对象中使用Super引用,但如果在其他方法声明中使用会到导致语法错误
let friend={
getGreeting:function(){
return super.getGreeting();//Uncaught SyntaxError: 'super' keyword unexpected here
}
}
//在es5中在这个案例中,reactive.getGreeting()会报程序上的错误,this是reactive的原型是friend对象,当执行reactive的getGreeting方法时
//会调用friend的getGreeting()方法,而此时的this是reactive ,而Object.getPrototypeOf(this)返回的时friend对象,所以进入递归调用时触发栈溢出错
let person={
getGreeting(){
return 'Hello'
}
}
let friend={
getGreeting(){
return Object.getPrototypeOf(this).getGreeting().call(this)+'Hi'
}
}
Object.setPrototypeOf(friend,person);
let reactive=Object.create(friend);
console.log(person.getGreeting());
console.log(friend.getGreeting());
console.log(reactive.getGreeting());//Object.getPrototypeOf(...).getGreeting(...).call is not a function at Object.getGreeting
//在es6中这个问题便可以迎刃而解,super引用不是动态变化的,她总是指向正确的对象,在这个事例中,
//无论有多少方法继承了getGreeting,super.getGreeting()始终指向person.getGreeting()
let person={
getGreeting(){
return 'Hello'
}
}
let friend={
getGreeting(){
return super.getGreeting()+"Hi"
}
}
Object.setPrototypeOf(friend,person);
let reactive=Object.create(friend);
console.log(person.getGreeting());
console.log(friend.getGreeting());
console.log(reactive.getGreeting());
//正式的方法定义,在es6之前从未正式定义'方法'的概念,方法仅仅是一个具有功能而非数据的对象属性,在es6中正式将方法定义一个函数
let person={
//方法
getGreeting(){
return 'Hello'
}
}
//不是方法,在这个实例中定义了person对象,它有一个getGreeting()方法,有用直接把函数值给了person对象,因而getGreeting()方法的
//[[HomeObject]]属性值为person , 而创建shareGreeting()函数时,由于未将其值赋值给一个对象,因而该方法没有明确定义[[HomeObject]]
//属性。在大多数这些小差别无关紧要,但是当使用Super引用时就变得非常重要 。super的所有引用通过[[HomeObject]]属性来确定后续的运行过程
//第一步是在[[HomeObject]]属性上调用Object.getPrototypeOf()方法来检索原型的引用;然后寻找原型找到同名函数;
//最后,设置this绑定并且调用相应的方法
function shareGreeting(){
return 'Hi';
}
let person={
getGreeting(){
return 'Hello'
}
}
let friend={
getGreeting(){
return super.getGreeting()+'Hi'
}
}
Object.setPrototypeOf(friend,person);
console.log(friend.getGreeting());
网友评论