转行学前端的第 31天 : 了解 ECMAScript Object 数据类型

944 阅读10分钟

我是小又又,住在武汉,做了两年新媒体,准备用 6 个月时间转行前端。

今日学习目标


昨天基于一些页面搜索,学习了变量作用域相关的知识。今天主要是基于搜索来仔细学习 Object 对象,又是适合学习的一天,加油,小又又!!!!


what

Object 构造函数为给定值创建一个对象包装器。

如果给定值是 nullundefined,将会创建并返回一个空对象,否则,将返回一个与给定值对应类型的对象。

当以非构造函数形式被调用时,Object 等同于 new Object()


how

字面量声明

一个对象初始化器,由花括号/大括号 ({}) 包含的一个由零个或多个对象属性名和其关联值组成的一个逗号分隔的列表构成。

对象初始化是一个描述对象初始化过程的表达式。对象初始化是由一组描述对象的属性组成。

属性的值可以是原始类型,也可以是其他对象。

var o = {};
var o = {a: 'foo', b: 42, c: {}};

var a = 'foo', b = 42, c = {};
var o = {a: a, b: b, c: c};

var o = {
  property: function ([parameters]) {},
  get property() {},
  set property(value) {}
};

ECMAScript 2015 的新标记

请参考兼容性表格获取这些标记的支持信息。在不被支持的环境中,这些标记将造成语法错误。

// Shorthand property names (ES2015)
var a = 'foo', b = 42, c = {};
var o = {a, b, c};

// Shorthand method names (ES2015)
var o = {
  property([parameters]) {}
};

// Computed property names (ES2015)
var prop = 'foo';
var o = {
  [prop]: 'hey',
  ['b' + 'ar']: 'there'
};

构造函数声明

对象是由 new 运算符加上要实例化对象的名字创建的。

// 对象初始化器(Object initialiser)或对象字面量(literal)
{ [ nameValuePair1[, nameValuePair2[, ...nameValuePairN] ] ] }

// 以构造函数形式来调用
new Object([value])
参数名 具体说明
nameValuePair1, nameValuePair2, ... nameValuePairN 成对的名称(字符串)与值(任何值),其中名称通过冒号与值分隔。
value 任何值

一个对象是一个包含相关资料功能的集体(通常由一些变量函数组成,我们称之为对象里面的属性方法)。这种语法与 Java 语言的相似,不过当有不止一个参数时,ECMAScript 要求使用括号

如果没有参数,括号可以省略,注意:尽管括号不是必需的,但是为了避免混乱,最好使用括号。


对象属性

属性访问器

创建对象后,可以读取或者修改它。属性访问器提供了两种方式用于访问一个对象的属性,它们分别是点号和方括号。

const person1 = {};
person1['firstname'] = 'Mario';
person1['lastname'] = 'Rossi';

console.log(person1.firstname);
// expected output: "Mario"

const person2 = {
  firstname: 'John',
  lastname: 'Doe'
};

console.log(person2['lastname']);
// expected output: "Doe"


语法

object.property
object['property']

描述

我们可以将对象看做是一个关联数组(或者:映射、字典、哈希表、查询表)。这个数组中的键就是这个对象中属性的名称。通常,当我们提及一个对象的属性时,会对属性与方法之间做个对比。

然而,属性与方法之间的区别并不大。一个方法就是一个可以被调用的属性而已,例如一个指向函数 Function 实例的引用可以作为对象属性的值。

访问对象属性有两种方式:点号表示法和方括号表示法。

  • 点号表示法
get = object.property;
object.property = set;

以上代码中,property必须是一个有效的 JavaScript 标识符,例如,一串字母数字字符,也包括下划线及美元符号,但不能以数字作为开头。比如,object.$1是合法的,而 object.1是无效不合法的。

document.createElement('pre');

在上述代码块中,document中存在一个名为"createElement"的方法并且被调用了。


  • 方括号表示法
get = object[property_name];
object[property_name] = set;

property_name 是一个字符串。该字符串不一定是一个合法的标识符;它可以是任意值,例如,"1foo","!bar!",甚至是 " "(一个空格)。

document['createElement']('pre');

这里的代码的功能跟上一个例子的作用是相同的。

括号之前允许有空格。

document ['createElement']('pre');

属性名称

属性名称必须是字符串或符号 Symbol。这意味着非字符串对象不能用来作为一个对象属性的键。

任何非字符串对象,包括 Number,都会通过 toString 方法,被转换成一个字符串。

var object = {};
object['1'] = 'value';
console.log(object[1]);

上述代码的输出为"value",因为 1 被类型转换为'1'。

var foo = {unique_prop: 1}, bar = {unique_prop: 2}, object = {};
object[foo] = 'value';
console.log(object[bar]);

上述的代码的输出也是 "value",由于对象 foo 和 bar 都会被转成相同的字符串。

SpiderMonkey JavaScript 引擎中,这个字符串是 "[object Object]"。


属性定义

上面学习了如何用初始化标记对象属性。经常能遇到希望将代码中的变量放到对象中的情况。可能遇到如下代码:

var a = "foo", 
    b = 42,
    c = {};

var o = { 
  a: a,
  b: b,
  c: c
};

ECMAScript 2015 中,有更简短的标记可以实现同样的效果:

var a = 'foo', 
    b = 42, 
    c = {};

// Shorthand property names (ES2015)
var o = {a, b, c};

// In other words,
console.log((o.a === {a}.a)); // true

方法定义

基础说明

ECMAScript 2015开始,在对象初始器中引入了一种更简短定义方法的语法,这是一种把方法名直接赋给函数的简写方式。该简写语法与ECMAScript 2015gettersetter语法类似。

var obj = {
  foo: function() {
    /* code */
  },
  bar: function() {
    /* code */
  }
};

// 简写为
var obj = {
  foo() {
    /* code */
  },
  bar() {
    /* code */
  }
};

注意:简写语法使用命名函数而不是匿名函数(如…foo: function() {}…)。命名函数可以从函数体调用(这对匿名函数是不可能的,因为没有标识符可以引用)。详细信息,请参阅function


语法

var obj = {
  property( parameters… ) {},
  *generator( parameters… ) {},
  async property( parameters… ) {},
  async* generator( parameters… ) {},

  // with computed keys:
  [property]( parameters… ) {},
  *[generator]( parameters… ) {},
  async [property]( parameters… ) {},

  // compare getter/setter syntax:
  get property() {},
  set property(value) {}
};

对象属性也可以是一个函数gettersetter方法。

var o = {
  property: function ([parameters]) {},
  get property() {},
  set property(value) {},
};

ECMAScript 2015引入了一种简短写法, "function" 关键字也可以丢掉。

// Shorthand method names (ES6)
var o = {
  property([parameters]) {},
  get property() {},
  set property(value) {},
  * generator() {}
};

计算属性名

从ECMAScript 2015开始,对象初始化语法开始支持计算属性名。其允许在[]中放入表达式,计算结果可以当做属性名。这种用法和用方括号访问属性非常类似,也许你已经用来读取和设置属性了。现在同样的语法也可以用于对象字面值了:

// Computed property names (ES6)
var i = 0;
var a = {
  ["foo" + ++i]: i,
  ["foo" + ++i]: i,
  ["foo" + ++i]: i
};

console.log(a.foo1); // 1
console.log(a.foo2); // 2
console.log(a.foo3); // 3

var param = 'size';
var config = {
  [param]: 12,
  ["mobile" + param.charAt(0).toUpperCase() + param.slice(1)]: 4
};

console.log(config); // { size: 12, mobileSize: 4 }

扩展属性

ECMAScript 提案(第3阶段)的剩余/扩展属性将扩展属性添加到对象文字。它将自己提供的对象的枚举属性复制到一个新的对象上。

使用比Object.assign()更短的语法,可以轻松克隆(不包括原型)或合并对象。

var obj1 = { foo: 'bar', x: 42 };
var obj2 = { foo: 'baz', y: 13 };

var clonedObj = { ...obj1 };
// Object { foo: "bar", x: 42 }

var mergedObj = { ...obj1, ...obj2 };
// Object { foo: "baz", x: 42, y: 13 }

请注意,Object.assign()会触发setter,而展开操作符则不会。

额,可是 jsconsole 好像没支持这个~~~


注意事项

重复属性名

属性使用了同样的名称时,后面的属性会覆盖前面的属性。

var a = {x: 1, x: 2};
console.log(a); // { x: 2}

ECMAScript 5 严格模式的代码中, 重复的属性名会被当做SyntaxError

引入计算的属性名以后,属性名会在运行时出现重复。ECMAScript 2015 移除了这个限制。

function haveES6DuplicatePropertySemantics(){
  "use strict";
  try {
    ({ prop: 1, prop: 2 });

    // No error thrown, duplicate property names allowed in strict mode
    return true;
  } catch (e) {
    // Error thrown, duplicates prohibited in strict mode
    return false;
  }
}

变更原型

定义属性为__proto__: 值 或 "proto": 值 时,不会创建名为__proto__属性。

如果给出的值是对象或者null,那么对象的[[Prototype]]会被设置为给出的值。(如果给出的值不是对象也不是null,那么对象的原型不会改变。)

var obj1 = {};
console.log(Object.getPrototypeOf(obj1) === Object.prototype);

var obj2 = { __proto__: null };
console.log(Object.getPrototypeOf(obj2) === null);

var protoObj = {};
var obj3 = { "__proto__": protoObj };
console.log(Object.getPrototypeOf(obj3) === protoObj);

var obj4 = { __proto__: "not an object or null" };
console.log(Object.getPrototypeOf(obj4) === Object.prototype);
console.log(!obj4.hasOwnProperty("__proto__"));

在对象字面值中,仅有一次变更原型的机会;多次变更原型,会被视为语法错误。

不使用冒号标记的属性定义,不会变更对象的原型;而是和其他具有不同名字的属性一样是普通属性定义。

var __proto__ = "variable";

var obj1 = { __proto__ };
console.log(Object.getPrototypeOf(obj1) === Object.prototype);
console.log(obj1.hasOwnProperty("__proto__"));
console.log(obj1.__proto__ === "variable");

var obj2 = { __proto__() { return "hello"; } };
console.log(obj2.__proto__() === "hello");

var obj3 = { ["__prot" + "o__"]: 17 };
console.log(obj3.__proto__ === 17);

方法定义不是构造函数

所有方法定义不是构造函数,如果尝试实例化它们,将抛出TypeError

var obj = { 
  method() {}
};
new obj.method; // TypeError: obj.method is not a constructor

var obj = { 
  * g() {} 
};
new obj.g; // TypeError: obj.g is not a constructor (changed in ES2016)

方法

Object 构造函数的方法

方法名 描述
Object.assign() 通过复制一个或多个对象来创建一个新的对象。
Object.create() 使用指定的原型对象和属性创建一个新对象。
Object.defineProperty() 给对象添加一个属性并指定该属性的配置。
Object.defineProperties() 给对象添加多个属性并分别指定它们的配置。
Object.entries() 返回给定对象自身可枚举属性的 [key, value] 数组。
Object.freeze() 冻结对象:其他代码不能删除或更改任何属性。
Object.getOwnPropertyDescriptor() 返回对象指定的属性配置。
Object.getOwnPropertyNames() 返回一个数组,它包含了指定对象所有的可枚举或不可枚举的属性名。
Object.getOwnPropertySymbols() 返回一个数组,它包含了指定对象自身所有的符号属性。
Object.getPrototypeOf() 返回指定对象的原型对象。
Object.is() 比较两个值是否相同。所有 NaN 值都相等(这与==和===不同)。
Object.isExtensible() 判断对象是否可扩展。
Object.isFrozen() 判断对象是否已经冻结。
Object.isSealed() 判断对象是否已经密封。
Object.keys() 返回一个包含所有给定对象自身可枚举属性名称的数组。
Object.preventExtensions() 防止对象的任何扩展。
Object.seal() 防止其他代码删除对象的属性。
Object.setPrototypeOf() 设置对象的原型(即内部 [[Prototype]] 属性)。
Object.values() 返回给定对象自身可枚举值的数组。

构造方法主要是做了基础了解,准备之后实际使用的时候,再详细了解


Object 实例的方法

方法名 描述 使用方法
isPrototypeOf(object) 判断该对象是否为另一个对象的原型,返回值是truefalse obj.isPrototypeOf(objectName)
propertyIsEnumerable(prop) 判断给定的属性是否可以用 for...in 语句进行枚举,返回值是truefalse obj.propertyIsEnumerable()
hasOwnProperty(prop) 判断对象是否有某个特定的属性,必须用字符串指定该属性,返回值是truefalse obj.hasOwnProperty(param1)
toString(param1) 返回对象的原始字符串表示 obj.toString(param1)
toLocaleString(param1) 返回对象的值转化为本地原始字符串表示 varName.toLocaleString(param1)
valueOf() 返回最适合该对象的原始值。 obj.valueOf()

参考网站


今日学习总结


今日心情

今日主要是基于搜索来仔细学习 Object 对象,希望明天学习到更多东西~~~~

本文使用 mdnice 排版