js对象的深入理解(四-----精华篇)

本篇将讲解js对象的存取器,介绍两个重要的对象方法

为什么vue不兼容IE8,因为IE8不兼容ESMAScript5,Vue会将对象所有的属性遍历,使用Object.defineProperty把这些属性全部转为getter/setter.(存储器)

在ES5中,对象的属性值可以用一个或两个方法代替,这两个方法就是getter和setter,由getter和setter定义的属性被称为存取器属性 ,它不同于数据属性,数据属性只有一个简单的值

当我们查询存取器属性的值时,JavaScript调用getter方法(无参数)。这个方法的返回值就是属性存取表达式的值,将赋值表达式返回的值当成参数传入setter

我们之前提过对象的属性特性,比如可写可读,如果一个属性同事时具有getter|和setter方法,那么这个属性就是一个读/写属性,如果只有getter 只有setter 就晓得了吧

getter和setter

我们简单来看看如何使用

    var obj = {
    get p() {
        return 'getter';
    },
    set p(value) {
        console.log('setter: ' + value);
        return value
    }
    }
    console.log(obj.p) //getter
    console.log(obj.p=20) //setter:20

从这里我们能看出,首先调用属性会触发对象的getter方法,设置属性会触发对象的setter方法,而且setter方法是可以全局操作的,我们看下面这个例子

    var b=10
    var that=this
    var obj = {
    get p() {
        return 'getter';
    },
    set p(value) {
        that.b=value
        return value
    }
    }
    obj.p=20
    console.log(b)//20

最简单的运用

    var a={
        _age:18,//通过改变age判断方法的触发
        get age(){
            console.log('get')
            return this._age //getter方法没有参数
        },
        set age(val){ //参数就是我们改变数据的操作
            console.log('set')
            return this._age=val
        }
    }
    console.log(a.age) //18 get
    a.age=21
    console.log(a.age) //21 set
我们再来聊聊对象的属性特性,对象的四个特性,可读性(value),可写性(writable),可枚举性(enumerable),可配置性(configurable),这几个单词可以稍微加点印象,指不定哪天你在浏览文档的时候就能翻到这几个单词,比如undefined

我们之前就说过,undefined是JavaScript的一个全局属性
好,任何一个对象都有以上的属性,Object也为我们提供了方法用来判断

      var a={x:1}
      var b = Object.getOwnPropertyDescriptor(a,'x')
      console.log(b)  //{value: 1, writable: true, enumerable: true, configurable: true}

我们用存取器试试

    var a={
        _age:18,//通过改变age判断方法的触发
        get age(){
            console.log('get')
            return this._age //getter方法没有参数
        },
        set age(val){ //参数就是我们改变数据的操作
            console.log('set')
            return this._age=val
        }
    }
    console.log(Object.getOwnPropertyDescriptor(a,'age')) //{set: undefined, enumerable: true, configurable: true, get: ƒ}

如果未设置getter setter方法对应的就是undefined,相当于get代替了value,set代替了writable,继承的属性或者是不存在的属性都将返回undefined,了解一下

接下来我们讲一下对象两个重要的方法,虽然说重要不过可能很多小伙伴没见过

Object.defineProperties()和Object.defineProperty()

这两个方法有点像哈,英语小王子一眼就能看出来单复数了哈

Object的defineProperty和defineProperties这两个方法在js中的重要性十分重要,主要功能就是用来定义或修改这些内部属性,与之相对应的getOwnPropertyDescriptor和getOwnPropertyDescriptors就是获取这行内部属性的描述。后面两个就不多做描述了

我们都知道vue双向绑定原理就是Object.definePriperty()方法,我们先看看Object.defineProperties(),今天将以实现简单的双向绑定原理结束(还好今天UI小姐姐没让我改bug)

Object.definProperties()

功能:
方法直接在一个对象上定义一个或多个新的属性或修改现有属性,并返回该对象。
语法: Object.defineProperties(obj, props)

obj: 将要被添加属性或修改属性的对象
props: 该对象的一个或多个键值对定义了将要为对象添加或修改的属性的具体配置(简单来说就是映射表---看代码就懂)

     var obj = new Object();
    Object.defineProperties(obj, {
        name: {
            value: '张三',
            configurable: false,
            writable: true,
            enumerable: true
        },
        age: {
            value: 18,
            configurable: true
        }
    })
    console.log(obj.name, obj.age) // 张三, 18

很容易理解哈,然后我们看到我给age只设置了两个属性,可读可配置,我们来改一下看看行不行

     var obj = new Object();
    Object.defineProperties(obj, {
        name: {
            value: '张三',
            configurable: false,
            writable: true,
            enumerable: true
        },
        age: {
            value: 18,
            configurable: true
        }
    })
    obj.age=20
    console.log(obj.age) // 18  很明显这是不可以滴

我们使用Object.getOwnPropertyDescriptor()方法看看属性特性

     var obj = new Object();
    Object.defineProperties(obj, {
        name: {
            value: '张三',
            configurable: false,
            writable: true,
            enumerable: true
        },
        age: {
            value: 18,
            configurable: true
        }
    })
    var person = {
        name: '张三',
        age: 18
    }
    var desc = Object.getOwnPropertyDescriptor(obj, 'age'); 
    console.log(desc)   //obj.html:33 {value: 18, writable: false, enumerable: false, configurable: true}

没配置的为false

    var person = {
        name: '张三',
        age: 18
    }
    var desc = Object.getOwnPropertyDescriptor(person, 'age'); 
    console.log(desc)  //{value: 18, writable: true, enumerable: true, configurable: true}

我们常用的对象操作,默认属性都是true

之前介绍了delete 删除对象属性,也就是configurable为ture是可以删除的

    delete obj.age
    console.log(obj.age) //undefined   严格模式下出错 非严格模式下可以运行

那么Object.defineProperties(obj, props)也是可以使用存取器了

     var obj = new Object();
    Object.defineProperties(obj, {
        name: {
            value: '张三',
            configurable: false,
            writable: true,
            enumerable: true
        },
        age: {
            value: 18,
            configurable: true
        },
        sex:{
            get(){
                return 'nan'
            }
        }
    })
    console.log(obj.sex) // nan

当然也是可以配置属性特性

        sex:{
            get(){
                return 'nan'
            },
            configurable: false,
            writable: true,
            enumerable: true
        }

这个方法还是很强大的,我们可以根据需要更改特性,比如下方这个例子

    var obj={
        c:10
    }
    Object.defineProperties(obj, {
        name: {
            value: '张三',
            configurable: false,
            writable: true,
            enumerable: true
        },
        age: {
            value: 18,
            configurable: true
        },
        c:{          
            writable:false
        }

    })
    obj.c=20
    console.log(obj.c) // 10 设置成无法修改了

Object.defineProperty()

功能:
方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性, 并返回这个对象。如果不指定configurable, writable, enumerable ,则这些属性默认值为false,如果不指定value, get, set,则这些属性默认值为undefined

语法:Object.defineProperty(obj, prop, descriptor)
obj: 需要被操作的目标对象
prop: 目标对象需要定义或修改的属性的名称
descriptor: 将被定义或修改的属性的描述符

    var obj={

        c:10
    }
    Object.defineProperties(obj, {
        name: {
            value: '张三',
            configurable: false,
            writable: true,
            enumerable: true
        },
        age: {
            value: 18,
            configurable: true
        },

        c:{
            writable:false
        }

    })
    Object.defineProperty(obj,'c',{value:20})
    console.log(obj.c) //20

这样就可以更改值了,哪怕你是不可写的,当然这是在可配置的情况下

     c:{
            writable:false,
            configurable: false
        }

如果是不可配置的,就会报错注意一下
Object.defineProperty配置的对象是不可枚举的

    var obj={ 
    }
    Object.defineProperty(obj,'c',{value:20})
    for(var index in obj){
       console.log(index)  // kong
    }
   console.log(obj.c)// 20

但是可以取到这个属性哦

    var obj={
        c:10
    }
    Object.defineProperty(obj,'c',{writable:false})
    obj.c=20
    console.log(obj.c)// 10

很多方法在严格模式下是会报错的,如果我们已经设置了不可写做出修改操作,在严格模式下会报错,这三个参数都是必填,第三个参数写个{}也行,不能不写

两种方法还是很类似的,当然啦 也有这两种方法没办法为所欲为的时候,简单介绍一下对象的属性

原型属性

这个我们快速过,之前我们讲的Object.create()就是很好的代表

类属性

对象的类属性是个字符串,用来表示对象的类型信息,然而ES3与ES5都未设置这个属性的方法,有一种间接的方法可以查询到它

   function classof(obj){
    
    if(obj==null){
        return 'Null'
    }
    if(obj==undefined){
        return "Undefined"
    }
    return Object.prototype.toString.call(obj).slice(8,-1) //字符串过滤
   }
   console.log(classof(null)) //Null
   console.log(classof(1)) //Number
   console.log(classof("")) //String
   console.log(classof(false)) //Boolean
   console.log(classof(/./))  //RegExp

toString() 是 Object 的原型方法,调用该方法,默认返回当前对象的 [[Class]] 。这是一个内部属性,其格式为 [object Xxx] ,其中 Xxx 就是对象的类型。我把前面的内容去了更明了

可扩展性

对象的可扩展性用以表示是否可以给对象添加新属性,非常强悍,之前提到的两个方法在这里只有瑟瑟发抖的份

        var a={
            b:10
        }
        console.log(Object.isExtensible(a)) //true

如果为true表明是可扩展的
我们强力改变让它不可扩展

        var a={
            b:10
        }
        Object.preventExtensions(a) 
        console.log(Object.isExtensible(a)) //false

扩展性用以表示是否可以给对象添加新属性

        var a={
            b:10
        }
        a.c=20
        console.log(a.c) //20
        Object.preventExtensions(a)
        a.d=30
        console.log(a.d) //undefined

我们使用defineProperty尝试一下

        var a={
            b:10
        }
        a.c=20
        console.log(a.c) //20
        Object.preventExtensions(a)
        a.d=30
        Object.defineProperty(a,'e',{value:40})
        console.log(a.d) //undefined
        console.log(a.e) //报错 对象不可扩展 

可扩展性属性的目的是将对象锁定,防止外界的干扰,不过如果是继承的属性就没法拒绝,爸爸给的东西不管好的坏的都得乖乖受着

简单介绍一下可扩展性,有兴趣的可以去了解一下Object.seal()封闭,Object.freeze()冻结,更凶残

序列化对象

简单提一下,序列化对象是指将对象的状态转成字符串,也可将字符串还原为对象。
就是我们常用的JSON.strstringify()和JSON.parse()转字符串和转对象
JSON的全称就是 “JavaScript Object Notation”---------JavaScript对象表示法

我们写个简易的双向绑定结束这篇js对象

    
    
    
        
        
        
        
        Document
    
    
                

希望你可以理解,不懂欢迎留言

你可能感兴趣的:(js对象的深入理解(四-----精华篇))