第6章 面向对象程序设计

ECMAScript把对象定义为:“无序属性的集合,其属性可以包含基本值、对象或者函数。”

无论是用Object实例创建一个对象,还是对象字面量创建一个对象,它们都有属性和方法。这些属性在创建时都带有一些特征值,JavaScript通过这些特征值来定义它们的行为。

6.1.1 属性的类型

ECMAScript第5版在定义只有内部才用的特征时,描述了属性的各种特征。定义这些特征是为了实现JavaScript用的,因此在JavaScript中不能直接访问它们。为了表示特性是内部值,该规范把它们放在了两对方括号中[[]]。

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

1.数据属性

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

[[Configurable]]:表示能否通过delete删除属性从而重新定义属性,能否修改属性的特性,或者能否把属性修改为访问器属性。直接在对象上定义的默认是true

[[Enumerable]]:表示能否通过 for-in循环返回属性。直接在对象上定义的默认是true

[[Writable]]:表示能否修改属性的值。直接在对象上定义的默认是true

[[Value]]:包含这个属性的数据值。读取属性值的时候,从这个位置读,写入的时候,把新值保存在这个位置。这个特性的默认值为undefined。

例: var person = { name: “Jason”};

对于这个例子,它的[[Configurable]] [[Enumerable]]  [[Writable]]特性都被设置为true,而[[Value]] 特性被设置为指定的值—Jason。

要修改属性默认的特性,必须使用ECMAScript5 的 Object.defineProperty()方法。这个方法接收三个参数:属性所在的对象、属性的名字和一个描述符对象 。其中描述符对象的属性必须是:configurable、enumerable、writable和value。设置其中的一或者多个值,可以修改对应的特性值。

例:

var person = {};

Object.defineProperty(person, "name", {

    writable: false, //设置不能修改属性的值

    value: "Jason Liu"

});

console.log(person.name); // Jason liu

person.name = "IronMan";

console.log(person.name); // Jason Liu

Object.defineProperty(person, age, {

    configurable: false, //设置为不能从对象中删除属性。

    value: 23

});

console.log(person.age);// 23

delete person.age;

console.log(person.age); // 23

在调用Object.defineProperty()方法创建一个新的属性时,如果不指定,configurable、enumerable、writable特性的默认值都是false。

2.访问器属性

访问器的属性不包含数据值;它们包含一对儿 getter 和 setter函数(不是必须)。在读取访问器属性时,会调用getter函数,这个函数负责返回有效的值;在写入访问器属性时,会调用setter函数并传入新值,这个函数负责决定如何处理数据。访问器有四个特征:

[[Configurable]]:表示能否通过delete删除属性从而重新定义属性,能否修改属性的特征性,或者能否把属性修改为数据属性。对于直接定义在对象上的,默认值是true。

[[Enumerable]]:表示能否通过 for-in 循环返回属性。对于直接在对象上定义的属性,这个特征的默认值是true。

[[Get]]:在读取属性时调用的函数。默认值为 undefined。

[[Set]]:在写入属性时调用的函数,默认值是undefined。

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

例:

var book = {

    _year:2018,

    edition:1

};

Object.defineProperty(book, "year", {

get:function() {

    return this._year;

 },

set:function(newValue) {

    if(newValue >2004) {

    this._year = newValue;

            this.edition  += newValue -2004;

        }

    }

});

book.year =2006;

console.log(book.edition); // 3

console.log(book._year);// 2006

这是使用访问器属性的常见方式,即设置一个属性的值会导致其它属性发生变化。

6.1.2 定义多个属性

Object.defineProperties() 通过描述符一次定义多个属性

例:

var book = {};

Object.defineProperties(book, {

    _year: {

        writable:true,

         value:2017

  },

  edition: {

        writable:true,

          value:1

  },

year: {

     get:function() 

           return this._year

       },

set:function(newValue) {

    if(newValue >2015) {

               this._year = newValue;

              this.edition += newValue -2014;

              }

        }

    }

});

book.year =2016;

console.log(book.edition); // 3

console.log(book.year); //2016

6.2.3 原型模式

创建的每个函数都有一个 prototype(原型) 属性,这个属性是一个指针,指向一个对象,而这个对象的用途是包含由特定类型的所有实例共享的属性和方法。prototype就是通过调用构造函数而创建的那个实例对象的原型对象。

1.理解原型对象

无论什么时候,只要创建了一个新函数,就会根据一组特定的规则为该函数创建一个 prototype 属性,这个属性指向函数的原型对象。在默认情况下,所有的原型对象都会自动获得一个 constructor(构造函数)属性,这个属性是一个指向 prototype 属性所在函数的指针。

创建自定义的构造函数之后,其原型对象默认值会取得 constructor 属性;至于其它方法,则都是默认从 Object 继承而来的。当调用构造函数创建一个新实例后,该实例的内部将包含一个指针,指向构造函数的原型对象。 



第6章 面向对象程序设计_第1张图片

isPrototypeOf()  如果 [[Prototype]] 指向调用 isPrototypeOf() 方法的对象,那么这个方法就会返回true。

Object.getPrototypeOf() 返回 [[Prototype]]  的值。

每当代码读取某个对象的某某个属性时,都会执行一次搜索,目标是具有给定名字的属性。搜索首先从对象的实例本身开始。如果在实例中找到了具有给定名字的属性,则返回该属性的值。如果没有找到,则继续搜索指针指向的原型对象,在原型对象中查找具有给定名字的属性。如果在原型对象中找到了,则返回这个属性的值。

当为对象实例添加一个属性时,这个属性就会屏蔽原型对象中保存的同名属性。添加这个属性只能阻止我们访问原型中的那个属性。即使将这个属性设置为null,也只会在实例中设置这个属性,而不会恢复其指向原型的连接。但是使用 delete 操作符则可以完全删除实例属性,从而能够重新访问原型中的属性。

hasOwnProperty() 检测属性是存在于实例中还是存在与原型中。


第6章 面向对象程序设计_第2张图片
hasOwnProperty() 方法

2. 原型与in操作符

有两种方式使用 in 操作符:单独使用和在for-in 循环中使用。单独使用时,in 操作符会通过对象能够访问给定属性时返回true,无论该属性存在实例中还是原型中。


第6章 面向对象程序设计_第3张图片
in操作符

利用 in操作符和 hasOwnProperty() 方法判断通过对象能够访问的属性是存在与原型还是实例当中。


第6章 面向对象程序设计_第4张图片

Object.keys()获取对象上所有可枚举的实例属性。返回值是对象上所有可枚举的实例属性组成的一个数组。

Object.getOwnPropertyName() 获取所有实例属性,无论是否能枚举。

你可能感兴趣的:(第6章 面向对象程序设计)