JavaScript--关于对象你不知道的哪些事儿

学习Javascript,对象是我们再熟悉不过的一种数据结构了,也是一个永远绕不过的话题,但是总有那么些知识,是我们既陌生又熟悉,所以关于对象你不知道的哪些事儿做个归纳总结,还是很有必要的。

创建对象的俩中方式:

  • 构造形式: var obj = new Object()

  • 文字形式:var obj = {}

二者的区别:文字形式可以添加多个key/value,而构造形式必须逐个添加key/value

数据类型:

  • 基本类型:string, number, boolean, undefined, null
  • 引用类型:除了基本类型,其他都是引用类型。

typeof [‘引用类型’] ===> Object
typeof null ===> Object

注意:这些对象在底层都是表示为二进制,在JavaScript中二进制的前三位都是0,那么就会被认为是Object类型,而null的二进制表示全是0,自然前三位也是0,所以typeof null 的结果是Object

Javascript的内置对象:Number, String, Boolean, Object, Array, Function, Date, RegExp, Error

访问属性的方式:

  • .操作符–>属性访问
  • []操作符–>键访问

区别:. 操作符要求属性名满足标识符的命名规范,而 [“..”] 语法 可以接受任意 UTF-8/Unicode 字符串作为属性名。
所以,可以通过动态的方式为对象添加属性:

1
2
3
4
let name = 'name'
let obj = {}
obj[name + 'Vale'] = '小明'
obj.nameValue = '小明'

在对象中,属性名永远都是字符串。如果你使用 string(字面量)以外的其他值作为属性 名,那它首先会被转换为一个字符串。即使是数字也不例外,虽然在数组下标中使用的的确是数字,但是在对象属性名中数字会被转换成字符串,所以当心不要搞混对象和数组中数字的用法。

数组:
数组是特殊的对象。所以数组也支持[]的方式来访问,但是数组期望数组下标是整数。也仍然可以给数组添加属性:

1
2
3
4
var myArray = ['foo', 42, 'bar']
myArray.bar = 'bar'
myArray.length // 3
myArray.baz // 'baz'

可以看到虽然添加了命名属性(无论是通过 . 语法还是 [] 语法),数组的 length 值并未发 生变化。

对象的属性描述符:
自从ES5之后,所有的属性都具备了属性描述符:

1
2
3
4
5
6
7
8
9
10
var myObject = {
a: 1
}
Object.getOwnPropertyDescriptor(myObject, 'a')
{
value: 1,
writable: true, // 可写
configable: true, // 可配置
enumerable: true // 可枚举
}

在创建普通属性时属性描述符会使用默认值,我们也可以使用 Object.defineProperty(..) 来添加一个新属性或者修改一个已有属性(如果它是 configurable)并对特性进行设置。

1
2
3
4
5
6
7
8
var myObject = {}
Object.getOwnProperty(myObject, 'a', {
value: 1,
writable: true,
configable: true,
enumerable: true
})
myObject.a // 1
  • writable –> 可写,如果值为false,通过myObject.a = 2对对象属性的修改,将会不起作用,在严格模式下,将会报错。
  • confinable –> 可配置,如果值为false,那么对象就成为不可配置,不管是不是严格模式,尝试修改一个不可配置的属性都会报错,而且,confinable修改成false是单向的,无法撤销。而且如果属性confinable是false,我们可以把writable由true改为false,但是不能false改为true。configurable:false 还会禁止删除这个属性。
  • enumerable –> 可枚举,如果值为false,比如在for…in循环中,那么该属性就是不可见的,但是依旧可以正常访问。

对象的不可变性:

  • 对象常量–> 结合writable: false 和confinable: false就可以创建一个真正憝常量属性(不可修改,重新定义,删除)

  • 禁止扩展–> Object.preventExtensions(myObject)不允许在myObject对象上扩展新属性

  • 密封对象–> 会在一个现有对象上调用 Object.preventExtensions(..) 并把所有现有属性标记为 configurable:false。密封之后不仅不能添加新属性,也不能重新配置或者删除任何现有属性(虽然可以 修改属性的值)。

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

对象的Get和Put:

  • 我们知道访问对象属性的方式,应该是先从对象上找某个属性,如果有,那么就返回其属性值,如果没有要查找的属性,那么就回去其原型链找,这个过程就是其内部定义的get方法执行的操作。但是当找不到属性和属性的值是undefined返回的值都是undefined。
    1
    2
    3
    4
    5
    var myObject = {
    a: undefined
    }
    myObject.a // undefined
    myObject.b // undefined
  • Put操作与Get操作有点不同。
    1. 属性是否是访问描述符(参见3.3.9节)?如果是并且存在setter就调用setter。
    2. 属性的数据描述符中writable是否是false?如果是,在非严格模式下静默失败,在
      严格模式下抛出 TypeError 异常。
    3. 如果都不是,将该值设置为属性的值。
      如果对象中不存在这个属性,Put操作会更加复杂。

Getter和Setter:
对象默认的 [[Put]] 和 [[Get]] 操作分别可以控制属性值的设置和获取。在 ES5 中可以使用 getter 和 setter 部分改写默认操作,但是只能应用在单个属性上,无法 应用在整个对象上。getter 是一个隐藏函数,会在获取属性值时调用。setter 也是一个隐藏 函数,会在设置属性值时调用。通常来说getter和setter是成对出现的。

1
2
3
4
5
6
7
8
9
10
11
var myObject = {
// 给 a 定义一个 getter
get a() {
return this._a_;
},
// 给 a 定义一个 setter
set a(val) {
this._a_ = val * 2;
}
};
myObject.a = 2; myObject.a; // 4

存在性:
上面说,当访问一个对象的属性的时候会返回的是undefined,那么到底是不错在这个属性呢,还是属性值是undefeated?这是个问题。

  • in –> 可以通过in操作符来检查属性是否会在这个对象上,而且in操作符会检查原型链上的属性。
  • hasOwnProperty(…)–>可以检查属性是否会在这个对象,而且不会检查原型链。
  • Object.prototype.hasOwnProperty. call(myObject,”a”)有的对象可能没有连接到Object.prototype( 通 过 Object. create(null) )创建。那么hasOwnProperty就会失败。

检查可枚举:myObject.propertyIsEnumerable()检查属性是不是存在对象上,且是enumerable:true,不会检查原型链。
Object.keys(..) 会返回一个数组,包含所有可枚举属性,Object.getOwnPropertyNames(..) 会返回一个数组,包含所有属性,无论它们是否可枚举。并不会检查原型链。

遍历:
for…in…通过遍历对象的key来得到属性值,而且遍历的顺序是不可信的
for…of…循环首先会向被访问对象请求一个迭代器对象,然后通过调用迭代器对象的 next() 方法来遍历所有返回值。for..of 循环每次调用 myObject 迭代器对象的 next() 方法时,内部的指针都会向前移动并 返回对象属性列表的下一个值.知道返回done:true遍历结束。

  • 版权声明: 本博客所有文章除特别声明外,著作权归作者所有。转载请注明出处!
  • Copyrights © 2015-2022 Lee
  • 访问人数: | 浏览次数:

请我喝杯咖啡吧~

支付宝
微信