美文网首页
面向对象—理解对象

面向对象—理解对象

作者: 泡杯感冒灵 | 来源:发表于2020-06-29 10:54 被阅读0次

    什么是对象?

    我们可以把ECMAScript的对象想象成散列表,也就是一组名值对,其中值可以是数据和函数。

    对象的创建

    每个对象都是基于一个引用类型创建的,这个引用类型可以是原生类型,也可以是开发人员定义的类型

    常见的两种创建对象的方式:
    1. 创建一个Object的实例 (早期开发人员常用的创建新对象的方式)
            var person = new Object();
            person.name = '李修缘';
            person.age = 20;
            person.job = '开发';
    
            person.sayName = function (){
                alert(this.name)
            }
    
    1. 使用对象字面量创建对象
            var person = {
                name: '李修缘',
                age: 20,
                job: '开发',
    
                sayName: function(){
                    alert(this.name)
                }
            }
    

    这两种方式创建的 person对象是一样的,都有相同的属性和方法。这些属性在创建时都带有一些特征值,javaScript通过这些特征值来定义它们的行为。

    属性类型

    ECMA-262第五版在定义只有内部才用的特性(attribute)时,描述了属性(property)的各种特征。因为这些特性是为了实现javaScript引擎用的,因此在javaScript中不能直接访问它们。为了表示特性是内部值,该规范把它们放在了两对方括号中,例如[[Enumerable]]

    ECMAScript中有两种属性:数据属性访问器属性

    1. 数据属性

    数据属性包含一个数据值的位置。在这个位置可以读取和写入值。数据属性有4个描述其行为的特性

    • [[Configurable]]: 该特性表示能否通过delete删除属性从而重新定义属性,能否修改属性的特性,或者能否把属性修改为访问器属性。像前边两个例子中那样直接在对象上定义的属性,它们的这个特性默认值为true。
    • [[Enumerable]]:表示能否通过 for - in 循环返回属性。像前边两个例子中那样直接在对象上定义的属性,它们的这个特性默认值为true。
    • [[Writable]]: 表示能否修改属性的值。像前边两个例子中那样直接在对象上定义的属性,它们的这个特性默认值为true。
    • [[Value]]:包含这个属性的数据值。读取属性值的时候,从这个位置读;写入属性值的时候,把新值保存在这个位置。这个特性的默认值为undefined
    注意:要修改属性默认的特性,必须使用ECMAScript5Object.defineProperty()方法。这个方法接收三个参数属性所在的对象属性的名字一个描述符对象。其中描述符(descriptor)对象的属性必须是:configurable,enumerable,writable,value.设置其中的一个或多个值,可以修改对象的特性值。例如:
            var person = {};
            Object.defineProperty(person,"name", {
                writable: false,
                value:"飞鸟"
            })
    
            alert(person.name)  // "飞鸟"
            person.name = "孤峰"
            alert(person.name)  // "飞鸟"
    

    这个例子创建了一个name属性,它的值飞鸟是只读的。这个属性的值是不可修改的,如果尝试为它指定新值,非严格模式下,赋值操作将会被忽略,严格模式下,赋值操作会导致抛出错误。类似的规则也适用于不可配置的属性,例如configurable

            var person = {};
            Object.defineProperty(person,"name", {
                configurable: false,
                value:"飞鸟"
            })
    
            alert(person.name)  // "飞鸟"
            delete person.name 
            alert(person.name)  // "飞鸟"
    

    把configurable 设置为false,表示不能从对象中删除属性,如果对这个属性调用delete,在严格模式下什么也不会发生,在严格模式下会导致错误。而且,一旦把属性变为不可配置的,就不能再把它变回可配置了。此时再调用Object.defineProperty()方法修改除writable之外的特性都会导致错误。
    在调用Object.defineProperty()方法创建一个新的属性时,如果不指定,configurable,enumerable,writable,特性的默认值都是false。如果调用Object.defineProperty()方法只是修改已定义的属性的特性,则无此限制。

    2.访问器属性

    访问器属性不包含数据值;它们包含一对儿gettersetter函数(不过,这两个函数都不是必需的)。在读取访问器属性时,会调用getter函数,这个函数负责返回有效的值;在写入访问器属性时,会调用setter函数并传入心值,这个函数负责决定如何处理数据。访问器属性也有4个特性

    • [[Configurable]]: 该特性表示能否通过delete删除属性从而重新定义属性,能否修改属性的特性,或者能否把属性修改为数据属性。对于直接在对象上定义的属性,它们的这个特性默认值为true。
    • [[Enumerable]]:表示能否通过 for - in 循环返回属性。对于直接在对象上定义的属性,它们的这个特性默认值为true。
    • [[Get]]:在读取属性时调用的函数。默认值为undefined
    • [[Set]]:在写入属性时调用的函数。默认值为undefined

    访问器属性不能直接定义,必须使用Object.defineProperty()方法来定义。例如:

            var book = {
                _year:2019,
                edition:1
            }
            Object.defineProperty(book,"year", {
                get:function(){
                    return this._year;
                },
                set:function(newValue){
                    if(newValue > 2019){
                        this._year = newValue;
                        this.edition += newValue- 2019;
                    }
                }
            })
            book.year = 2020;
            alert(book.edition);  // 2
    

    以上代码创建了一个book对象,并给它定义了两个默认的属性:_year和edition 。_year前面的下划线是一种常用的记号,用于表示只能通过对象方法访问的属性。而访问器属性year则包含一个getter函数和一个setter函数getter函数返回_year的值,setter函数则通过计算来确定正确的版本。因此把year属性修改为2020会导致_year变为2020,而edition变为2.这是使用访问器属性的常见方式,即设置一个属性的值会导致其他属性发生变化。
    不一定非要同时指定getter函数setter函数。只指定getter函数意味着属性不能写,尝试写入会被忽略,严格模式下尝试下入会抛出错误。类似的,只指定setter函数的属性也不能读,否则在非严格模式下会返回undefined,严格模式下会抛出错误

    定义多个属性

    由于为对象定义多个属性的可能性很大,ECMAScript5又定义了一个Object.defineProperties()方法。利用这个方法可以通过描述符一次定义多个属性。
    该方法接收两个对象参数:第一个对象是要添加和修改其属性的对象,第二个对象的属性与第一个对象中要添加或修改的属性一一对应。例如:

            var book = {};
            Object.defineProperties(book,{
                _year:{
                    writable:true,
                    value:2019
                },
                edition:{
                    writable:true,
                    value:1
                },
                year:{
                    get:function() {
                        return this._year;
                    },
                    set:function(newValue) {
                        if(newValue > 2019){
                            this._year = newValue;
                            this.edition += newValue - 2019
                        }
                    }
                }
            })
    

    以上代码在book对象上定义了两个数据属性(year和edition)和一个访问器属性(year)。最终的对象与上个例子定义的对象相同。唯一的区别就是这里的属性都是同一时间创建的。

    该怎么读取属性的特性呢?

    • ECMAScript5定义了 Object.getOwnPropertyDescriptor()方法,可以取得给定属性的描述符。
    • 这个方法接收两个参数:属性所在对象要读取其描述符的属性名称
    • 该方法返回值是一个对象。
    1. 如果是访问器属性,这个对象的属性有configurableenumerrablegetset
    2. 如果是数据属性,这个对象的属性有configurableenumerrablewritablevalue
            var descriptor = Object.getOwnPropertyDescriptor(book,"_year")
            console.log(descriptor.value)  // 2019
            console.log(descriptor.writable)  //true
            console.log(descriptor.configurable)  //false
            console.log(descriptor.get)  //undefined
    
    
      
            var descriptor = Object.getOwnPropertyDescriptor(book,"year")
            console.log(descriptor.value)  // undefined
            console.log(descriptor.enumerable)  //false
            console.log(typeof descriptor.get)  // function  get是一个指向getter函数的指针
    

    在JavaScript中,可以针对任何对象,包括DOM和BOM对象,使用 Object.getOwnPropertyDescriptor()方法

    相关文章

      网友评论

          本文标题:面向对象—理解对象

          本文链接:https://www.haomeiwen.com/subject/pkbsfktx.html