ES6学习-扩展对象的功能性

在JavaScript中,几乎每一个值都是某种特定类型的对象,所以ES6加强了对象的功能性。

对象类别

·普通对象:具有JavaScript对象所有默认内部行为。
·特异对象:具有某些与默认行为不符的内部行为。
·标准对象:ECMAScript6规范中定义的对象,例如:Array,Date等。标准对象既可以是普通对象,也可以是特异对象。
·内建对象:脚本开始执行时存在于JavaScript执行环境中的对象,所有标准对象都是内建对象。

对象字面量语法扩展

属性初始值的简写

在ES5中,对象字面量只是简单的键值对集合,这意味着初始化属性值时会有一些重复。

function createPerson(name,age){
    return {
        name:name,
        age:age
    };
}

这段代码中这个函数属性名称与函数的参数相同,在ES6中,通过使用属性初始化的简写语法,就可以消除这种属性名称与局部变量之间的重复书写。

//这是简写
function createPerson(name,age){
    return {
        name,
        age
    };
}

当对象字面量里只有一个属性的名称时,JavaScript引擎会在可访问作用域中查找其同名变量;如果找到,就会把变量的值赋值给对象字面量的同名属性。这样做的好处是:有助于消除命名错误。

对象方法的简写语法

ES6也改进了为对象字面量定义方法的语法。

//  ES6之前
var persoon={
    name:"cc",
    sayName:function(){
        console.log(this.name);
    }
};
//ES6中消除了冒号和function关键字
var person={
    name:"cc",
    sayName(){
        console.log(this.name);
    }
}

简写方法和之前的定义方法唯一不同的是简写方法可以使用super关键字(稍后讨论)。

可计算属性名

在ES6之前,如果属性名称被包含在变量里或者通过计算获得该变量的值,那么ES5并不能为一个对象字面量定义该属性的。
而在ES6中,可在对象字面量中使用可计算属性名称,其语法与引用对象实例的可计算属性名称相同,也是使用方括号。

//例子一
let lastName="last name";
let person={
    "first name":"Nicholas",
    [lastName]:"Zakes"
};
console.log(person["first name"]);//"Nicholas"
console.log(person[lastName]);//"Zakes"
//例子二
var suffix="name";
var person={
    ["first"+suffix]:"Nicholas",
    ["last"+suffix]:"Zakes"
};
console.log(person["firstname"]);//"Nicholas"
console.log(person["lastname"]);//"Zakes"

新增方法

ES6为了让某些任务也更容易完成,在全局对象Object对象中引入了新的方法。

Object.is()方法

ES5前,开发者习惯用===确定比较值,但是+0和-0在JavaScript中是是不同实体,然后+0===-0,同样,NaN===NaN会返回false,而ES6中引入Object.is()弥补全等运算符的不准确性。

console.log(+0===-0);//true
console.log(NaN===NaN);//false
console.log(Object.is(+0,-0));//false
console.log(Object.is(NaN,NaN));//true
Object.assign()方法

混合(Mixin)是JavaScript中实现对象组合最流行的模式,它可以实现一个对象接收来自另一个对象的属性和方法。

function mixin(receiver,supplier){
    Object.keys(supplier).forEach(function(key){//遍历自身属性,并添加到新对象中
        receiver[key]=supplier[key];
    });
    return receiver;
}

这样一来利用这个函数不通过继承就可以获得新属性。

function EventTarget(){/*...*/}
EventTarget.prototype={
    constructor:EventTarget,
    emit:function(){return "cc";},
    on:function(){/*...*/}
};
var myObject={};
mixin(myObject,EventTarget.prototype);
myObject.emit("somethingChanged");//"cc"

这种混合模式非常流行,所以在ES6中添加了Object.assign()方法实现了相同的功能,这个方法接收对象和任意数量的源对象,最终返回对象。值得注意的是不能复制访问器属性。
任何使用mixin()的方法都可以直接使用这个方法。

function EventTarget(){/*...*/}
EventTarget.prototype={
    constructor:EventTarget,
    emit:function(){return "cc";},
    on:function(){/*...*/}
};
var myObject={};
Object.assign(myObject,EventTarget.prototype);
myObject.emit("somethingChanged");//"cc"

Object.assign()可以接收任意数量的源对象,并按指定顺序将属性复制到接收对象中,但是排位靠后的优先。

function first(){/*...*/}
first.prototype={
    constructor:"first",
    emit:function(){return "first";},
    on:function(){/*...*/}
};
function second(){/*...*/}
first.prototype={
    constructor:"second",
    emit:function(){return "second";},
    on:function(){/*...*/}
};
var myObject={};
mixin(myObject,first.prototype,second.prototype);
myObject.emit("somethingChanged");//"second"

重复的对象字面量属性

ES5严格模式中中,对象加入了对象字面量重复性的校检,当多个命名属性时会抛出错误。
而ES6中不会,ES6中会选取最后一个值。

//ES6
var person={
    name:"cc",
    name:"ccg"
}
console.log(person.name);//"ccg"

自有属性枚举顺序

ES5中未定义对象属性的枚举顺序,由JavaScript引擎厂商自行决定,然而ES6中严格规定了对象的自有属性被枚举的返回顺序。
自有属性的枚举顺序的基本规则是:

  1. 所有的数字键按升序排序。
  2. 所有的字符串键按照它们被加入对象的顺序排序。
  3. 所有symbol键按照它们被加入对象的顺序排序。
var obj={
    a:1,
    0:1,
    c:1,
    2:1,
    b:1,
    1:1
};
obj.d=1;
console.log(Object.getOwnPropertyNames(obj).join(""));//012acbd

增强对象原型

ES6对原型进行了改进。

改变对象的原型

正常情况下,对象原型在实例化后就无法改变了,但是ES6中添加了Object.setPrototypeOf()方法来改变这一现状。

let person={
    getGreeting(){
        return "Hello";
    }
};
let dog={
    getGreeting(){
        return "Woof";
    }
};
//以person对象为原型
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
简化原型访问的Super引用

Super可以更快捷的访问原型,请看例子。

let person={
    getGreeting(){
        return "Hello";
    }
};
let dog={
    getGreeting(){
        return "Woof";
    }
};
let friend={
    getGreeting(){
        return Object.getPrototypeOf(this).getGreeting.call(this)+",hi";
    }
};
//将原型设置为person
Object.setPrototypeOf(friend,person);
console.log(friend.getGreeting());//"Hello,hi"
console.log(Object.getPrototypeOf(friend)===person);//true
//将原型设置为dog
Object.setPrototypeOf(friend,dog);
console.log(friend.getGreeting());//"Woof,hi"
console.log(Object.getPrototypeOf(friend)===dog);//true
//用super可以准确找到指向当前对象的原型
let friend={
    getGreeting(){
        return super().getGreeting()",hi";
    }
};

Super在多重继承非常有用,请看例子

let person={
    getGreeting(){
        return "Hello";
    }
};
//以person对象为原型
let friend={
    getGreeting(){
        return Object.getPrototypeOf(this).getGreeting.call(this)+",hi";
    }
};
Object.setPrototypeOf(friend,person)
//原型是friend
let relative=Object.create(friend);
console.log(person.getGreeting());//"Hello"
console.log(friend.getGreeting());//"Hello,hi"
console.log(relative.getGreeting());//error!
//call(this)的定位会使程序进入递归调用,直到触发栈溢出报错

如果不使用call(this),程序会一级一级向上找,直到找到最大的构造函数Object。

let person={
    getGreeting(){
        return "Hello";
    }
};
//以person对象为原型
let friend={
    getGreeting(){
        return Object.getPrototypeOf(this).getGreeting()+",hi";
    }
};
Object.setPrototypeOf(friend,person);
//原型是friend
let relative=Object.create(friend);
console.log(person.getGreeting());//"Hello"
console.log(friend.getGreeting());//"Hello,hi"
console.log(relative.getGreeting());//"Hello,hi,hi"

最佳实践是使用Super,因为它不是动态变化的,总会指向正确的对象。

let person={
    getGreeting(){
        return "Hello";
    }
};
//以person对象为原型
let friend={
    getGreeting(){
        return super.getGreeting()+",hi";
    }
};
Object.setPrototypeOf(friend,person);
//原型是friend
let relative=Object.create(friend);
console.log(person.getGreeting());//"Hello"
console.log(friend.getGreeting());//"Hello,hi"
console.log(relative.getGreeting());//"Hello,hi"

正式的定义方法

ES6以前从未正式定义“方法”的概念,而在ES6中被正式定义为一个函数,这个函数内部包含[HomeObject]属性容纳这个方法从属的对象。

let person={
    //是方法
    getGreenting(){
        return "Hello";//明确赋值person,[HomeObject]的属性值为person
    }
};
//不是方法
function shareGreeting(){
    return "Hi";//没有明确赋值给一个对象,[HomeObject]无法定义
}

值得注意的点是,Super的所有引用都是要通过[HomeObject]属性来确定后续的进程。第一步是在[HomeObject]属性值上调用Object.getPrototypeOf()来检索原型的引用率;然后搜索原型寻找同名函数;最后,设置this值并且调用相应的方法。

let person={
    getGreenting(){
        return "Hello";
    }
};
let friend={
    getGreenting(){
        return super.getGreenting()+",hi!";
    }
};
//以person对象为原型
Object.setPrototypeOf(friend,person);
console.log(friend.getGreenting());//Hello,hi!
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,088评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,715评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,361评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,099评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 60,987评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,063评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,486评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,175评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,440评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,518评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,305评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,190评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,550评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,880评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,152评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,451评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,637评论 2 335

推荐阅读更多精彩内容