你不知道的javascript之对象的全面解析

学习js必然绕不开对象,今天我们就来比较全面地了解一下js中对象。

定义对象的语法

对象可以通过两种形式定义:声明(文字)形式和构造形式。

文字形式:

var myObj = {    
	 key: value    
	  // ... 
};

构造形式:

var myObj = new Object(); 
myObj.key = value;

构造形式和文字形式生成的对象是一样的。唯一的区别是,在文字声明中你可以添加多个 键 / 值对,但是在构造形式中你必须逐个添加属性。

js中的内置对象

js 中还有一些对象子类型,通常被称为内置对象,主要有以下几种:

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

这些内置对象从表现形式来说很像其他语言中的类型(type)或者类(class),比如 Java 中的 String 类,可以通过new关键字来调用(实例化)。

观察如下代码:

var strPrimitive = "I am a string";  
typeof strPrimitive; // "string"  
strPrimitive instanceof String; // false 
 
var strObject = new String( "I am a string" );  
typeof strObject; // "object" 
strObject instanceof String; // true 

上述代码中,原始值 “I am a string” 并不是一个对象,它只是一个字面量,所以strPrimitive instanceof String输出false。并且它是一个不可变的值,如果要在这个字面量上执行一些操作,比如获取长度、访问其中某个字符等,那需要将其转换为 String 对象

看到上述加粗的文字描述,我们心中可能会有些疑惑,因为我们常常使用到如下代码,而且能正确获得长度,这是为什么呢?

var strPrimitive = "I am a string";
var len = strPrimitive.length;
console.log(len); //13

上述代码能正常执行是因为js自动把字符串字面量转换成一个 String 对象,也就是说我们并不需要显式创建一个String对象,对于其他对象来说也是如此,比如我们可以通过代码 var re = /\d+/; 来声明一个正则表达式re。

对象的属性

访问对象属性的方法

观察如下代码:

var myObject = {     
	a: 2 
}; 
myObject.a; // 2 
myObject["a"]; // 2

我们可以通过 . 操作符或者 [] 操作符来访问属性。

.a 语法通常被称为“属性访问”,[“a”] 语法通常被称为“键访问”,相信大家比较常用的是属性访问。

这里有个我们需要注意的点,即在对象中(es5),属性名永远都是字符串。如果我们使用 string(字面量)以外的其他值作为属性名,那它首先会被转换为一个字符串,即使是数字也不例外。

数据描述符和属性描述符

观察如下代码:

var myObject = {}; 
 
Object.defineProperty( myObject, "a", {     
	value: 2,     
	writable: true,      
	configurable: true,      
	enumerable: true 
} );  
 
myObject.a; // 2

上述代码中,value就是属性a的数据描述符,因为它只保存一个数值,而writable(可写)、 enumerable(可枚举)和 configurable(可配置)就是属性a的属性描述符,定义了属性a的行为。

下面我们来分析一下属性描述符:

writable

writable 决定是否可以修改属性的值,如果把writable 设置为false,那么就不能修改属性的值,语句myObject.a = 3;会静默失效,a的值还是原来的2,如果在严格模式下,该语句会报错。

configurable

configurable决定属性是否可以配置,只要属性是可配置的,就可以使用 defineProperty() 方法来修改属性描述符,

这里要注意的是把configurable 修改成 false 是单向操作,无法撤销!即我们通过defineProperty() 方法把configurable的值设置成 false,那么将无法再次使用defineProperty() 方法把configurable的值设置成 true。

把属性的configurable的值设置成 false会禁止删除这个属性,即语句delete myObject.a会静默失效。

enumerable

这个描述符控制的是属性是否会出现在对象的属性枚举中,比如说 for…in 循环。如果把 enumerable 设置成 false,这个属性就不会出现在枚举中,虽然仍然可以正常访问它(myObject.a),但是使用for…in 循环遍历myObject时,属性a不会被遍历到。

属性的不变性

有时候我们会需要维护一个不变的对象,即对象中属性不可进行修改、删除等操作,那么我们可以通过以下·的方法来实现这个需求。

  1. 对象常量
    结合 writable:false 和 configurable:false 就可以创建一个真正的常量 属性(不可修改、 重定义或者删除)。

  2. 禁止扩展
    如果我们想禁止一个对象添加新属性并且保留已有属性,可以使用 Object.preventExtensions()方法。

  3. 密封
    Object.seal()方法会创建一个“密封”的对象,这个方法实际上会在一个现有对象上调用 Object.preventExtensions() 并把所有现有属性标记为 configurable:false。

    所以,密封之后不仅不能添加新属性,也不能重新配置或者删除任何现有属性(可以修改属性的值,因为writable不为false)。

  4. 冻结
    Object.freeze()方法会创建一个冻结对象,这个方法实际上会在一个现有对象上调用 Object.seal() 并把所有“数据访问”属性标记为 writable:false,这样就无法修改它们的值。

属性的存在性

怎样判断一个属性是否存在于当前对象呢?
观察如下代码:

var myObject = {      
a:2 
}; 
 
("a" in myObject); // true 
("b" in myObject); // false  
 
myObject.hasOwnProperty( "a" ); // true 
myObject.hasOwnProperty( "b" ); // false

由上述代码,我们可以看出:可以通过in操作符和hasOwnProperty()方法来判断属性的存在性。

它们的区别是:in 操作符会检查属性是否在对象及其 [[Prototype]] 原型链中。相比之下,hasOwnProperty() 只会检查属性是否在 myObject 对象中,不会检查 [[Prototype]] 链。关于原型链,我会在下一篇博客中进行介绍。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值