JavaScript - 对象、包装对象

468 阅读5分钟

创建方法

  • 对象字面量:是创建对象最简单最常用的方法

    var obj = {};
    
  • 构造函数

    var obj = new Object();
    
  • Object.create(原型)

    对于创建一个对象来说,更推荐使用字面量的方式创建对象,因为使用 new Object() 的方式创建对象需通过作用域链一层层找到 Object,但使用字面量的方式就没这个问题

属性的增删改查

  • :可以通过对象名+点+属性名的方法来给对象添加新的属性并且赋值
  • :修改的操作和增加的操作其实是一样的,只要调用相同的属性名然后赋一个新的值就可以了
  • 对象名+点+属性名对象名[属性名]
  • delete 操作符,其作用就是来删除属性的

包装对象

JavaScript 中有三种包装对象,它们对应的构造函数分别是 StringNumberBoolean,这三个包装对象对应着三个原始类型:字符串、数值和布尔

而原始数据类型是没有属性和方法的,它们就是单纯的值,若希望获取它们的属性或调用方法,就需要包装对象来帮忙 -> 原始类型会先通过其包装对象对应的构造函数转换成对象,然后用这个对象调用方法或使用属性,结束后原始类型仍是原始类型,新创建的包装对象会被销毁

注意:undefinednull 无包装对象

下面的结果是为什么?

var str = 'abcd';
console.log(str.length) // 4

按理说这个字符串原始值是没有 length 属性的,但实际却可查看 length 属性

此处就涉及到一个叫做包装类的东西,在调用执行这一行代码之前,程序会自动把 str 包装成一个字符串对象,该对象上面有属性和方法,在这一行代码执行完毕之后再销毁这个字符串对象

var str = 'abcd';
// var str1 = new String('abcd')
str.length // str1.length
// 销毁str1

这也就是为什么在执行 str.length = 2; 这句话后再打印 str.length 还是 4 的原因:

  • 系统在执行 str.length = 2 时,先创建了一个 String 对象,这个对象的值是 ‘abcd’
  • 改变的 length 其实是这个隐式创建的对象的 length 值,并不是改变了原始值 str
  • str.length = 2 这句代码执行完后隐式创建的字符串对象就被销毁了,所以打印的 str.length 还是 4
var str = 'abcd';
// var str1 = new String('abcd')
str.length = 2 // str1.length = 2
// 销毁str1
console.log(str.length) // abcd长度还是4

注意:其他类型的数据也是一样的,当给原始值加属性时都是先隐式包装成对象,然后赋完属性值之后再销毁这个对象

包装对象的 valueOftoString 的两个方法在原型上有经过覆盖,所以它们的返回值与一般的 Object 的设计不同:

  • valueOf 方法返回值:对应的原始数据类型值
  • toString 方法返回值:对应的原始数据类型值,转换为字符串类型时的字符串值

toString 方法会比较特别,这三个包装对象里的 toString 的说明如下:

  • Number 包装对象的 toString 方法:可以有一个传参,可以决定转换为字符串时的进制 (2、8、16)
  • String 包装对象的 toString 方法:与 String 包装对象中的 valueOf 相同返回结果
  • Boolean 包装对象的 toString 方法:返回 "true""false" 字符串

注意,常被搞混的是直接使用 Number()String()Boolean() 三个强制转换函数的用法,这与包装对象的用法不同,包装对象是必须使用 new 关键字进行对象实例化的,如 new Number(123),而 Number('123') 则是强制转换其他类型为数字类型的函数

Number()String()Boolean() 三个强制转换函数所对应的就是在 ECMAScript 标准中的 ToNumberToStringToBoolean 三个内部运算转换的对照表,而当它们要转换对象类型前,会先用上面说的 ToPrimitive 先将对象转换为原始数据类型再进行转换到所要的类型值

扩展:JS 监听对象属性的改变

假设有个 obj 对象,在 ES5 中可以通过 Object.defineProperty 来实现已有属性的监听

Object.defineProperty(obj, 'name', {
  set: function(key, value) {...}
})

缺点:若 id 不在 obj 对象中,则不能监听 id 变化

ES6 中,可以通过 proxy 来实现

var data = new Proxy(obj, {
  set: function(target, key, value,receiver) {...}
}

即使有属性在 obj 对象中不存在,通过 data.id 来定义同样也可以监听这个属性的变化

扩展:什么是面向对象?

面向对象是一种思想,是基于面向过程而言的,即面向对象是将功能等通过对象来实现,将功能封装进对象之中,让对象去实现具体细节

这种思想将数据作为第一位,是对数据的一种优化,简化过程,操作起来更加方便

面向对象有三个特点:

  • 封装。隐藏对象的属性和实现细节,对外提供公共访问方式
  • 继承。提高代码复用性,继承是多态的前提
  • 多态。是父类或接口定义的引用变量可以指向子类或具体实现类的实例对象