IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> JavaScript知识库 -> 回顾definePropety方法 -> 正文阅读

[JavaScript知识库]回顾definePropety方法

definePropety

?顾名思义,这个方法就是给对象添加属性的方法,属于es6的知识点。

默认情况下,使用?Object.defineProperty()?添加的属性值是不可修改(immutable)的。?

这个方法传递三个参数,分别是 给? 哪个对象? 添加? 哪个属性,且 这个属性需要做什么配置

配置项存在四个属性,分别是 value,enumerable,writable,configurable

?value:该属性对应的值。可以是任何有效的 JavaScript 值(数值,对象,函数等)。默认为?undefined

// 定义对象
let person = {
  name: '张三',
  six: '男'
}

Object.defineProperty(person, 'age', {})

console.log(person, 'person')

??

?给定一个值之后

// 定义对象
let person = {
  name: '张三',
  six: '男'
}

Object.defineProperty(person, 'age', {
  value: 22
})

?

但是这个age属性,颜色较浅,这又是为什么呢?

for (const i in person) {
  console.log(i, 'i')
}

通过 遍历之后,我们发现,控制台上只有 原先的两个属性,新增加的 age 属性,则是没有被遍历到,这是因为??defineProperty 的 第三个参数配置项,有一个默认配置项? enumerable 会控制属性是否能被枚举?

enumerable :? ?当且仅当该属性的?enumerable?键值为?true?时,该属性才会出现在对象的枚举属性中。默认为?false所以在for...in? 遍历 或者 Object.keys()? 遍历时,才会无法打印出来

// 定义对象
let person = {
  name: '张三',
  six: '男'
}

Object.defineProperty(person, 'age', {
  value: 22,
  enumerable: true
})

console.log(person, 'person')

for (const i in person) {
  console.log(i, person[i])
}

?

可以看到,我将 默认的??enumerable : false? 改为了 true ,遍历的时候,控制台上就展示了所有的属性,且 person 对象属性颜色一致,这就是配置 为 是否可枚举的属性

?writable:这个就是控制新增的属性是否可以修改,默认为false不能修改属性值

// 定义对象
let person = {
  name: '张三',
  six: '男'
}

Object.defineProperty(person, 'age', {
  value: 22,
  enumerable: true,
  // writable:true
})

console.log(person, 'person')    // {name: '张三', six: '男', age: 22}
person.age = 18
console.log(person, 'person')    // {name: '张三', six: '男', age: 22}
// 改变属性值无效

?设置为 true 之后,就变成了可修改的属性

// 定义对象
let person = {
  name: '张三',
  six: '男'
}

Object.defineProperty(person, 'age', {
  value: 22,
  enumerable: true,
  writable:true   //  控制是否能改变属性值
})

console.log(person, 'person')    // {name: '张三', six: '男', age: 22}
person.age = 18
console.log(person, 'person')    // {name: '张三', six: '男', age: 18}
// 改变了属性值

?

?configurable :控制属性是否能被删除,默认是 false 不能被删除的

?通过正常方式定义的对象属性,是可以删除的,例如下面的 通过字面量创建的 person 对象属性

// 定义对象
let person = {
  name: '张三',
  six: '男'
}

console.log(person, 'person')
delete person.name
console.log(person, 'person')

?

?但是,通过?defineProperty 添加的属性,且?configurable:?false 之后,该属性则不能被删除

// 定义对象
let person = {
  name: '张三',
  six: '男'
}

Object.defineProperty(person, 'age', {
  value: 22,
  enumerable: true,
  writable: true,
  configurable: false  //默认为false,不能删除该属性
})

console.log(person, 'person')
delete person.age
console.log(person, 'person')

?

但是,将?configurable: true? 之后,该属性则是可以删除的了

// 定义对象
let person = {
  name: '张三',
  six: '男'
}

Object.defineProperty(person, 'age', {
  value: 22,
  enumerable: true,
  writable: true,
  configurable: true
})

console.log(person, 'person')
delete person.age
console.log(person, 'person')

?

??

除了这四个用来配置属性的方法,还存在两个读取的方法,分别是 get() 和 set() 两个函数

?get() : 属性的 getter 函数,如果没有 getter,则为?undefined。当访问该属性时,会调用此函数。执行时不传入任何参数,但是会传入?this?对象(由于继承关系,这里的this并不一定是定义该属性的对象)。该函数的返回值会被用作属性的值。默认为?undefined

?下面这段代码,我向? person 对象内部添加了 age 属性,且值为 18,该属性,可枚举、可修改、可删除,然后我接着写了 get() 方法,用来做读取这个操作,也就是访问这个 age 属性时,返回一个值,这个时候就出问题了。

// 定义对象
let person = {
  name: '张三',
  six: '男'
}

Object.defineProperty(person, 'age', {
  value: 18,          //默认 undefined 属性值
  enumerable: true,   // 默认 false  ,禁止枚举
  writable: true,     // 默认 false ,禁止修改
  configurable: true,  // 默认 false , 禁止删除

  // get函数( 通常叫做 getter ),当访问该属性时,会自动调用此函数,
  // 默认传入this对象,函数的返回值会被作为 该属性的值
  get() { return 'bValue'; },
})

console.log(person, 'person')

?这个错误解释一下就是:?使用Object.defineProperty() 定义对象属性时,如已设置 set 或 get, 就不能设置 writable 和 value 中的任何一个了,所有关于value的操作都由get和set代理了。

?所以我们需要把 value 和??writable? 属性删除,如下

Object.defineProperty(person, 'age', {
  // value: 18,          //默认 undefined 属性值
  enumerable: true,   // 默认 false  ,禁止枚举
  // writable: true,     // 默认 false ,禁止修改
  configurable: true,  // 默认 false , 禁止删除

  // get函数( 通常叫做 getter ),当访问该属性时,会自动调用此函数,
  // 默认传入this对象,函数的返回值会被作为 该属性的值
  get() { return 'bValue'; },
})

?结果如下,三个属性都是存在的,此时 age 属性 的值没有展示出来,且多了一个 get age() 这个方法,我们点击 age 的属性值,发现 和我们在 get 函数内部返回的值 是一样的

?这就印证了,为什么不让写 value 这个属性,因为 get 函数 返回的值,默认成为了 value 的值

那么?writable 对应的 set 又是什么样的呢?

set()?:属性的 setter 函数,如果没有 setter,则为?undefined。当属性值被修改时,会调用此函数。该方法接受一个参数(也就是被赋予的新值),会传入赋值时的?this?对象。
默认为?undefined

Object.defineProperty(person, 'age', {
  // value: 18,          //默认 undefined 属性值
  enumerable: true,   // 默认 false  ,禁止枚举
  // writable: true,     // 默认 false ,禁止修改
  configurable: true,  // 默认 false , 禁止删除

  // get函数( 通常叫做 getter ),当访问该属性时,会自动调用此函数,
  // 默认传入this对象,函数的返回值会被作为 该属性的值
  get() { return 'bValue'; },

  // 当修改 age 的值时,set函数( settter )就会被调用,且会受到修改的具体值
  set(x) {
    console.log('age被修改了,且值是,', x)
  }
})

set函数被调用时,会触发这个 console,我们来看看控制台上输出了什么

在改变了 age 属性的值之后,我们看到控制台上打印出了set()函数内部的console,但是我们再次输出 person 对象的时候,发现 person 对象中 age 属性值并没有发生改变,这是因为,我们只是接收到了需要改变的值,但是并没有将新的值 赋值 给 age 属性,但是如果我们直接 赋值,则会出现下面的情况

?1、直接赋值

Object.defineProperty(person, 'age', {
  // value: 18,          //默认 undefined 属性值
  enumerable: true,   // 默认 false  ,禁止枚举
  // writable: true,     // 默认 false ,禁止修改
  configurable: true,  // 默认 false , 禁止删除

  // get函数( 通常叫做 getter ),当访问该属性时,会自动调用此函数,
  // 默认传入this对象,函数的返回值会被作为 该属性的值
  get() { return 'bValue'; },

  // 当修改 age 的值时,set函数( settter )就会被调用,且会收到修改的具体值
  set(x) {
    console.log('age被修改了,且值是,', x)
    age = x
  }
})

?

此时我们会发现,这改了和没改一样,根本没生效啊,这是因为 set() 函数内部的 age ,根本就不是 我们通过 definepropetry() 新增的age 属性

2、通过this.age 赋值

?因为之前说过,set 和 get 会默认将 this 传递进去,所以,我们使用 this.age 来赋值。

Object.defineProperty(person, 'age', {
  // value: 18,          //默认 undefined 属性值
  enumerable: true,   // 默认 false  ,禁止枚举
  // writable: true,     // 默认 false ,禁止修改
  configurable: true,  // 默认 false , 禁止删除

  // get函数( 通常叫做 getter ),当访问该属性时,会自动调用此函数,
  // 默认传入this对象,函数的返回值会被作为 该属性的值
  get() { return 'bValue'; },

  // 当修改 age 的值时,set函数( settter )就会被调用,且会收到修改的具体值
  set(x) {
    console.log(this, 'this')
    console.log('age被修改了,且值是,', x)
  }
})

在调用 set() 方法之后,我们能看到,打印出的 this 内部,是存在 age 属性的,所以按道理来说,我们使用 this.age = x 来说是能成功修改 age 的属性值的

?但是实际上,在我进行赋值操作之后,出现了一个我没想到的问题

Object.defineProperty(person, 'age', {
  // value: 18,          //默认 undefined 属性值
  enumerable: true,   // 默认 false  ,禁止枚举
  // writable: true,     // 默认 false ,禁止修改
  configurable: true,  // 默认 false , 禁止删除

  // get函数( 通常叫做 getter ),当访问该属性时,会自动调用此函数,
  // 默认传入this对象,函数的返回值会被作为 该属性的值
  get() { return 'bValue'; },

  // 当修改 age 的值时,set函数( settter )就会被调用,且会收到修改的具体值
  set(x) {
    console.log('age被修改了,且值是,', x)
    this.age = x
  }
})

?

?set() 方法被调用了很多很多次,直到最后堆栈溢出才停止调用,这说明这样也是不可取的,那么,我想修改属性的值,应该怎么做呢?

其实很简单,我们在外面定义一个变量,用来存储 age 的属性值,然后通过 get() 函数将 number的值返回出去,这样的话,在外部访问 age 属性时,就会走 get() 函数,然后 将当前的 number 的值返回出去,那么在修改的时候,就会调用 set()? 方法,然后动态的改变 number 的值

// 定义 number
let number = 18

// 定义对象
let person = {
  name: '张三',
  six: '男'
}

Object.defineProperty(person, 'age', {
  // value: 18,          //默认 undefined 属性值
  enumerable: true,   // 默认 false  ,禁止枚举
  // writable: true,     // 默认 false ,禁止修改
  configurable: true,  // 默认 false , 禁止删除

  // get函数( 通常叫做 getter ),当访问该属性时,会自动调用此函数,
  // 默认传入this对象,函数的返回值会被作为 该属性的值
  get() { return number },

  // 当修改 age 的值时,set函数( settter )就会被调用,且会收到修改的具体值
  set(x) {
    console.log('age被修改了,且值是,', x)
    number = x
  }
})

?

?本章总结

1、defineProperty 方法接收三个参数,第一个参数是需要改变的对象,第二个参数是,需要添加的属性,第三个参数则是一个可配置的 json对象,用来配置 添加的属性

2、配置对象内部存在四个属性和两个方法

四个属性分别是

  • value: xxx,??????????// 设置新增属性的值,默认?undefined?属性值,可以是任何类型的值

  • enumerable:?true,???// 设置新增属性是否能被枚举,默认?false??,禁止枚举

  • writable:?true,?????// 设置新增属性是否能被修改,默认?false?,禁止修改

  • configurable:?true,??// 设置新增属性是否能被删除,默认?false?,?禁止删除

两个方法分别是

  • get(){} : get函数(?通常叫做?getter?),当访问该属性时,会自动调用此函数,默认传入this对象,函数的返回值会被作为?该属性的值
  • set(){} :?当修改?age?的值时,set函数(?settter?)就会被调用,且会收到修改的具体值

ps : 一般会将新增的属性的属性值,通过一个变量定义在外部,而不是直接写死,这是因为,在set() 的时候,无法同步修改 该属性值。定义在外的属性值,其实和 需要改变的对象 是两个不想管的东西,但是通过??defineProperty? 连接了起来,你要访问属性值,我就去给你现取,你想修改属性值,我也给你同步修改 外部变量的值,想访问新的值了,再去调用 新的 get() 取到新的值返回

  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章      下一篇文章      查看所有文章
加:2021-10-06 12:08:27  更:2021-10-06 12:10:50 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/18 22:07:28-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码