【作用】:以指定对象为原型,创建新的对象,必传。该参数可以是null
, 对象, 函数的prototype
属性 (创建空的对象时需传null
, 否则会抛出TypeError异常)。
注:如果prototype传入一个null
,那么这个对象将是一个没有任何属性的对象。对比一下 new Object() 和它的字面量写法:{}
var obj1 = new Object()
console.dir(obj1)
var obj2 = {}
console.dir(obj2)
var obj3 = Object.create(null)
console.dir(obj3)
输出结果:
可以看到前两种创建对象的方式创建出的对象都是以Object.prototype
为原型,而第三种由于传入的是null,因此这个对象没有原型属性。如果要让obj3也有原型,可以在定义的时候直接传入原型或者创建后再手动配置:
// 方式一
var obj3 = Object.create({})
// 方式二
var obj3 = Object.create(null)
Object.setPrototypeOf(obj3,Object,prototype)
【参数】:
prototype: 就是要作为原型的那个对象;
description 为新的对象指定新的属性,并对属性进行描述,可用的关键字:
– value:新属性的值
– writable: 是否可以修改,默认false
– configurable: 是否可以删除,默认false
– enumerable: 当前属性是否可以被for… in… 枚举到,默认false
– get:属于accessors的一种,值是获取当前属性指的回调函数 (注意accessors
与 value
和writable
这两个冲突,逻辑上也很好理解)
– set:属于accessors的一种,值是修改当前属性值触发的回调函数,并且实参即为修改后的值 (注意accessors
与 value
和writable
这两个冲突,逻辑上也很好理解)
注:descriptors可以通过Object.getOwnPropertyDescriptor(obj, 'name')
这个Object原型上的方法获得。比如:
console.log(Object.getOwnPropertyDescriptor(obj, 'name'))
//输出内容
configurable: true
enumerable: true
value: "123"
writable: true
【栗子】:
var obj = {
country : 'CN',
race : 'HUM'
}
var new_obj = Object.create(obj,{// 最外层对象,键是要创建的新属性名称,值是一个对象,包括了value,writable等属性
name:{
value:'蔡徐坤',
enumerable:true
},
gender:{
value:'女',
writable:true, //可以修改性别
configurable:true, //可以不要性别
enumerable:false //不要暴露自己的性别
}
})
new_obj.name = 'ikun' //名字改不了
new_obj.gender = '男' //厉不厉害你鲲哥
for(var i in new_obj){
console.log(new_obj[i])
}
上面这个例子以我国著名音乐家、舞蹈家、篮球运动员蔡徐坤先生为例。
首先设置一个obj父类,包含了country
属性和race
属性,然后通过调用Object
方法,以obj为原型构造一个新的对象new_obj
,并定义两个新的属性:name
和gender
,而 这两个属性也分别是两个对象,对象中包括了一些性质:
其中name
的writable
和configurable
默认是false,颇有行不更名坐不改姓的高风亮节;
而gender
的writable
和configurable
则设为true,展现了她艺术人格中灵活多变的一面。
定义完new_obj
之后,尝试修改姓名为'ikun'
,由于她行不更名坐不改姓的艺术风骨,这个改动失败了。
而new_obj.gender = '男'
则展现了性别的灵活多变,令人目不暇接。
最后通过for
枚举new_obj
的属性,会打印出name
,country
和age
,唯独将gender
神秘的一面留给了大家。(因为enumerable是false)
【作用】:为指定对象扩展多个属性
【参数】:
accessors
与 value
和writable
这两个冲突,逻辑上也很好理解)accessors
与 value
和writable
这两个冲突,逻辑上也很好理解)【栗子】:
由于上一个例子演示了value和writable,这个例子就演示下get 和 set。
value/writable
和 get/set
是冲突的两组属性。
如果属性A设置了value/writable
,那么这个属性A的属性可以直接通过obj.A访问,但是这样定义属性会有一个不方便的地方,那就是需要用到对象中其他属性的时候:
假设这样一个情景,一个对象的fullName
属性需要通过firstName
和lastName
拼接而成,那么在定义的时候可能会写出这样的错误代码:
var obj3 = {
firstName : 'kobe',
lastName : 'bryant',
fullName : this.firstName + this.lastName
}
console.log(obj3)
最后的结果,obj3的fullName
属性是NaN
,为什么?
因为定义这个对象的时候,this指向的是window作用域,window里自然是没有firstName
和lastName
的。两个undefined相加,结果就是NaN。
而我们用Object.defineProperties
则可以解决这个问题:
var obj2 = {
firstName: 'kobe',
lastName: 'bryant'
}
Object.defineProperties(obj2, { // 最外层对象,囊括要设置的属性
fullName: {
get: function () { //获取扩展属性的回调函数
return this.firstName + ' ' + this.lastName
},
set: function (data) { //监听扩展属性的回调函数,当扩展的属性发生变化时会自动调用
//此时扩展的属性的新值会作为实参传入到这个回调函数中
dataArr = data.split(' ')
this.firstName = dataArr[0]
this.lastName = dataArr[1]
},
// value: 'shabi',
// writable: true,
// configurable:true,
enumerable: true
}
})
obj2.fullName = 'steve jobs'
for (var i in obj2) {
console.log(obj2[i]) // steve jobs
}
通过get属性绑定一个回调函数,来获取fullName
属性。可能大家会有个疑问:为什么get
回调函数里的this
就指向obj2
本身呢?这涉及到get
的调用规则。get
是一个异步回调函数,每当 obj2.fullName
成为右值的时候,get
就会被obj2
调用,那么this自然就指向obj2
本身了。
同理,set
通过绑定一个回调函数来监听 fullName
的变化。每当fullName
成为左值的时候,set
方法就会被obj2
调用,并且会将赋给左值的东西(这个案例里是'steve jobs'
字符串)作为实参(对应的形参就是data
)传入到set函数中。在set
函数里通过分割字符串分别修改firstName
和lastName
,这样下次再获取fullName
的时候,就能根据新的firstName
和lastName
计算出新的fullName
,相当于实现了对fullName
的更新。