彻底搞懂Object(1),文末有福利

descriptor中的存取描述符

OK,我们介绍了descriptor中的数据描述符相关的vaulewritbale,接着聊聊有趣的存取描述符,也就是在vue中也出现过getter、setter方法。

我们知道,JavaScript中对象赋值与取值非常方便,有如下两种方式:

let o = {};

// 通过.赋值取值

o.name = ‘echo’;

//通过[]赋值取值,这种常用于key为变量情况

o[‘age’] = 27;

一个很直观的感受就是,对象赋值就是种瓜得瓜种豆得豆,我们给对象赋予了什么,获取的就是什么。那大家有没有想过这种情况,赋值时我提供1,但取值我希望是2。巧了,这种情况我们就可以使用Object.defineProperty()中的存取描述符来解决这个需求。说直白点,存取描述符给了我们赋值/取值时数据劫持的机会,也就就是在赋值与取值时能自定义做一些操作,

getter函数在获取属性值时触发,注意,是你为某个属性添加了getter在获取这个属性才会触发,如果未定义则为undefined,该函数的返回值将作为你访问的属性值。

setter函数在设置属性时触发,同理你得为这个属性提前定义这个方法才行,设置的值将作为参数传入到setter函数中,在这里我们可以加工数据,若未定义此方法默认也是undefined。

OK,让我们用gettersetter模拟最常见的对象赋值与取值,看个例子:

let o = {};

o.name = ‘听风是风’;

o.name; // ‘听风是风’

//使用get set模拟赋值取值操作

let age;

Object.defineProperty(o, ‘age’, {

get() {

// 直接返回age

return age;

},

set(val) {

// 赋值时触发,将值赋予变量age

age = val;

}

});

o.age = 18;

o.age; // 18

在上面例子模拟中,只要为o赋值setter就会触发,并将值赋予给age,那么在读取值getter直接返回变量age即可。

OK,到这里我们顺利学习了存取描述符settergetter

descriptor中的共有属性

最后,让我们了解剩余两个属性configurableenumerable

enumerable值类型为Boolean,表示该属性是否可被枚举,啥意思?我们知道对象中有个方法Object.keys()用于获取对象可枚举属性,比如:

let o = {

name: ‘听风是风’,

age: 27

};

Object.keys(o); // [‘name’,‘age’]

通俗点来说,上面例子中的两个属性还是可以遍历访问的,但如果我们设置enumerable为false,就会变成这样:

let o = {

name: ‘听风是风’

};

Object.defineProperty(o, ‘age’, {

value: 27,

enumerable: false

});

// 无法获取keys

Object.keys(o); // [‘name’]

// 无法遍历访问

for (let i in o) {

console.log(i); // ‘name’

};

configurable的值也是Boolean,默认是false,configurable 特性表示对象的属性是否可以被删除,以及除 value 和 writable 特性外的其他特性是否可以被修改。

先说删除,看个例子:

let o = {

name: ‘听风是风’

};

Object.defineProperty(o, ‘age’, {

value: 27,

configurable: false

});

delete o.name;//true

delete o.age;//false

o.name;//undefined

o.age;//18

删除好说,我们来看看它对于其它属性的影响,看个例子:

var o = {};

Object.defineProperty(o, ‘name’, {

get() {

return ‘听风是风’;

},

configurable: false

});

// 报错,尝试通过再配置修改name的configurable失败,因为已经定义过了configurable

Object.defineProperty(o, ‘name’, {

configurable: true

});

//报错,尝试修改name的enumerable为true,失败,因为未定义默认为false

Object.defineProperty(o, ‘name’, {

enumerable: true

});

//报错,尝试新增set函数,失败,一开始没定义set默认为undefined

Object.defineProperty(o, ‘name’, {

set() {}

});

//尝试再定义get,报错,已经定义过了

Object.defineProperty(o, ‘name’, {

get() {

return 1;

}

});

// 尝试添加数据描述符中的vaule,报错,数据描述符无法与存取描述符共存

Object.defineProperty(o, ‘name’, {

value: 12

});

由于前面我们说了,未定义的属性虽然没用代码写出来,但它们其实都有了默认值,当configurable为false时,这些属性都无法被重新定义以及修改。

其它注意点

那么到这里,我们把descriptor中所有属性都介绍完了,在使用中有几点需要强调,这里再汇总一下。

前面概念已经提出对象属性描述符要么是数据描述符(value,writable),要么是存取描述符(get,set),不应该同时存在两者描述符。

var o = {};

Object.defineProperty(o, ‘name’, {

value: ‘时间跳跃’,

get() {

return ‘听风是风’;

}

});

这个例子就会报错,其实不难理解,存取方法就是用来定义属性值的,value也是用来定义值的,同时定义程序也不知道该以哪个为准了,所以用了value/writable其一,就不能用get/set了;不过configurableenumerable这两个属性可以与上面两种属性任意搭配。

我们在前面已经说了各个属性是有默认值的,所以在用Object.defineProperty()时某个属性没定义不是代表没用这条属性,而是会用这条属性的默认值。

let o = {};

Object.defineProperty(o, ‘name’, {

value: ‘时间跳跃’

});

//等同于

Object.defineProperty(o, ‘name’, {

value: ‘时间跳跃’,

writable: false,

enumerable: false,

configurable: false

});

同理,以下代码也对等:

var o = {};

o.name = ‘听风是风’;

//等同于

Object.defineProperty(o, ‘name’, {

value: ‘听风是风’,

writable: true,

enumerable: true,

configurable: true

});

//等同于

let name = ‘听风是风’;

Object.defineProperty(o, ‘name’, {

get() {

return name;

},

set(val) {

name = val;

},

enumerable: true,

configurable: true

});

关于属性分类与默认值,如下表:

|

| configurable | enumerable | value | writable | get | set |

| — | — | — | — | — | — | — |

| 数据描述符 | 可以 | 可以 | 可以 | 可以 | 不可以 | 不可以 |

| 存取描述符 | 可以 | 可以 | 不可以 | 不可以 | 可以 | 可以 |

| 默认值 | false | false | false | false | undefined | undefined |

现学现用,趁热打铁

=========

那么到这里,我们详细介绍了Object.defineProperty相关属性与用法,趁热打铁,我们活用它来解决一些问题。原本我想通过模拟vue数据双向绑定,模拟const以及解决文章开头面试题,但碍于文章篇幅确实过长了,const模拟大家感兴趣可自行百度,vue数据双向绑定我会另起一篇文章,所以这里就来解决文章开头的题目好了。

我们提取题目细节,年龄只接受正整数(在set中判断),毕竟没人是负年龄,其次对应范围有对应的年龄段,根据年龄返回对应年龄段即可(在get中操作);

这里直接上function的实现:

function Person() {

// 初始化年龄

let age;

Object.defineProperty(this, “age”, {

get() {

let ageRange = [41, 20, 0],

level = [‘老年’, ‘中年’, ‘少年’];

for (let i = 0; i < ageRange.length; i++) {

// 根据年纪大小返回对应范围

if (age >= ageRange[i]) {

return level[i];

};

};

},

set(val) {

// 年龄只保存正整数

val >= 0 ? age = val : null;

}

});

};

let p = new Person();

p.age = 1;

console.log(p.age); // ‘少年’

p.age = 39;

console.log(p.age); // ‘中年’

p.age = 41;

console.log(p.age); // ‘老年’

值得一提的是,实现代码中我们将需要年龄与相关返回值配置成了数组,而非常理上的if...else if...,这样做的好处是即便修改年龄或者增加年龄范围,我们要做的也仅仅是修改数组配置即可,而不需要对逻辑层中添加更多的if...else。更多条件判断优雅写法欢迎阅读博主这篇文章 提升代码幸福度,五个技巧减少js开发中的if else语句

为什么我不用ES6的class类来实现上面的操作了,因为公司不允许使用ES6,去年学的关于类好多都忘记了…整理这篇文章也花了好长时间,脑袋有点沉,这个改写就留给各位强大的网友吧。

那么到这里,关于Object.defineProperty的介绍就结束了。

补充

==

关于上面这道题,考察的虽然是Object.definedProperty的getter与setter,不过出题人的本意不是希望这么用的,任何对象在定义时候可以添加get,set方法,比如:

let p = {

age_: 27,

name: ‘echo’,

get age() {

return this.age_;

},

get name() {

return ‘听风是风’

}

};

p.name; // 听风是风

p.age; // 27

那么知道了这一点,我们来按照出题人的本意来分别实现上面的题目,首先是function情况:

function Person() {

// 初始化年龄

this.age_ = undefined;

};

// 在函数原型上定义age的get,set方法

Person.prototype = {

get age() {

let ageRange = [41, 20, 0],

level = [‘老年’, ‘中年’, ‘少年’];

for (let i = 0; i < ageRange.length; i++) {

// 根据年纪大小返回对应范围

if (this.age_ >= ageRange[i]) {

return level[i];

};

};

},

set age(val) {

// 年龄只保存正整数

val >= 0 ? this.age_ = val : null;

}

}

let p = new Person();

p.age = 1;

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数前端工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:前端)

最后

文章到这里就结束了,如果觉得对你有帮助可以点个赞哦,如果有需要前端校招面试题PDF完整版的朋友可以点击这里即可免费获取,包括答案解析。

滞不前!**

因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

[外链图片转存中…(img-ubB0RNvE-1712340156868)]

[外链图片转存中…(img-wlRyqgmu-1712340156869)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!

[外链图片转存中…(img-QCqOzoIH-1712340156869)]

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:前端)

最后

文章到这里就结束了,如果觉得对你有帮助可以点个赞哦,如果有需要前端校招面试题PDF完整版的朋友可以点击这里即可免费获取,包括答案解析。

[外链图片转存中…(img-7T34ltwA-1712340156870)]

  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值