记录Object的那些事...

220 阅读5分钟
(1)最近看了一篇文章,描述了对象的属性和方法,原来学习这些就够了。详情

查看一个对象的属性和方法的最佳方式:在浏览器输入这行代码

Object.getOwnPropertyNames(Object).sort().forEach(function (val) {console.log(val, '\n')});

(2)Object.create()\new object()\{} 三个的区别

Object.create(proto[, propertiesObject])
记住:如果proto参数不是 null 或一个对象,则抛出一个 TypeError 异常。
比如:console.log(Object.create()) // 抛出一个 TypeError 异常

Object.create(生成操作)使用指定的原型对象及其属性去创建一个新的对象

var o2 = Object.create({}, {
  p: {
    value: 42
  } 
})
o2.p = 10
console.log(o2) // {p: 42}
o2.q = 12
for (var prop in o2) {
   console.log(prop) // q
}
delete o2.p // false

创建一个可写的,可枚举的,可配置的属性

var o2 = Object.create({}, {
  p: {
    value: 42, 
    writable: true,
    enumerable: true,
    configurable: true 
  } 
})
o2.p = 10 // 可写
console.log(o2) // {p: 10}
o2.q = 12
for (var prop in o2) {
   console.log(prop) // p 1 可枚举
}
delete o2.p // true  //可配置

区别

Object.create(null) 创建的对象是一个空对象,在该对象上没有继承 Object.prototype 原型链上的属性或者方法,例如:toString(), hasOwnProperty()等方法。

Object.create();继承指定对象

new Object():继承内置对象Object

Object.create = function (obj) {
  return { '__proto__': obj};
}
// 视为Object.create实现原理

可以通过Object.create(null) 创建一个干净的对象,也就是没有原型,而 new Object() 创建的对象是 Object的实例,原型永远指向Object.prototype

var test1 = {x:1}; // 默认是可读的,可写的,可枚举的,可配置的属性
var test2 = new Object({x:1});
var test3 = Object.create({x:1});
var test4 = Object.create(null);
console.log(test1.x) //1
console.log(test1.__proto__.x === test1.x) //false
console.log(test2.__proto__.x === test1.x) //false
console.log(test3.__proto__.x === test1.x) //true
console.log(test4.__proto__) // undefined

var obj = {}
var obj2 = Object.create(obj) 
console.log(obj.__proto__ === Object.prototype) // true
console.log(obj2.__proto === Object.prototype) // false
console.log(obj2.__proto === obj.prototype) //true
//使用现有的对象obj来提供新创建obj2 的对象的__proto__
//简单的说就是重写obj2 的原型

(3)Object.defineProperty:在一个对象上定义一个新属性,或者修改一个已经存在的属性, 并返回这个对象。默认可读,可写,可配置,可枚举。数据劫持操作(监控属性变化)(这玩意就很重要了)

这篇文章精简

Object.defineProperty(obj, prop, descriptor)

var obj = {}
Object.defineProperty(obj,"age",{
    value: 42, 
    enumerable: true,
    configurable: true ,
    set(){},
    get(){}
})
注意: value,writable 和 set(){},get(){} 不能同时使用

Object.defineProperty缺点:只能监控"对象属性"的改变,监控数组需另行处理,而且对象新增属性也无法有效监控。后续处理,等待vue源码吧。。。

(4) __proto__ \Object.setPrototypeOf()\Object.getPrototypeOf()

对指定对象的原型的一些操作

var obj = {}
var obj = new Object()
console.log(obj.__proto__ === Object.prototype) // true
console.log(Object.getPrototypeOf(obj) === Object.prototype) //true
console.log(obj.constructor.prototype === Object.prototype) //true

实质就是对象的隐示原型  === 实例化对象的构造函数的显示原型

function Parent() {
}
var child = new Parent();
console.log(Object.getPrototypeOf(child) === Parent.prototype) // true
Object.setPrototypeOf(child, Object.prototype);
child对象的原型对象设置为Object.prototype对象
console.log(Object.getPrototypeOf(child) === Parent.prototype) // false

function C(){
  this.age=4;
}

let proto = {
  url:"xxx"
};

C.prototype.address="修改原型对象";
let A=new C();
let B=new C();
Object.setPrototypeOf(A, proto);
console.log(A.address); // undefined
console.log(B.address); // 修改原型对象
console.log(C.prototype.isPrototypeOf(B)) //true
//A,B实例化原型同时指向C
//A的原型对象发生了修改,但是不会影响B的原型对象
//对象B是否在对象C的原型链上

Object.setPrototypeOf方法的作用与__proto__相同。用来设置一个对象的prototype对象。它是 ES6 正式推荐的设置原型对象的方法。这里

(5)Object.getOwnPropertyDescriptor:返回指定对象上一个自有属性对应的属性描述符(自身的属性,而不是原型链上的属性)

propertyIsEnumerable() 方法返回一个布尔值,表明指定的属性名是否是当前对象可枚举的自身属性。

var obj = {name:"hello"} // 默认是可枚举,可写,可配置
console.log(Object.getOwnPropertyDescriptor(obj,'name'))
//{value: "hello", writable: true, enumerable: true, configurable: true}
Object.defineProperty(obj,'age',{value:"xxxx"}) // // 默认是不可枚举,不可写,不可配置
console.log(Object.getOwnPropertyDescriptor(obj,'age'))
//{value: "xxxx", writable: false, enumerable: false, configurable: false}

var obj = {name:"hello"}
console.log(obj.propertyIsEnumerable('name')) // true

(6)for in,Object.keys和Object.getOwnPropertyNames

Object.getOwnPropertyNames:获取对象自身的全部属性名(返回数组:自身所有) 

Object.keys:获取对象自身可枚举的属性键(返回数组:自身可枚举的) 

for in : 输出自身以及原型链上可枚举的属性。

 hasOwnProperty: 输出对象自身的属性

可以这么认为:Object.getOwnPropertyNames就是for in和hasOwnProperty的集合体。

for (var key in child) {
    if (child.hasOwnProperty(key)) {
        console.log(key);
    }
}

(7)isPrototypeOf()\instanceOf 

isPrototypeOf() 一个对象是否存在于另一个对象的原型链上。

typeof:只能判断:string,boolean,number,NaN,undefined 

instanceof: 判断一个实例对象是否由某个构造函数构造而来 ,基于原型链。

constructor:判断一个实例对象是由哪个构造函数构造出来,原型对象被重写会发生变化。

Object.prototype.toString.call(a) === '[object Array]':判断类型的最佳方式

Object.hasOwnPrototype() / in :hasOwnPrototype

var o =new Object();
o.prop ='exists';
console.log(o.hasOwnProperty('prop')) // true
console.log(o.hasOwnProperty('toString')) // false
console.log(o.hasOwnProperty('hasOwnProperty')) //false
console.log('hasOwnProperty' in o) // true
console.log('toString' in o) //true
console.log('prop' in o) //true

function Person () {}
var person = new Person()
console.log(person.constructor)   //Person
console.log(person.constructor === Person) // true
console.log(person instanceof Person) // true

所以:

A.isPrototypeOf (B) 判断的是A对象是否存在与B对象的原型链之中
A instanceof B  判断的是B.prototype是否存在与A的原型链之中
所以就有下面的结论:    
如果 A.isPrototypeOf(B)  返回true 则B instanceof A 一定返回true

每个函数都有一个原型对象,默认的时候这个原型对象都会得到一个构造函数,这个constructor构造函数指向原型对象所对应的函数(原型指向的函数)。这里


(8) Object.is(A,B)方法用来判断两个值是否相同,类似 ===

特殊点:

console.log(Object.is(+0,-0)) // false
console.log(+0 === -0)  // true
console.log(Object.is(NaN,NaN )) // true
console.log(NaN === NaN) // false

(9)Object.assign()能够将一个或者多个对象的属性拷贝到目标对象这里

只会拷贝源对象自身的并且可枚举的属性到目标对象。

后来的源的属性将覆盖早先的相同的属性。

object.assign()顶级是深拷贝,其他是浅拷贝。官方列出的例子

let obj1 = { a: 0 , b: { c: 0}};
let obj2 = Object.assign({}, obj1);
console.log(JSON.stringify(obj2)); // { a: 0, b: { c: 0}}
// 检验顶级深拷贝
 obj1.a = 1; 
 console.log(JSON.stringify(obj1)); // { a: 1, b: { c: 0}}
 console.log(JSON.stringify(obj2)); // { a: 0, b: { c: 0}}
// 非顶级浅拷贝
  obj2.b.c = 3;
  console.log(JSON.stringify(obj1)); // { a: 1, b: { c: 3}}
  console.log(JSON.stringify(obj2)); // { a: 0, b: { c: 3}}

简单的解决方案: JSON.parse(JSON.stringify(xxx));最好的处理方式终结版

总结:

没有了总结,真正学会了Object吗。。。。。。