资讯专栏INFORMATION COLUMN

ES6系列---对象功能扩展

sarva / 1742人阅读

摘要:通过多种方式来加强对象的使用,通过简单的语法扩展,提供更多操作对象及与对象交互的方法。增强对象原型改变对象的原型正常情况下,无论是通过构造函数还是方法创建对象,其原型是在被创建时指定的。引用相当于指向对象原型的指针

ES6通过多种方式来加强对象的使用,通过简单的语法扩展,提供更多操作对象及与对象交互的方法。

对象字面量语法扩展 对象属性初始值的简写

ES5中初始化属性值的方式:

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

这段代码中的createPerson()函数创建的对象,其属性名与函数的参数相同,在返回的结果中,nameage分别重复了两遍,只是其中一个是对象属性名,另一个是为属性赋值的变量。

ES6中可以简单地只写属性名即可:

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

当对象字面量里只有一个属性的名称时,JavaScript引擎会在可访问作用域中查找同名变量;如果找到,则该变量的值被赋给对象字面量的同名属性。

对象方法的简写

ES5中定义对象方法:

var person = {
    name: "Nicholas",
    sayName: function() {
        console.log(this.name);
    }
};

ES6中简写后的对象方法:

var person = {
    name: "Nicholas",
    sayName() {
        console.log(this.name);
    }
};

二者唯一的区别是,简写方法可以使用super关键字(稍后会讨论)。

可计算属性名

ES5中,如果想要通过计算得到属性名,就需要使用方括号代替点记法,请看:

var person = {};
    lastName = "last name";
    
person["first name"] = "Nicholas";
person[lastName] = "Zakas";

console.log(person["first name"]);   // "Nicholas"
console.log(person[lastName]);   // "Zakas"

ES5在对象字面量中,也可以直接使用字符串字面量作为属性名:

var person = {
    "first name": "Nicholas"
};

console.log(person["first name"]);  // "Nicholas"

这种模式适用于属性名提前已知或可被字符串字面量表示的情况。然而,如果属性名"first name"被包含在一个变量中(就像之前的示例中的那样),或者需要通过计算才能得到该变量的值,那么ES5中是无法为一个对象字面量定义该属性的。

而在ES6中,可在对象字面量中使用可计算属性名,请看:

let lastName = "last name";

let person = {
    "first name": "Nicholas",
    [lastName]: "Zakas"
};

console.log(person["first name"]);  // "Nicholas"
console.log(person[lastName]);   // "Zakas"

在对象字面量中使用方括号表示该属性名是可计算的,它的内容将被求值并最终转化为一个字符串,因而同样可以使用表达式作为属性的可计算名称,例如:

var suffix = " name";

var person = {
    ["first" + suffix]: "Nicholas",
    ["last" + suffix]: "Zakas"
};

console.log(person["first name"]);  // "Nicholas"
console.log(person["last name"]);   // "Zakas"
新增方法 Object.is()方法

当你想在JavaScript中比较两个值时,可能习惯于使用相等运算符(==)或全等运算符(===),许多开发者更喜欢后者,从而避免在比较时触发强制类型转换的行为。但即使全等运算符也不完全准确,比如+0和-0在JavaScript引擎中被表示为两个完全不同的实体,而如果使用全等运算符===对两者进行比较,得到的结果是两者相等;同样,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

consolog.log(5 == 5);   // true
consolog.log(5 == "5");   // true
consolog.log(5 === 5);   // true
consolog.log(5 === "5");   // false
console.log(Object.is(5, 5));   // true
console.log(Object.is(5, "5"));   // false

对于Object.is()方法来说,其运行结果在大部分情况下与===运算符相同,唯一的区别在于+0和-0被识别为不相等并且NaN与NaN等价。但是你大可不必抛弃等号运算符,是否选择使用Object.is()方法而不是===取决于那些特殊情况如何影响代码。

Object.assign()方法

混合(Mixin)是JavaScript种实现对象组合最流行的一种模式。在一个mixin方法中,一个对象接收来自另一个对象的属性和方法,许多JavaScript库中都有类似minxin方法:

function mixin(receiver, supplier) {
    Object.keys(supplier).forEach(function(key) {
        receiver[key] = supplier[key];
    });
    return receiver;
}

mixin()函数遍历supplier的自有属性并复制到receiver中(复制行为是浅复制,当属性值为对象时只复制对象的引用)。这样一来,receiver不通过继承就可以获得新属性,请参考这段代码:

function EventTarget() { ... }
EventTarget.prototype = {
    constructor: EventTarget,
    emit: function() { ... },
    on: function() { ... }
};

var myObject = {};
mixin(myObject, EventTarget.prototype);

myObject.emit("somethingChanged");

这种混合模式非常流行,因而ES6添加了Object.assign()方法来实现相同的功能:

Object.assign(myObject, EventTarget.prototype);

Object.assign()方法接受一个接收对象和任意数量的源对象,最终返回接收对象。如果多个源对象具有相同属性,则排位靠后的会覆盖排位靠前的。

需要注意的是,Object.assign()方法不能将提供者的访问器属性复制到接收对象中。由于Object.assign()方法执行了赋值操作,因此提供者的访问器属性最终会转变为接收对象中的一个数据属性,请看示例:

var receiver = {},
    supplier = {
        get name() {
            return "file.js";
        }
    };
    
Object.assign(receiver, supplier);

var descriptor = Object.getOwnPropertyDescriptor(receiver, "name");

console.log(descriptor.value);   // "file.js"
console.log(descriptor.get);     // undefined

在这段代码中,supplier有一个名为name的访问器属性。当调用Object.assign()方法时返回字符串"file.js",因此receiver接收这个字符串后将其存为数据属性receiver.name

增强对象原型 改变对象的原型

正常情况下,无论是通过构造函数还是Object.create()方法创建对象,其原型是在被创建时指定的。对象原型在实例化之后保持不变,直到ES5都是JavaScript编程最重要的设定之一,虽然在ES5中添加了Object.getPrototypeOf()方法来返回任意指定对象的原型,但仍缺少对象在实例化后改变原型的标准方法。

所以,在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
console.log(friend.getGreeting());   // "Woof"
console.log(Object.getPrototypeOf(friend) === dog);   // true

这段代码定义了两个基对象:persondog。二者多有getGreeting()方法。friend对象先继承person对象,调用getGreeting()方法输出"Hello";当原型被变更为dog对象时,原先与person对象的关联被解除,调用person.getGreeting()方法时输出的内容就变为了"Woof"。

对象原型的真实值被存储在内部专用属性[[Prototype]]中,调用Object.getPrototypeOf()方法返回存储在其中的值,调用Object.setPrototypeOf()方法改变其中的值。然而,这不是操作[[Prototype]]值的唯一方法。

用super简化原型访问

ES6引入了super引用的特性,使用它可以更便捷地访问对象原型。举个例子,如果你想重写对象实例方法,又需要调用与它同名的原型方法,先看看ES5中的实现:

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

在这个示例中,friend对象的getGreeting()方法调用了同名的原型方法。Object.getPrototypeOf()方法可以确保调用正确的原型,并向输出字符串叠加另一个字符串;后面的.call(this)可以确保正确设置原型方法中的this值。

要准确记得如何使用Object.getPrototypeOf()方法和.call(this)方法来调用原型上的方法实在有些复杂,所以ES6引入了super关键字。super引用相当于指向对象原型的指针:

let friend = {
    getGreeting() {
        // return Object.getPrototypeOf(this).getGreeting.call(this) + ", hi!";
        return sper.getGreeting() + ", hi!";
    }
};

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/85178.html

相关文章

  • ES6系列文章 对象字面量

    摘要:使得声明对象字面量更加简单,提供了属性简写和方法简写功能,属性名计算的新特性。属性简写在及以前的版本中,对象字面量只支持键值对集合。实际业务中,对象字面量的初始化会有一定的代码重复。 showImg(https://segmentfault.com/img/bVWd8N?w=320&h=235); ECMAScript6使得声明对象字面量更加简单,提供了属性简写和方法简写功能,属性名计...

    snifes 评论0 收藏0
  • 做一名精致的JavaScripter 01:JavaScript简介

    摘要:精致从细节做起。标准会在每年的月发布一次,作为当年的正式版本,便是年发布的正式版本。支持情况各大浏览器对的支持情况浏览器支持情况对的支持情况支持情况。在浏览器中基于实现的已经成为的重要组成部分。 精致从细节做起。前端的工作也有一段时间了,大大小小的前端框架都有接触过,越是深入学习越是感觉之前的学习过于粗糙,基础不够扎实,于是准备近期把JavaScript的基础知识点梳理一下,查缺补漏,...

    张巨伟 评论0 收藏0
  • JavaScript从初级往高级走系列————ES6

    摘要:采用二八定律,主要涉及常用且重要的部分。对象是当前模块的导出对象,用于导出模块公有方法和属性。箭头函数函数箭头函数把去掉,在与之间加上当我们使用箭头函数时,函数体内的对象,就是定义时所在的对象,而不是使用时所在的对象。 ES6 原文博客地址:https://finget.github.io/2018/05/10/javascript-es6/ 现在基本上开发中都在使用ES6,浏览器环境...

    孙淑建 评论0 收藏0
  • 【全栈React】第2天: 什么是 JSX?

    摘要:代表基本上是常规。第次更新,在年完成。几乎完全支持所有主要的浏览器。但这将是一段时间,直到较旧版本的浏览器逐步停止使用。这意味着将转换为。在组件的情况下,写入的将如下所示在我们在第一个作出反应组件使用的语法是语法。 本文转载自:众成翻译译者:iOSDevLog链接:http://www.zcfy.cc/article/3797原文:https://www.fullstackreact....

    Eirunye 评论0 收藏0
  • ES6系列---类

    摘要:原型会自动调整,通过调用方法即可访问基类的构造函数。在简单情况下,等于类的构造函数的值是输出这段代码展示了当调用时等于。 大多数面向对象编程语言都支持类和类继承的特性,而JavaScript只能通过各种特定方式模仿并关联多个相似的对象。这个情况一直持续到ES5。由于类似的库层出不穷,最终ES6引入了类特性,统一了类和类继承的标准。 ES5模仿类 先看一段ES5中模仿类的代码: func...

    huayeluoliuhen 评论0 收藏0

发表评论

0条评论

sarva

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<