ES5标准中的Object.create() 和 Object.defineProperties()

ES5标准中的Object.create和Object.defineProperties

  • Object.create(prototye,[description])
  • Object.defineProperties(object,descriptors)

Object.create(prototye,[description])

【作用】:以指定对象为原型,创建新的对象,必传。该参数可以是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)

输出结果:
ES5标准中的Object.create() 和 Object.defineProperties()_第1张图片
可以看到前两种创建对象的方式创建出的对象都是以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的一种,值是获取当前属性指的回调函数 (注意accessorsvaluewritable这两个冲突,逻辑上也很好理解)
    – set:属于accessors的一种,值是修改当前属性值触发的回调函数,并且实参即为修改后的值 (注意accessorsvaluewritable这两个冲突,逻辑上也很好理解)

    注: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,并定义两个新的属性:namegender,而 这两个属性也分别是两个对象,对象中包括了一些性质:
其中namewritableconfigurable默认是false,颇有行不更名坐不改姓的高风亮节;
genderwritableconfigurable则设为true,展现了她艺术人格中灵活多变的一面。

定义完new_obj之后,尝试修改姓名为'ikun',由于她行不更名坐不改姓的艺术风骨,这个改动失败了。
new_obj.gender = '男'则展现了性别的灵活多变,令人目不暇接。

最后通过for枚举new_obj的属性,会打印出name,countryage,唯独将gender神秘的一面留给了大家。(因为enumerable是false)

Object.defineProperties(object,descriptors)

【作用】:为指定对象扩展多个属性
【参数】:

  • object: 要扩展属性的对象;
  • descriptors 要扩展的属性,并对属性进行描述,可用的关键字:
    – value:新属性的值
    – writable: 是否可以修改,默认false
    – configurable: 是否可以删除,默认false
    – enumerable: 当前属性是否可以被for… in… 枚举到,默认false
    – get:属于accessors的一种,返回值为当前属性值的回调函数 (注意 accessorsvaluewritable这两个冲突,逻辑上也很好理解)
    – set:属于accessors的一种,修改当前属性值触发的回调函数,并且实参即为修改值 (注意 accessorsvaluewritable这两个冲突,逻辑上也很好理解)

【栗子】:

由于上一个例子演示了value和writable,这个例子就演示下get 和 set。
value/writableget/set是冲突的两组属性。
如果属性A设置了value/writable,那么这个属性A的属性可以直接通过obj.A访问,但是这样定义属性会有一个不方便的地方,那就是需要用到对象中其他属性的时候:
假设这样一个情景,一个对象的fullName属性需要通过firstNamelastName拼接而成,那么在定义的时候可能会写出这样的错误代码:

        var obj3 = {
            firstName : 'kobe',
            lastName : 'bryant',
            fullName : this.firstName + this.lastName
        }
        console.log(obj3)

最后的结果,obj3的fullName属性是NaN,为什么?
因为定义这个对象的时候,this指向的是window作用域,window里自然是没有firstNamelastName的。两个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函数里通过分割字符串分别修改firstNamelastName,这样下次再获取fullName的时候,就能根据新的firstNamelastName计算出新的fullName,相当于实现了对fullName的更新。

你可能感兴趣的:(javascript学习笔记,javascript,js)