JavaScript中的对象

文章目录

  • 语法
  • 内置对象
  • 对象中的内容
    • 访问对象中的内容
    • 属性描述符
    • getter和setter
    • 存在性
    • 遍历

语法

创建一个对象有两种形式:声明(文字)形式构造形式
例如:

// 声明形式
var myObject = {
  name: 'cherry',
  age: 20,
};

// 构造形式
var myObject = new Object();
myObject.name = 'cherry';
myObject.age = 20;

一般我们在开发的时候,在创建一个对象的时更喜欢用声明(文字)形式,这种形式可以简化创建包含有大量属性的对象的过程。

内置对象

Object是JavaScript的基础,它也是JavaScript语言类型中的一种。JavaScript中的语言类型包含:

  • string
  • number
  • boolean
  • null
  • undefined
  • Object
  • symbol (ES6新增)

除去object之外,其他的类型都被称为简单基础类型,在使用typeof来测试null的时候,会返回‘object’,但是null并不是object类型。造成这种情况是由于不同对象在底层会被表示为二进制,当二进制的前三位都是0的时候会被认为是object类型,而null的二进制表示为全0,因此,前三位自然是0,所以在使用typeof的时候,会返回’object‘。Object类型有多衍生的子类型,函数就是Object的一个子类型,数组也是。这些子类型通常被称为JavaScript的内置对象。有些内置对象的名字看起来和简单基础类型一样。

  • String
  • Number
  • Boolean
  • Array
  • Function
  • Date
  • Error
  • RegExp
  • Object

这些内置对象在JavaScript中实际上是内置函数,这些内置函数可以作为构造函数来使用,从而可以构建一个对应子类型的新对象。

例如:


var str = 'I am a string';
typeof str ; // string
str instanceof String; // false

var strObj = new String('I am a string');
typeof strObj ; // object
strObj instanceof String; // true

原始值’I am a string’并不是一个对象,它只是一个字面量,并且是一个不可改变的值。当我们需要在字符串上执行一些操作的时候,比如:获取具体的对应位置的字符,获取字符串的长度…,需要将其转换为String对象,幸好,在必要的时候语言会自动将字符串字面量转换为String对象。也就是数,你不需要自己显式的创建一个对象。


var str = 'I am a string';
console.log(str.length); // 13
console.log(str.charAt(3)); // 'm'

对象中的内容

对象中的内容是由一些存储在特定命名位置的(任何类型)的值组成。虽然这么说,但是对象并不是拥有这些内容,在引擎内部,这些值的存储方式各种各样,一般并不会存储在对象容器中,存储在对象容器中的是这些属性的名字,这些名字就像指针一样,指向这些值真正的存储位置。

访问对象中的内容

访问对象中的内容有两种方式:.操作符(属性访问)[]操作符(键访问)

例如:

var myObj = {
  a: 2,
};

myObj.a ; // 2
myObj['a']; // 2

这两种访问方式访问的都是同一个位置,拿到的也是同一个值,在日常开发中,我们最常用的是属性访问。这两种访问方式的区别在于,.操作符要求属性名必须符合标识符的命名规范,而['...']操作符则可以接受任意的UTF-8/Unicode字符串。例如,如果访问名称为’super-name’的属性,就不能使用.操作符,只能使用['super-name']来访问。

属性描述符

从ES5开始,所有的属性都具有属描述符,属性描述符用来描述该属性是否只读,是否可配置,以及是否可遍历。所以属性描述符是针对一个属性而言的,并不是针对整个对象。

  • writable
  • configurable
  • enumerable

以上就是JavaScript中的属性描述符。writable决定了是否可以修改属性的值,configurable决定了是否可以配置属性的属性描述符,enumerable决定了属性是否可遍历。在我们创建一个属性的时候,这三个属性描述符都是默认值。

var myObj = {
  a: 2,
};

Object.getOwnPropertyDescription(myObj, 'a');
// {
//    value: 2,
//    writable: true,
//    configurable: true,
//    enumerable: true,
// }

我们可以使用Object.defineProperty(…)来添加一个新属性或修改一个已有属性,并对属性操作符进行设置。

var myObj = {};
Object,defineProperty(myObj,  'a', {
  value: 2,
  wirtable: true,
  configurable: true,
  enumerable: true,
});

一般来说,你并不会使用这种方式来为对象添加属性,除非你想改变属性的属性描述符。

getter和setter

ES5中的gettersetter用来改写默认操作,但是只能应用于单个属性,不能应用于整个对象上。getter是一个隐藏函数,在调用对象属性的时候调用,setter也是一个隐藏函数,在给对象属性赋值的时候调用。

通常来说gettersetter是成对出现的,当你给一个属性定义了gettersetter时,这个属性会被定义为‘访问描述符’,对于访问描述符,JavaScript会忽略它的valuewritable属性,取而代之的是只关心它的getset以及configurableenumerable特性。

var myObj = {
   get a() {
     return this.a;
   }
   set a(val) {
     this.a = val * 2;
   }
}
myObj.a = 2;
myObj.a ; // 4
     

存在性

之前我们提到过,如果引用一个对象中不存在的属性时,会返回undefined,但是undefined有可能是对象中的属性存储的值,那么如何来区分者两种情况?

var myObj = {
  a: undefined,
}
myObj.a; // undefined
myObj.b; // undefined;

在JavaScript中用来判定一个属性是否存在的方法有两个:

  • in操作符
  • hasOwnProperty(…)

继续上面的例子:

('a' in myObj); // true
('b' in myObj); // false

myObj.hasOwnProperty('a'); // true
myObj.hasOwnProperty('b'); // false

这两种方法的区别是。in操作符不但会在当前对象中进行查找,也会查找该对象的原型链,而hasOwnProperty(...)只会在当前对象中进行查找,不会查找该对象的原型链。

遍历

之前介绍的enumerable描述符用来描述一个属性是否可枚举,而可枚举就相当于一个属性是否会出现在对象属性的遍历中。例如:

var myObject = {
  a: 2,
};
Object.definePropertyDescription(myObject, 'b', {
  value: 4,
  enumerbale: false, // 让属性b不可枚举
});

myObject.b; // 3
("b" in myObject); // true 
myObject.hasOwnProperty( "b" ); // true 

for (var k in myObject) {
  console.log( k, myObject[k] ); 
} 
// "a" 2

可以看到的是,'b'确实可以访问,并且存在于myObject当中,但是使用for...in进行遍历的时候,确不会出现在循环中,原因就是属性b是一个不可枚举属性

我们还可以使用其他的方式进行检测一个属性是否可枚举,接着上面的例子:

myObjec.propertyIsEnumerable('a'); true
myObjec.propertyIsEnumerable('b'); false

Object.keys(myObject); // ['a']
Object.getOwnPropertyNames( myObject ); ['a', 'b']

propertyIsEnumerable(...)方法可以检测一个属性是否可以枚举,Object.keys(..)返回的是一个数组,包含一个对象中所有可枚举的属性名,Object.getOwnPropertyNames(...)返回的也是一个数组,包含的是一个对象所有的属性名,无论它们是否可枚举。且这两个方法都只会返回这个对象包含的直接属性,并不会涉及到对象的原型链。

你可能感兴趣的:(javascript)