-
Notifications
You must be signed in to change notification settings - Fork 0
/
对象的新增方法.html
431 lines (417 loc) · 15.2 KB
/
对象的新增方法.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
p{ white-space: pre-line;}
</style>
</head>
<body>
<p>
一 对象的新增方法
1.Object.is()
ES5: 比较两个值是否相等,只有两个运算符:相等运算符(==)和严格相等运算符(===)。
它们都有缺点,前者会自动转换数据类型,
后者的NaN不等于自身,以及+0等于-0。
JavaScript 缺乏一种运算,在所有环境中,只要两个值是一样的,它们就应该相等。
ES6: 提出“Same-value equality”(同值相等)算法,Object.is就是部署这个算法的新方法,
它用来比较两个值是否严格相等,与严格比较运算符(===)的行为基本一致。
不同之处只有两个:一是+0不等于-0,二是NaN等于自身。
</p>
<script>{
+0 === -0 //true
NaN === NaN // false
Object.is(+0, -0) // false
Object.is(NaN, NaN) // true
}
</script>
<p>
二 Object.assign()
基本用法
Object.assign方法用于对象的合并,将源对象(source)的所有可枚举属性,复制到目标对象(target)
</p>
<script>
{
let target={a:1}
let source1={b:2}
let source2={c:3}
Object.assign(target,source1,source2)
console.log(target)// {a:1, b:2, c:3}
}
</script>
<p>
二.1 注意点
1.目标对象与元对象有同名属性或者多个源对象有同名属性,则后面的属性会覆盖前面的属性
2.如果只有一个参数,Object.assign会直接返回该参数,后面不管加多少参数都是原对象
3.如果该参数不是对象,则会先转成对象,然后返回。
4.由于undefined和null无法转成对象,所以如果它们作为参数,就会报错。
5.undefined和null不出现在首参数,不会报错
6.其他类型的值(即数值、字符串和布尔值)不在首参数,也不会报错。
但是,除了字符串会以数组形式,拷贝入目标对象,其他值都不会产生效果。
因为只有字符串 能包装成对象
7.Object.assign拷贝的属性是有限制的,只拷贝源对象的自身属性(不拷贝继承属性),也不拷贝不可枚举的属性(enumerable: false)。
属性名为 Symbol 值的属性,也会被Object.assign拷贝。
8. 属于浅拷贝 如果源对象某个属性的值是对象,那么目标对象拷贝得到的是这个对象的引用。
9.数组的处理 会把数组当成对象处理
10.取值函数的处理 如果复制的值是一个取值函数,那么将求值后再复制
</p>
<script>
//1
{
let target={a:2,b:3}
let source1={a:4}
Object.assign(target,source1)
console.log(target)//{a: 4, b: 3}
}
//2
{
let target={a:2,b:3}
let source1={a:4,c:5}
let obj={ss:555}
console.log(target===Object.assign(target,source1))
console.log(Object.assign(obj) === obj )// true
console.log(target)//{a: 4, b: 3}
}
//3
{
console.log(typeof Object.assign(2) )// "object"
}
//4
{
// Object.assign(undefined) // 报错
// Object.assign(null) // 报错
}
//5
{
let obj = {a: 1};
console.log( Object.assign(obj, undefined) === obj )// true
console.log( Object.assign(obj, null) === obj )// true
}
//6
{
let s1='abc'
let s2=true
let s3=10
let obj=Object.assign({},s1,s2,s3)
console.log(obj)// { "0": "a", "1": "b", "2": "c" }
console.log(Object('abc'))// {0: "a", 1: "b", 2: "c", length: 3, [[PrimitiveValue]]: "abc"}
}
//7
{
console.log(
Object.assign({b: 'c'},
Object.defineProperty({}, 'invisible', {
enumerable: false,
value: 'hello'
})
)) // { b: 'c' }
Object.assign({ a: 'b' }, { [Symbol('c')]: 'd' })// { a: 'b', Symbol(c): 'd' }
}
//8
{
let obj={a:{b:1}}
let obj2=Object.assign({},obj)
obj.a.b=2
console.log(obj2.a.b)//2
}
//9
{
console.log(Object.assign([1,2,3,],[4,5]))
//[4,5,3] 把数组视为属性名为 0、1、2 的对象,因此源数组的 0 号属性4覆盖了目标数组的 0 号属性1
}
//10
{
let source = {
get foo() { return 1 }
};
let target = {};
console.log(Object.assign(target, source))//// { foo: 1 }
}
</script>
<p>
三 常见用途
1.为对象添加属性
2.为对象添加方法
3.克隆对象 不过只能克隆对象自身的值 ,不能克隆它继承的值注意中的
4.合并对个对象,将多个对象合并
5.为属性指定默认值
</p>
<script>
//1
{
class Point{
constructor(x,y){
Object.assign(this,{x,y})
}
}
let ss=new Point(2,3)
console.log(ss)//Point {x: 2, y: 3}
}
//2
{
class Point{}
Object.assign(Point,{doSome(){
console.log("doSome")
}})
Point.doSome()
}
// 3 克隆并被克隆集成的值 如果想保持继承链
{
// 有待详细
// function clone(origin) {
// let originProto = Object.getPrototypeOf(origin);
// return Object.assign(Object.create(originProto), origin);
// }
}
//5
{
let DEFAULTS = {
logLevel: 0,
outputFormat: 'html'
};
function processContent(options) {
options = Object.assign({}, DEFAULTS, options);
console.log(options);
// ...
}
processContent({logLevel:2})//{logLevel: 2, outputFormat: "html"}
}
</script>
<p>
四. es5 Object.getOwnPropertyDescriptor() 会返回某个对象属性的描述对象 某个单个的
es6 Object.getOwnPropertyDescriptors() 返回指定对下个所有自身属性(非继承属性的描述对象)
//暂时没有纳入reflect 后面也会加入reflect
目的 主要是为了解决Object.assign()无法正确拷贝get属性和set属性的问题。 所有的
</p>
<script>
//两个方法的基础用法
{
let source={
set foo(value){
console.log(value)
},
s:1
}
let target={}
console.log("-------------")
console.log( Object.getOwnPropertyDescriptor(source))//undefined
console.log( Object.getOwnPropertyDescriptor(source,'s'))//{value: 1, writable: true, enumerable: true, configurable: true}
console.log( Object.getOwnPropertyDescriptors(source))
//{foo: {…}, s: {…}}
// foo: {get: undefined, set: ƒ, enumerable: true, configurable: true}
// s: {value: 1, writable: true, enumerable: true, configurable: true}
// __proto__: Object
console.log( Object.getOwnPropertyDescriptors(source,'s'))//同上
}
//返回整个对象属性的描述对象
{
let obj={
foo:123,
get bar(){
return 'c'
}
}
console.log(obj.bar)//c
console.log(Object.getOwnPropertyDescriptor(obj))//返回所有元对象的属性名都是该对象的属性名,对应的属性值就是该属性的描述对象
// {foo: {…}, bar: {…}}
// bar:configurable: true
// enumerable: true
// get: ƒ bar()
// set: undefined
// __proto__: Object
// foo: {value: 123, writable: true, enumerable: true, configurable: true}
// __proto__: Object
console.log(Object.getOwnPropertyDescriptors(obj))//与上面一样
}
// 无法拷贝get set属性的方法
{
let source={
set foo(value){
console.log(value)
}
}
let target={}
Object.assign(target,source)
console.log(Object.getOwnPropertyDescriptor(target,'foo'))
// { value: undefined,
// writable: true,
// enumerable: true,
// configurable: true }
//Object.assign方法总是拷贝一个属性的值,而不会拷贝它背后的赋值方法或取值方法。所以value为undefined
}
// 用途一 解决浅拷贝的问题 Object.getOwnPropertyDescriptors()方法配合Object.defineProperties()方法,就可以实现正确拷贝。
{
let source={
set foo(value){
console.log(value)
},
s:1
}
let target={}
console.log( Object.getOwnPropertyDescriptor(source))
console.log( Object.getOwnPropertyDescriptors(source))
Object.defineProperties(target,Object.getOwnPropertyDescriptors(source))
console.log(Object.getOwnPropertyDescriptor(target,"foo"))
//{get: undefined, set: ƒ, enumerable: true, configurable: true}
}
//用途二 是配合Object.create()方法,将对象属性克隆到一个新对象
//这属于浅拷贝。
{
let obj = {
foo: 123,
get bar() { return 'abc' }
};
let clone = Object.create(Object.getPrototypeOf(obj),
Object.getOwnPropertyDescriptors(obj));
console.log(clone)
//{foo: 123}bar: "abc"foo: 123get bar: ƒ bar()arguments: (...)caller: (...)length: 0name: "get bar"__proto__: ƒ ()
//或者 换箭头函数写法
let shallowClone = (obj) => Object.create(
Object.getPrototypeOf(obj),
Object.getOwnPropertyDescriptors(obj)
);
}
//实现继承一个对象
{
let prot={a:1}
//es6之前
let obj = {
__proto__: prot,
foo: 123,
};
//foo: 123 __proto__ : a:1
//实现继承的方式一
let temp=Object.create(prot)//__proto__ : a:1
let obj1= Object.assign(Object.create(prot),{
foo:123
})
//实现继承的方式二
let obj2 = Object.create(
prot,
Object.getOwnPropertyDescriptors({
foo: 123,
})
);//foo: 123 __proto__ : a:1
}
// 简单了解了下with函数 https://blog.csdn.net/zwkkkk1/article/details/79725934
//with函数尽量避免
{
}
</script>
<p>
五. __proto__属性,Object.setPrototypeOf(),Object.getPrototypeOf()
1.__proto__属性
用来读取或设置当前对象的prototype对象
是__proto__前后的双下划线,说明它本质上是一个内部属性,而不是一个正式的对外的 API
只有浏览器必须部署这个属性,其他运行环境不一定需要部署,而且新的代码最好认为这个属性是不存在
一般使用Object.setPrototypeOf()(写操作)、Object.getPrototypeOf()(读操作)、Object.create()(生成操作)代替
实际上 __proto__调用的是Object.prototype.__proto__
一个对象本身部署了__proto__属性,该属性的值就是对象的原型。
2.Object.setPrototypeOf()
返回参数对象本身 ES6 正式推荐的设置原型对象的方法。
Object.setPrototypeOf(object, prototype)
注意点
1.undefined和null无法转为对象 会报错
2.如果第一个参数不是对象,会自动转为对象。但是由于返回的还是第一个参数,所以这个操作不会产生任何效果。
3.Object.getPrototypeOf()
用于读取一个对象的原型对象。
4. Object.keys(),Object.values(),Object.entries()
Object.keys() 返回一个数组 成员是参数对象自身的(不含继承)的所有可遍历属性的键名
Object.values() 方法返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历(enumerable)属性的键值。
注意点
1.Object.create方法的第二个参数添加的对象属性(属性p),如果不显式声明,默认是不可遍历的, 所以keys遍历不了
2.会过滤属性名为 Symbol 值的属性。
3.如果Object.values方法的参数是一个字符串,会返回各个字符组成的一个数组。因为会默认转成对象对象
Object.entries() 方法返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历(enumerable)属性的键值对数组
除了返回值不一样,该方法的行为与Object.values基本一致。
//Reflect 暂时没有
基本用途 1.用来遍历对象的属性
2. 遍历对象的属性
5.Object.fromEntries()
Object.fromEntries()方法是Object.entries()的逆操作,用于将一个键值对数组转为对象。
该方法的主要目的,是将键值对的数据结构还原为对象,因此特别适合将 Map 结构转为对象。
</p>
<script>
// __proto__调用的是Object.prototype.__proto__ 具体实现的方式
{
Object.defineProperty(Object.prototype, '__proto__', {
get() {
let _thisObj = Object(this);
return Object.getPrototypeOf(_thisObj);
},
set(proto) {
if (this === undefined || this === null) {
throw new TypeError();
}
if (!isObject(this)) {
return undefined;
}
if (!isObject(proto)) {
return undefined;
}
let status = Reflect.setPrototypeOf(this, proto);
if (!status) {
throw new TypeError();
}
},
});
}
//设置原型
{
let proto={}
let obj={x:30}
let obj2= Object.setPrototypeOf(obj,proto)
//obj x:30 返回参数对象本身
proto.y=20
proto.z=10
obj.x//30
obj.y//20
obj.z//10
Reflect.getPrototypeOf(obj)//y: 20 z: 10 说明x 的定义是在实例上
}
//Object.keys()
{
let obj = { foo: 'bar', baz: 42 };
Object.keys(obj)// ["foo", "baz"]
let obj1 = { a: 1, b: 2, c: 3 };
for (let key of Object.keys(obj1)) {
console.log(key); // 'a', 'b', 'c'
}
}
//Object.value()
{ //demo
const obj = { 100: 'a', 2: 'b', 7: 'c' };
Object.values(obj)// ["b", "c", "a"]
//Object.create方法的第二个参数添加的对象属性(属性p),如果不显式声明,默认是不可遍历的,
// 只要把enumerable改成true,Object.values就会返回属性p的值。
let obj2=Object.create({},{p:{value:3}})
Object.values(obj2)//[]
let obj3=Object.create({},{p:{value:3}})
Object.values(obj3)//[3]
//过滤Symbol的值的属性
Object.values({ [Symbol()]: 123, foo: 'abc' });// ['abc']
}
//Object.entries()
{
let obj3 = { foo: 'bar', baz: 42 };
Object.entries(obj3)//// [ ["foo", "bar"], ["baz", 42] ]
//遍历对象
let obj4={one:1,two:2}
for(let [k,v] of Object.entries(obj4)){
console.log(k,v)// one 1 two: 2
}
//将对象转为map结构
let obj6 = { foo: 'bar', baz: 42 };
let map = new Map(Object.entries(obj6));
}
{
let a= ()=>{
console.log("=======")
}
let enteries=new Map([['foo',22],[1,2]])
Object.fromEntries(enteries)// Object.fromEntries is not a function
}
</script>
</body>
</html>