js--对象

207 阅读6分钟

js -- 对象

七种原始类型,值只包含一种东西(数字,字符串...)。

对象则用来存储键值对和更复杂的实体。

对象属性的值可以是任意类型。

创建方式

字面量:let obj = { key:value};

构造函数:let obj = new Object();

let obj = {
    name:'名字',
    age:30
}
let obj1 = new Object();
console.log(obj1) // {}

操作

我们可以在对象创建后进行增,删,改,查的操作。

object.属性名 = 属性值

操作返回对应的属性值

let obj = {}
let res = (obj.name = 'zhangsan')
console.log(obj)
console.log(res)
// {name: "zhangsan"}
// 'zhangsan'

**delete object.属性名 **

返回操作结果 布尔值

let obj = {name: "zhangsan", age: 30}
let res = (delete obj.name)
console.log(obj)
console.log(res)
// {age: 30}
// true

object.属性名 = 新的属性值

返回新的属性值

 let obj = { name: "zhangsan" }
 let res = (obj.name = "lisi")
 console.log(obj)
 console.log(res)
 // {name: "lisi"}
 // 'lisi'

**object.属性名 **

返回对应的属性值,值不存在,返回undefined

let obj = { name: "zhangsan" }
let res = obj.name
 console.log(res)
 // 'zhangsan'

[] vs .

除了使用.对对象操作,也可以使用[]方式对对象进行操作。

用法:obj[属性名]

.点符号要求 key 是有效的变量标识符。这意味着:不包含空格,不以数字开头,也不包含特殊字符(允许使用 $_)。

[] 方括号可以操作多词属性。

let obj = {}
 obj.ni hao = 'lisi' // Uncaught SyntaxError: Unexpected identifier
 ==============================
 obj["ni hao"] = 'lisi'
 console.log(obj) //{ni hao: "lisi"}

[]方括号 可以通过任意表达式来获取属性名的方法。

 let key = "name"
 let obj = {}
 obj.key = true
 console.log(obj)  //{key: true}
 obj[key] = false
 console.log(obj)  // {key: true, name: false}

计算属性:

当创建一个对象时,我们可以在对象字面量中使用[]方括号动态设置属性。

可以在方括号中使用复杂的表达式或者变量。

let obj = { [key]:value }

let key = "name"
let obj = { [key]: 5}
console.log(obj)   // {name: 5}
console.log(obj.name)  // 5 

属性值简写:

我们通常将已存在的变量当做属性值。

当对象中属性和属性值变量名字相同时,可以简写。

属性值简写和正常方式可以共用。

  let name = "zhangsan"
  let obj = {
    name, // 等价于 name: name
    age: 23
   }
//  {name: "zhangsan", age: 23}

属性名

js中变量命名不能是保留字(let、for等 ),对象的属性名没有这种限制。

 let obj = {
   class: "zhangsan",
   for: 23
 }
 console.log(obj) //  {class: "zhangsan", for: 23}
 console.log(obj.class) // zhangsan

但是设置__proto__为属性名时,只能设置对象,不能设置非对象值,非对象值会被忽略。

let obj = { name: "zhangsan" }
 obj.__proto__ = 5
 console.log(obj.__proto__)  // {...}
 obj.__proto__ = { name: "123" }
 console.log(obj.__proto__)  // {name: "123"}

不使用冒号.标记的属性定义,不会变更对象的原型。

而是和其他具有不同名字的属性一样是普通属性定义。

let obj = { name: "zhangsan" }
 obj[__proto__] = 5
 console.log(obj[__proto__])
 console.dir(obj)
// 5 
// { [object Window]: 5, name: "zhangsan",__proto__: Object }

属性名可以是任何字符串或者 symbol,其他类型会被自动地转换为字符串。

let obj1 = { age: 23 }
let obj = { name: "zhangsan", 0: 123, [obj1]: 123 }
 console.log(obj)
 console.log(obj["0"])
 console.log(obj[0])
// {name: "zhangsan", [object Object]: 123}
// 123
// 123

in 操作符

检测属性是否存在。

js对象能够访问任何属性。即使属性不存在也不会报错。读取不存在的属性只会得到 undefined

in 的左边必须是 属性名。通常为字符串。

let obj = { age: 23, name: undefined }
console.log("name" in obj)
console.log("name1" in obj)
// true
// false

for in

用法:for (let key in obj) {}

遍历一个对象的所有键(key)。

 let obj = { name: "John", age: 30,  isAdmin: true  }
  for (let key in obj) {
        console.log(key)
  }
//name  age  isAdmin

对象属性排序

整数属性会被进行排序,其他属性则按照创建的顺序显示。

  let obj = {  name: "John", 3: "val3", 0: "val0",
                2: "val2", 1: "val1"
       }
    obj.age = 23
    console.log(obj)
//{0: "val0", 1: "val1", 2: "val2", 3: "val3", name: "John", age: 23}

“整数属性”指的是一个可以在不做任何更改的情况下与一个整数进行相互转换的字符串。

“49” 是一个整数属性名,因为我们把它转换成整数,再转换回来,它还是一样的。但是 “+49”, 就不行

// Math.trunc 是内置的去除小数部分的方法。
String(Math.trunc(Number("49"))) ; // "49",相同,整数属性
String(Math.trunc(Number("+49"))); // "49",不同于 "+49" ⇒ 不是整数属性
String(Math.trunc(Number("1.2"))); // "1",不同于 "1.2" ⇒ 不是整数属性

对象的引用

与原始类型相比,对象的根本区别之一是对象是通过引用被存储和复制的。

赋值了对象的变量存储的不是对象本身,而是该对象“在内存中的地址”,换句话说就是对该对象的“引用”。

当一个对象变量被复制 —— 引用则被复制,而该对象并没有被复制。

更改其中一个对象,另一个对象也可以看到修改(也就是说修改一个对象,另一个对象也会受到影响)。

  let obj = { name: "zhangsan", age: 23 }
  let obj1 = obj
  console.log(obj1) // {name: "zhangsan", age: 23}
  obj1.name = "lisi"
  console.log(obj) // {name: "lisi", age: 23}

比较

对象之间的比较,只有当两个对象为同一对象时,两者才相等。

let obj = { name: "zhangsan" }
let obj1 = obj
let obj2 = { name: "zhangsan" }
console.log(obj === obj1)  // true
console.log(obj === obj2)  // false

对象方法

对象属性的函数被称为 方法

let obj = {
      sayHi: function() {
                 console.log("hello")
             }
  }
 obj.sayHi() // hello

方法简写

 let obj = {
     sayHi() {  // 等价于 sayHi: function() {}
        console.log("hello")
      }
 }
 obj.sayHi()
this

为了访问对象,方法中可以使用 this 关键字。

this 的值就是在点之前的这个对象,即调用该方法的对象。

 let obj = {
     sayHi() {
       console.log(this)
      }
 }
 obj.sayHi() // {sayHi: ƒ}

可选链 "?."

可选链 ?. 允许读取位于连接对象链深处的属性的值,而不必明确验证链中的每个引用是否有效。

?. 操作符的功能类似于 . 链式操作符,不同之处在于,在引用为空 (null 或者 undefined) 的情况下不会引起错误,该表达式短路返回值是 undefined

可选链 ?. 前面的部分是 undefined 或者 null,它会停止运算并返回该部分。

可以连续进行使用。

 let obj = {name:{  age:30 }}
 console.log(obj?.name?.age)  // 30
 console.log(obj?.address?.street)  // undefined
 console.log(obj.address.street) // Cannot read property 'street' of undefined

?. 前的变量必须已声明

console.log(user?.name) // user is not defined

不要过度使用可选链如果根据我们的代码逻辑,user 对象必须存在,但 address 是可选的,那么我们应该这样写 user.address?.street,而不是这样 user?.address?.street

其它变体:?.(),?.

可选链 ?. 不是一个运算符,而是一个特殊的语法结构。它还可以与函数和方括号一起使用。

?.() 用于调用一个可能不存在的函数, 不存在返回undefined而不是抛出一个异常。

?.[] 可以用来访问属性。

 let key = "name"
 let key1 = "age"
 let obj = {
    name: "zhangsan",
    sayHi() {
       return "Hi"
    }
  }
 console.log(obj.sayHi?.()) // Hi
 console.log(obj.say?.())  // undefined
 console.log(obj?.[key])   // zhangsan
 console.log(obj?.[key1])  // undefined

还可以将 ?. 可选链跟 delete 一起使用。

let obj = {
    name: "zhangsan",
    age: 30
  }
console.log(delete obj?.name) // true
console.log(obj) // {age: 30}

?. 来安全地读取或删除,但不能写入

可选链 ?. 不能用在赋值语句的左侧。

  let obj = { name: "zhangsan" }
 console.log(obj?.name = 'lisi') //Invalid left-hand side in assignment

其他方法:&&,if ?:都可以实现相同的效果。