Javascript之对象基础
对象
创建对象的两种方式:
1 | let user = new Object(); // 构造函数法 |
属性的访问和设置值,删除变量,有两种方式:
1 | // method 1: |
属性值的限制和简写:
1 | // 在能过{}方式创建对象时,可使用多字词来做为属性的key |
循环获取对象:
1 | let user = { |
引用和复制
对象的值是引用。
1 | let user1 = { |
如果要通过赋值,将两个对象分来,就需要使用克隆。javascript内置有Object.assign,这这个克隆不够深:
1 | let user1 = { |
真正的深层克隆,可用 JavaScript 库 lodash 中的 _.cloneDeep(obj) 函数:
1 | _ = require('lodash'); |
对象方法
可以给对象创建方法,类似其它语言的 class method:
1 | let user = { |
类方法可写在类构造时:
1 | let user = { |
javascript 中的this,比其它语言中的this关键字更加宽范。他指定的内容是在运行时计算出来的。如:
1 | const user = {name: "Tom"}; |
this 并没有严格的与某个对象绑定。在javascript中,this比较自由。
注意:箭头头函数没有 this,如果在箭头函数中引用this,会取来自箭头函数外部的this,如:
1 | let user = { |
构造器 new
除了常规的 {…}来创建对象,也可以使用构造器。对于要多次创建的对象,用构造器更便捷。构造器函数实际上是个常规函数,有两个约定:
- 以大写字母开头
- 只能由 new 来执行
构造器执行时,由三个流程:
- 创建空对象{},并赋值给 this
- 执行函数体。
- 返回this
如:
1 | function User(name) { |
new 可以让任何函数以这种方式执行。但一般我们用于构建函数时,以大写字母命名,由new执行。
如果任何函数都可以被new来使用,那如何判断这个调用,是否是被new创建的呢?在函数内部,可使用 new.target 函数来测试是否是由new来创建的。如果不是new创建的,由返回undefined;否则,返回函数。
1 | function User(name) { |
构造器的return
构造器一般无 return 语句
- 如果构造器返回一个对象,则使用这个对象返回,而代替this
- 如果构造器返回一个原始类型,则忽略。就像没这句一亲。
1 | function User1(name) { |
可选链
对于一个对象,我们可能会像这样的方式访问其属性值:user.address.city.name。但有可能其address未设置,而直接访问 user.address.city.name 就会报错,而我们想其返回undefined亦或null.
我们可以在user到name中,从根一步步的判断是否存在,存在再取下一步。这种方式可行,但代码太难看。
在javascript中有个可选链的操作,可优雅的达到此目的,使用方法为 value?.prop,他执行下面的操作:
- 如果value为undefined或null,则返回undefined
- 如果value存在,则返回 value.prop
如下:
1 | const user = { |
可选链可用于函数和计算属性:
?.()或 ?.[]
也可用于删除属性:
delete user?.address
总之,可选链 ?. 语法有三种形式:
obj?.prop—— 如果obj存在则返回obj.prop,否则返回undefined。obj?.[prop]—— 如果obj存在则返回obj[prop],否则返回undefined。obj.method?.()—— 如果obj.method存在则调用obj.method(),否则返回undefined。
Symbol
复习一下javascript中的原始类型,共有7种:
- string
- number
- bigint
- boolean
- symbol
- undefined
- null
Symbol 的值是一个唯一的标识符,每次调用时不同。他在内部是不同的值,但在打印时,他的默认的 toString() 方法只展示其信息和id标识,并不显示唯一的标识信息值。如:
1 | const id1 = Symbol("id"); |
Symbol 的作用
Symbol 的最大作用,是允许我们创建对象的隐藏属性。比如我们引用第三方代码中的user对象,但我们想添加个标识符,又不想破坏原有代码,我们就可以起一个特殊的键来存放我们的属性值,而原有代码因不知道这个键,而不会感知到我们添加了内容。同时,Symbol对象在迭代时,会被忽略。
如:
1 | let user = { // 第三方代码中的数据 |
在迭代时,Symbol对象会被忽略,如:
1 | const id1 = Symbol("id1"); |
当克隆一个对象时, Symbol 会被克隆:
1 | let user = { |
全局 symbol
系统中有个全局 Symbol 符号表。当通过 Symbol.for(key)来创建Symbol时,他会创建并返回一个Symbol对象,同时记录在全局符号表中。当符号表中存在同名的Symbol时,则会返回已存在的Symbol。
反之,也可通过 Symbol.keyFor(sym:symbol)来把Symbol转换为标识符。
1 | let s1 = Symbol.for("id"); |
对象和原始值
JavaScript 允许我们像使用对象一样使用原始类型。
原始类型是一个原始值,就是7种原始类型中的任何一种的值。
对象,可以存储多个属性;可以使用{…}的方式创建且可以包含函数
原始类型,有很多的方法,而为了实现这些操作方法,内部通过包装器来实现。而包装器只在使用期间存在,用后即毁。如:
1 | const str = "Hello world!"; |
在访问字符串的 toUpperCase方法时,
- str是个原始值。访问其方法,需要创建一个包装对象,此对象有其用到的方法
- 包装器的方法被执行,将返回值给调用者。
- 中间的包装器对象销毁
注意:原始类型的构造器仅供内部使用,自己的代码中不要使用,容易出现问题。而不在new的构造方法可以使用。
1 | console.log(`typeof new Number(0): ${typeof new Number(0)}`); |
undefined和null没包装器,也没任何方法。


