Skip to content

Commit aa25b23

Browse files
update define property 2
1 parent edc5e62 commit aa25b23

File tree

3 files changed

+186
-5
lines changed

3 files changed

+186
-5
lines changed

0/about-object/demo-1.js

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
var dream = {};
2+
Object.defineProperty(dream, 'name', {
3+
value: 'dreamapple',
4+
writable: true
5+
});
6+
7+
console.log(dream.name); // dreamapple
8+
dream.name = 'apple'; // 修改name属性
9+
console.log(dream.name); // apple
10+
11+
Object.defineProperty(dream, 'a', {
12+
value: 1,
13+
enumerable: false // 不可枚举
14+
});
15+
Object.defineProperty(dream, 'b', {
16+
value: 2,
17+
enumerable: true // 可枚举
18+
});
19+
20+
// 只会输出 b
21+
for(prop in dream) {
22+
console.log(prop);
23+
}
24+
25+
console.log(Object.keys(dream)); // ['b']
26+
27+
console.log(dream.propertyIsEnumerable('a')); // false
28+
console.log(dream.propertyIsEnumerable('b')); // true
29+
30+
Object.defineProperty(dream, 'c', {
31+
value: 3,
32+
configurable: false
33+
});
34+
// //throws a TypeError
35+
//Object.defineProperty(dream, 'c', {
36+
// configurable: true
37+
//});
38+
// //throws a TypeError
39+
//Object.defineProperty(dream, 'c', {
40+
// writable: true
41+
//});
42+
// //won't throws a TypeError
43+
//Object.defineProperty(dream, 'c', {
44+
// writable: false
45+
//});
46+
47+
delete dream.c; // 属性不可以被删除
48+
console.log(dream.c); // 3
49+
50+
//Object.defineProperty(dream, 'c', {
51+
// writable: true,
52+
// configurable: true
53+
//});
54+
////Object.defineProperty(dream, 'c', {
55+
//// writable: true
56+
////});
57+
////Object.defineProperty(dream, 'c', {
58+
//// writable: false
59+
////});
60+

0/about-object/demo.js

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,17 +47,33 @@ console.log('------');
4747
var dreamapple = {
4848
firstName: 'dream',
4949
lastName: 'apple',
50-
get fullName() {
50+
//get fullName() {
51+
// return this.firstName + ' ' + this.lastName;
52+
//},
53+
//set fullName(fullName) {
54+
// var names = fullName.trim().split(' ');
55+
// if (2 === names.length) {
56+
// this.firstName = names[0];
57+
// this.lastName = names[1];
58+
// }
59+
//}
60+
};
61+
62+
63+
64+
Object.defineProperty(dreamapple, 'fullName', {
65+
enumerable: true,
66+
get: function () {
5167
return this.firstName + ' ' + this.lastName;
5268
},
53-
set fullName(fullName) {
69+
set: function (fullName) {
5470
var names = fullName.trim().split(' ');
55-
if(2 === names.length) {
71+
if (2 === names.length) {
5672
this.firstName = names[0];
5773
this.lastName = names[1];
5874
}
5975
}
60-
};
76+
});
6177

6278
dreamapple.firstName = 'Dream';
6379
dreamapple.lastName = 'Apple';

vanilla-js/object/define-property.md

Lines changed: 106 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,11 +83,116 @@ console.log(dreamapple.lastName); // King
8383
```
8484
是不是很方便呢?我们通过给`dreamapple`这个对象设置了属性`fullName``getter``setter`方法,就达到了我们想要的那种效果.
8585

86-
当然更好的一种方法就是使用`Object.defineProperty()`这个函数了,下面我们就来好好的探讨一下这个函数.
86+
当然更好的一种方法就是使用[`Object.defineProperty()`][1]这个函数了,下面我们就来好好的探讨一下这个函数.
87+
这个方法的作用就是直接在一个对象上定义一个新属性,或者修改一个已经存在的属性,并返回这个对象;我们先来看一下怎么使用这个方法:
88+
```javascript
89+
Object.defineProperty(obj, prop, descriptor)
90+
```
91+
其中参数`obj`表示的是需要定义属性的那个对象,参数`prop`表示需要被定义或者修改的属性名,
92+
参数`descriptor`就是我们定义的那个属性`prop`的描述;我们接下来主要讲解这个`descriptor`.
93+
它是一个对象,它有许多的属性,我们接下来来分析这些属性都是干什么用的:
94+
95+
+ **value** 该属性对应的值,可以是任何有效的JavaScript值(数值,对象,函数等),默认为`undefined`.我们可以看下面的一个小例子:
96+
```javascript
97+
var dream = {};
98+
Object.defineProperty(dream, 'name', {
99+
value: 'dreamapple'
100+
});
101+
102+
console.log(dream.name); // dreamapple
103+
dream.name = 'apple'; // 修改name属性
104+
console.log(dream.name); // 并不是apple,依旧是dreamapple
105+
```
106+
从上面的代码中我们可以看到,我们给`dream`定义了一个新的属性`name`,然后我们打印出这个属性就是我们预期的那样,得到的是`dreamapple`;
107+
但是,当我们尝试改变这个属性的时候,却发现这个属性并没有改变,还以第一次我们赋给它的值;这是为什么呢?
108+
原来,只有当我们这个属性的`writable`修饰为`true`时,我们这个属性才可以被修改.
109+
110+
+ **writable** 当且仅当仅当该属性的`writable``true`时,该属性才能被赋值运算符改变;它的默认值为false.我们来修改一下上面的代码,
111+
让属性`name`可以被修改:
112+
```javascript
113+
Object.defineProperty(dream, 'name', {
114+
value: 'dreamapple',
115+
writable: true
116+
});
117+
118+
console.log(dream.name); // dreamapple
119+
dream.name = 'apple'; // 修改name属性
120+
console.log(dream.name); // apple
121+
```
122+
我们可以看到,当我们把`writable`修改为`true`时,我们就可以修改`name`属性了.
123+
124+
+ **enumerable** 这个特性决定了我们定义的属性是否是可枚举的类型,默认是`false`;只有我们把它设置为`true`的时候这个属性才可以使用`for(prop in obj)``Object.keys()`
125+
中枚举出来.就像下面这样:
126+
```javascript
127+
Object.defineProperty(dream, 'a', {
128+
value: 1,
129+
enumerable: false // 不可枚举
130+
});
131+
Object.defineProperty(dream, 'b', {
132+
value: 2,
133+
enumerable: true // 可枚举
134+
});
135+
136+
// 只会输出 b
137+
for(prop in dream) {
138+
console.log(prop);
139+
}
87140

141+
console.log(Object.keys(dream)); // ['b']
88142

143+
console.log(dream.propertyIsEnumerable('a')); // false
144+
console.log(dream.propertyIsEnumerable('b')); // true
145+
```
146+
所以当我们想给你个对象添加一个不可枚举的属性的时候,就应该把`enumerable`设置为`false`.
89147

148+
+ **configurable** 这个特性决定了对象的属性是否可以被删除,以及除`writable`特性外的其它特性是否可以被修改;并且`writable`特性值只可以是`false`
149+
我们可以写一个代码示例来演示一下这个特性:
150+
```javascript
151+
Object.defineProperty(dream, 'c', {
152+
value: 3,
153+
configurable: false
154+
});
155+
//throws a TypeError
156+
Object.defineProperty(dream, 'c', {
157+
configurable: true
158+
});
159+
//throws a TypeError
160+
Object.defineProperty(dream, 'c', {
161+
writable: true
162+
});
163+
//won't throws a TypeError
164+
Object.defineProperty(dream, 'c', {
165+
writable: false
166+
});
167+
delete dream.c; // 属性不可以被删除
168+
console.log(dream.c); // 3
169+
```
170+
+ **get** 一个给属性提供`getter`的方法,如果没有`getter`则为`undefined`;该方法返回值被用作属性值,默认为undefined.
171+
+ **set** 一个给属性提供`setter`的方法,如果没有`setter`则为`undefined`;该方法将接受唯一参数,并将该参数的新值分配给该属性,默认为undefined.
172+
知道了这些之后我们就可以使用更标准的一种方式去解决我们在文中开头的问题了:
173+
```javascript
174+
Object.defineProperty(dreamapple, 'fullName', {
175+
enumerable: true,
176+
get: function () {
177+
return this.firstName + ' ' + this.lastName;
178+
},
179+
set: function (fullName) {
180+
var names = fullName.trim().split(' ');
181+
if (2 === names.length) {
182+
this.firstName = names[0];
183+
this.lastName = names[1];
184+
}
185+
}
186+
});
187+
```
188+
还有一点需要注意的是,`value``get,set`是不可以共存的,就是说你定义了`value`后就不能够再定义`get,set`特性了.
90189

190+
好啦,今天的文章就写到这里了,相信大家对于`Object.defineProperty(obj, prop, descriptor)`这个方法应该掌握了;还有一点需要提及的是
191+
其实`Vue.js``计算属性`也是在这个函数的基础上进行的一些改进,详情可以看这里[计算属性的奥秘][2].
91192

193+
如果你对这篇文章有什么意见或者建议可以在这里提出来[issues][3]
92194

93195

196+
[1]:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty
197+
[2]:http://cn.vuejs.org/guide/reactivity.html#计算属性的奥秘
198+
[3]:https://github.com/dreamapplehappy/hacking-with-javascript/issues/3

0 commit comments

Comments
 (0)