JavaScript对象

什么是对象

可以使用两种形式来创建对象: 声明形式和构建形式。

// 声明形式
var  obj = {
  key: 1,
}

// 构建形式
var obj2 = new Object();
obj2.key = 1;

js 数据类型

  • string
  • number
  • boolean
  • null
  • undefined
  • object

内置对象

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

复制对象

JSON对象的方法

这里我教大家一个简单的办法,通过JSON对象中的方法来实现


var obj1 = {
  a: {
    b: {
      c: {
        d: 1,
        e: 2
      }
    }
  },
  f: {
    g: 1
  },
  h: 2
}

var cacheObj = JSON.stringify(obj1)

var obj2 = JSON.parse(cacheObj);

Object.assgin浅复制

Object.assign(..) 方法的第一个参数是目标对象,之后还可以跟一个或多个源对象。它会遍历一个或多个源对象的所有可枚举

var obj1 = {
  a: 1,
  b: 2,
  c: {
    d: 3,
    e: 4
  }
}

var obj2 = Object.assign({}, obj1)

console.log(obj2 === obj1) // false

console.log(obj2.c === obj1.c) // true

属性描述符

属性描述符就是用来描述该属性的,value,writable,enumerable,configurable;

var obj1 = {
  a: 1,
  b: 2,
  c: {
    d: 3,
    e: 4
  }
}

var a = Object.getOwnPropertyDescriptor(obj1, 'a');

console.log(a) // { value: 1, writable: true, enumerable: true, configurable: true }

如你所见,我们用getOwnPropertyDescriptor所看到的属性描述,不仅仅能看到值是1,还能看到其他三个属性, writable (可写)、enumerable (可枚举)和 configurable (可配置)。

在创建普通属性时,属性描述符会使用默认值,我们可以用 defineProperty(..)来添加一个新的属性,或者当我们的configurable是可配置也就是ture的时候,可以对这个属性进行修改。

默认值

// 默认值
Object.defineProperty(obj1, 'a', {
  value: 1,
  writable: true,
  configurable: true,
  enumerable: true
})

定义不可写


var obj1 = {}

// 定义不可写属性
Object.defineProperty(obj1, 'b', {
  value: 22,
  writable: false,
  configurable: true,
  enumerable: true
})

obj1.b = 123;

console.log(obj1.b) // 22 不可被修改

定义不可配置

// 定义一个不可配置的属性

Object.defineProperty(obj1, 'c', {
  value: 3,
  writable: true,
  configurable: false,
  enumerable: true
})

Object.defineProperty(obj1, 'c', {
  value: 44444,
  writable: false,
  configurable: false,
  enumerable: false
})
// 走到这里时 并没有发现报什么错
// 但是 如果是这样

Object.defineProperty(obj1, 'c', {
  value: 3,
  writable: false,
  configurable: false,
  enumerable: false
})

// 报错
Object.defineProperty(obj1, 'c', {
  value: 3,
  writable: true,
  configurable: false,
  enumerable: true
})

// 除了无法修改, configurable:false 还会禁止删除这个属性

delete obj1.c;

console.log(obj1.c) // 3

需要注意,当configurable为false的时候,如果writable是ture或者enumerable是ture,之后是可以被修改成false的,但是不能由false修改成true.

Enumerable

var obj1 = {
  a: 1,
  b:2,
}

// 定义一个不可配置的属性

Object.defineProperty(obj1, 'c', {
  value: 3,
  writable: true,
  configurable: true,
  enumerable: false
})


for(let i in obj1){
  console.log(obj1[i]);//1 , 2
}

console.log(obj1.hasOwnProperty('c')) // true


结果显示 3 并没有被打印出来。

不变性

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

对象常量

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

禁止扩展

如果你想禁止一个对象添加新属性并且保留已有属性,可以使用 Object.preventExtensions(..)

var obj1 = {
  a: 1,
  b:2,
}

Object.preventExtensions(obj1)

obj1.c = 3

console.log(obj1.c) //undefined

密封

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

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

冻结

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

你可以“深度冻结”一个对象,具体方法为,首先在这个对象上调用 Object.freeze(..) ,然后遍历它引用的所有对象并在这些对象上调用 Object.freeze(..) 。但是一定要小心,因为这样做有可能会在无意中冻结其他(共享)对象。


[[get]]

当我们访问一个对象中的属性的时候,obj.a,其实不仅仅是在obj中查找是否有名为a的属性。

在语言规范中,其实obj实际上是实现了get操作,对象中默认内置的get方法首先在对象中查找是否有名称相同的属性,如果找到就会返回这个属性的值。如果没有找到就会寻找随着原型链向上查找。最终都没有找到的话就会返回undefined。

注意,这种方法和访问变量时是不一样的。如果你引用了一个当前词法作用域中不存在的变量,并不会像对象属性一样返回 undefined ,而是会抛出一个 ReferenceError 异常

[[put]]

Put被触发时,实际的行为取决于许多因素,包括对象中是否已经存在这个属性(这是最重要的因素)。

如果已经存在这个属性, Put 算法大致会检查下面这些内容。

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

如果对象中不存在这个属性, Put 操作会更加复杂。

Getter和Setter

对象默认的 [[Put]] 和 [[Get]] 操作分别可以控制属性值的设置和获取

在 ES5 中可以使用 getter 和 setter 部分改写默认操作,但是只能应用在单个属性上,无法应用在整个对象上。getter 是一个隐藏函数,会在获取属性值时调用。setter 也是一个隐藏函数,会在设置属性值时调用

当你给一个属性定义 getter、setter 或者两者都有时,这个属性会被定义为“访问描述符”(和“数据描述符”相对)。对于访问描述符来说,JavaScript 会忽略它们的 value 和writable 特性,取而代之的是关心 set 和 get (还有 configurable 和 enumerable )特性。

var obj1 = {
  // 给 a 定义一个 gette
  get a() {
    return 2;
  }
}

Object.defineProperty(obj1, 'b', {
  get: function () {
    return this.a * 2;
  },
  enumerable: true
})

obj1.a = 123214;

console.log(obj1.a) //2

console.log(obj1.b) //4

由于我们只定义了 a 的 getter,所以对 a 的值进行设置时 set 操作会忽略赋值操作,不会抛出错误。而且即便有合法的 setter,由于我们自定义的 getter 只会返回 2,所以 set 操作是没有意义的。

不管是对象文字语法中的 get a() { .. } ,还是 defineProperty(..) 中的显式定义,二者都会在对象中创建一个不包含值的属性,对于这个属性的访问会自动调用一个隐藏函数,它的返回值会被当作属性访问的返回值

通常来说 getter 和 setter 是成对出现的:

var obj1 = {
  // 给 a 定义一个 gette
  get a() {
    return this._a_;
  },
  set a(val) {
    this._a_ = val * 2;
  }
}

obj1.a = 2;

console.log(obj1.a) //4

代码中的a只是我们用来存储的一个空间,你也可以console.log(obj1.a_)来访问,没有实际意义

对象中的值是否存在

var obj1 = {
  a: undefined
}

console.log(obj1.a)

当我们访问obj1.a得到undefined的时候,我们怎么判断他是存储中的undefined还是不存在时返回的undefined呢

我们可以在不访问值的情况下判断这个属性是否存在

var obj1 = {
  a: undefined
}

console.log('a' in obj1) //true
console.log('b' in obj1) // false

console.log(obj1.hasOwnProperty('a')) // true
console.log(obj1.hasOwnProperty('b')) // false

in 操作符会检查属性是否在对象及其 [[Prototype]] 原型链中

hasOwnProperty(..) 只会检查属性是否在 myObject 对象中

propertyIsEnumerable(..) 会检查给定的属性名是否直接存在于对象中(而不是在原型链上)并且满足 enumerable:true 。

Object.keys(..) 会返回一个数组,包含所有可枚举属性, Object.getOwnPropertyNames(..)会返回一个数组,包含所有属性,无论它们是否可枚举。

遍历

  • forEach : forEach(..) 会遍历数组中的所有值并忽略回调函数的返回值

  • every : every(..) 会一直运行直到回调函数返回 false (或者“假”值)

  • some : some(..) 会一直运行直到回调函数返回 true (或者“真”值)。

  • for...of

  • for...in

  • for循环

其中 forEach every some 属于数组

iterator

for..of 循环首先会向被访问对象请求一个迭代器对象,然后通过调用迭代器对象的next() 方法来遍历所有返回值。

数组有内置的 @@iterator ,因此 for..of 可以直接应用在数组上。我们使用内置的 @@iterator 来手动遍历数组,看看它是怎么工作的:

var myArray = [ 1, 2, 3 ];
var it = myArray[Symbol.iterator]();
it.next(); // { value:1, done:false }
it.next(); // { value:2, done:false }
it.next(); // { value:3, done:false }
it.next(); // { done:true }

和数组不同,普通的对象没有内置的 @@iterator ,所以无法自动完成 for..of 遍历。

给对象定义iterator

var obj = {
  a: 1,
  b: 2
}

Object.defineProperty(obj, Symbol.iterator, {
  enumerable: false,
  writable: false,
  configurable: true,
  value: function () {
    var o = this;
    var idx = 0;
    var ks = Object.keys(o);
    return {
      next: function () {
        return {
          value: o[ks[idx++]],
          done: (idx > ks.length)
        }
      }
    }
  }
})

var i = obj[Symbol.iterator]();

console.log(i.next()) // { value: 1, done: false }
console.log(i.next()) // { value: 2, done: false }
console.log(i.next()) // { value: undefined, done: true }

for(let v of obj) {
  console.log(v) // 1 , 2
}



最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,444评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,421评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,036评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,363评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,460评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,502评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,511评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,280评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,736评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,014评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,190评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,848评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,531评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,159评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,411评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,067评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,078评论 2 352

推荐阅读更多精彩内容