面向对象—理解对象

2020-06-29  本文已影响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个描述其行为的特性

注意:要修改属性默认的特性,必须使用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个特性

访问器属性不能直接定义,必须使用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)。最终的对象与上个例子定义的对象相同。唯一的区别就是这里的属性都是同一时间创建的。

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

  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()方法

上一篇下一篇

猜你喜欢

热点阅读