面向对象的程序设计

一、对象属性类型

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

        [[Configurable]]:表示能否通过 delete 删除属性从而重新定义属性,能否修改属性的特性,或者能否把属性修改为访问器属性。像前面例子中那样直接在对象上定义的属性,它们的这个特性默认值为 true。

        [[Enumerable]]:表示能否通过 for-in 循环返回属性。像前面例子中那样直接在对象上定义的属性,它们的这个特性默认值为 true。

        [[Writable]]:表示能否修改属性的值。像前面例子中那样直接在对象上定义的属性,它们的这个特性默认值为 true。

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

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

        一旦把属性定义为不可配置的(configurable:false), 就不能再把它变回可配置了。此时,再调用 Object.defineProperty()方法修改除 writable 之外 的特性,

        var a = 0,  window.a的configurable默认为false;

        window.a = 0, window.a的configurable默认为true;

    2. 访问器属性

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

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

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

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

        var book = {

              _year: 2004,

            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 = 2005; alert(book.edition); //2

        支持 ECMAScript 5 的这个方法的浏览器有 IE9+(IE8 只是部分实现)、Firefox 4+、Safari 5+、Opera 12+和 Chrome。在这个方法之前,要创建访问器属性,一般都使用两个非标准的方法: __defineGetter__()和__defineSetter__()。这两个方法最初是由 Firefox 引入的,后来 Safari 3、 Chrome 1 和 Opera 9.5 也给出了相同的实现。使用这两个遗留的方法,可以像下面这样重写前面的例子。

        var book = {

            _year: 2004,

            edition: 1

        };        

        //定义访问器的旧有方法 

        book.__defineGetter__("year", function(){

            return this._year;

        });

        book.__defineSetter__("year", function(newValue){

            if (newValue > 2004) {

                this._year = newValue;

                this.edition += newValue - 2004;

            }

        });

        book.year = 2005; alert(book.edition); //2

        在 不 支 持 Object.defineProperty() 方 法 的 浏 览 器 中 不 能 修 改 [[Configurable]] 和 [[Enumerable]]。

    3、读取属性的特性

        ECMAScript 5 的 Object.getOwnPropertyDescriptor()方法,可以取得给定属性的描述 符。这个方法接收两个参数:属性所在的对象和要读取其描述符的属性名称。返回值是一个对象,如果 是访问器属性,这个对象的属性有 configurable、enumerable、get 和 set;如果是数据属性,这 个对象的属性有 configurable、enumerable、writable 和 value。

二、创建对象

    关于创建对象的几种模式我就不多赘述了,总体的思想是将公共方法和属性放在构造函数的原型中,在这我主要列出ES6及ES6之前的写法。

    ES6之前:

        function Person (name) {

            this.name = name

        }

        Person.prototype.sayHi = function(){

            return  'sayHi';

        }

        var person = new Person('Tom')

        console.log(person.name)  // Tom

        console.log(person.sayHi()) // sayHi

    ES6:  class Person {

                    constructor(name){

                        this.name = name;

                    }

                    sayHi(){

                        return  'sayHi';

                    }

               }


              let person = new Person('Tom')

              console.log(person.name)  // Tom

              console.log(person.sayHi()) // sayHi

三、继承

    实现继承最好的就是寄生组合继承方法了,ES6的extends也是基于此来实现继承的;以下是2种写法:

    ES6之前:

        function SuperType (name) {

            this.name = name

        }

        SuperType.prototype.sayHi = function(){

            return  this.name +  'sayHi';

        }

        function SubType (name,age) {

            SuperType.call(this,name);

            this.age = age

        }

        function inheritPrototype(subType, superType){

            var prototype = Object.create(superType.prototype);  // ES5 支持 Object.create()

           prototype.constructor = subType;

           subType.prototype = prototype;

        }

        inheritPrototype(SubType,SuperType);

        var subType = new SubType('Tom')

        console.log(subType.name)  // Tom

        console.log(subType.sayHi()) // TomsayHi

    ES6:  class SuperType {

                constructor(name){

                    this.name = name;

                }

                sayHi(){

                    return  `${this.name}sayHi`;

                }

            }

           class SubType  extends SuperType {

                constructor(name,age){

                    super(name) 

                    this.age = age;

                }

            }

          let subType = new SubType('Tom')

           console.log(subType.name)  // Tom

           console.log(subType.sayHi()) // TomsayHi

       子类必须在constructor方法中调用super方法,否则新建实例时会报错。如果子类在constructor方法中使用了this初始化实例属性,调用super方法必须放到this初始化实例属性的前面。这是因为子类没有自己的this对象,而是继承父类的this对象,然后对其进行加工。如果不调用super方法,子类就得不到this对象。

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