【JS】对象与原型

引言

对象很重要,是的,对象很重要。

对象

对象定义

在ECMAScript-262中,对象被定义为无序属性的集合,其属性可以包含基本值,对象或者函数
也就是说,在JavaScript中,对象无非就是由一些列无序的key-value对组成。其中value可以是基本值,对象或者函数。
从技术角度来说, 函数永远不会“ 属于” 一个对象,它们只是对于相同函数对象的多个引用。无论返回值是什么类型, 每次访问对象的属性就是属性访问。 如果属性访问返回的是一个函数, 那它也并不是一个“ 方法”。

内置对象
JavaScript 中还有一些对象子类型, 通常被称为内置对象。

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

他们或许很像类,但是在 JavaScript 中, 它们实际上只是一些内置函数。 这些内置函数可以当作构造函数来使用, 从而可以构造一个对应子类型的新对象。

属性描述符

从 ES5 开始, 所有的属性都具备了属性描述符:

  • writable
    决定是否可以修改属性的值: false为不可写,true为可写(不可修改属性)。
  • configurable
    只要属性是可配置的, 就可以使用 defineProperty(..) 方法来修改属性描述符。configurable:false 还会禁止删除这个属性。
  • enumerable
    这个描述符控制的是属性是否会出现在对象的属性枚举中(可出现在对象属性遍历中)。如果把 enumerable 设置成 false, 这个属性就不会出现在枚举中, 虽然仍然可以正常访问它。 相对地,设置成 true 就会让它出现在枚举中。

怎样使对象不可变

以下所有的方法创建的不可变对象都是浅不变型, 也就是说, 它们只会影响目标对象和它的直接属性。 如果目标对象引用了其他对象(数组、 对象、 函数, 等), 其他对象的内容不受影响, 仍然是可变的。

  1. 对象常量
    结合 writable:falseconfigurable:false 就可以创建一个真正的常量属性(不可修改、重定义或者删除)
var myObject = {
   
   };
Object.defineProperty( myObject, "FAVORITE_NUMBER", {
   
   
	value: 42,
	writable: false,
	configurable: false
});
  1. 禁止扩展:禁止添加新属性,保留原有属性
var myObject = {
   
   a:2};
Object.preventExtensions( myObject );
myObject.b = 3;
myObject.b; // undefined
  1. 密封
    Object.seal(..) 会创建一个“密封” 的对象, 这个方法实际上会在一个现有对象上调用Object.preventExtensions(..) 并把所有现有属性标记为 configurable:false。所以, 密封之后不仅不能添加新属性, 也不能重新配置或者删除任何现有属性(虽然可以修改属性的值)。
  2. 冻结
    Object.freeze(..) 会创建一个冻结对象, 这个方法实际上会在一个现有对象上调用Object.seal(..) 并把所有“数据访问” 属性标记为 writable:false, 这样就无法修改它们的值。这个方法是你可以应用在对象上的级别最高的不可变性, 它会禁止对于对象本身及其任意直接属性的修改(不过就像我们之前说过的, 这个对象引用的其他对象是不受影响的)。

setter和getter

gettersetter只能应用在单个属性上。他们都是隐藏函数。当给一个属性定义 gettersetter 或者两者都有时, 这个属性会被定义为“ 访问描述符”( 和“数据描述符” 相对)。 对于访问描述符来说, JavaScript 会忽略它们的 valuewritable 特性, 取而代之的是关心 setget(还有 configurableenumerable) 特性。

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

对象的[[Get]]和[[Put]]

对象默认的 [[Put]][[Get]] 可以理解为算法,这两种操作分别可以控制属性值的设置和获取。
Get会在原型链上查找并获取属性值
Put会检查:

  1. 属性是否是访问描述符? 如果是并且存在 setter 就调用 setter
  2. 属性的数据描述符中 writable 是否是 false ? 如果是, 在非严格模式下静默失败, 在严格模式下抛出 TypeError 异常。
  3. 如果都不是, 将该值设置为属性的值。

对象的操作

对象属性判断:

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

in操作符会检查属性是否在对象及其原型链上,hasOwnProperty只会检查是否在对象上,不会检查原型链。

Object.create

Object.create(..) 会创建一个新对象并把它关联到我们指定的对象。
Object.create(null) 会 创 建 一 个 拥 有 空(或 者 说 null[[Prototype]]链接的对象, 这个对象无法进行委托。 由于这个对象没有原型链, 所以instanceof 操作符( 之前解释过) 无法进行判断, 因此总是会返回 false。这些特殊的空 [[Prototype]] 对象通常被称作“ 字典”, 它们完全不会受到原型链的干扰, 因此非常适合用来存储数据。

if (!Object.create) {
   
   
    Object.create = function(o) {
   
   
        function F(){
   
   }
        F.prototype = o;
        return new F();
    };
}

对象复制

对象复制要考虑浅复制还是深复制。
对于 JSON 安全的对象来说, 有一种巧

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值