js高级程序设计学习-OOP

1,383 阅读4分钟

导言

面向对象(OO)语言有一个标示, 那就是他们都有类的概念,而通过类可以创建任意多个具有相同属性和方法的对象。前面提到过, ES 中没有类的概念, 因此它的对象也与具有类的语言中的对象不同。

理解对象

创建一个自定义对象的最简单的方式就是创建一个 Object 的实例, 然后再为它添加属性和方法

var person = new Object();
person.name = 'zs';
person.age = 23;

早期的js开发人员经常使用这个模式创建新对象,后面,对象字母量成为创建这种对象的模式。

var person = {
    name : 'zs',
    age : 23,
    sayName : function () {
        console.log(this.name)
    }
}

属性类型

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

1.数据属性

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

  • Configurable : 表示能否通过 detele 删除属性从而重新定义属性 , 能否修改属性的特性, 或者能否把属性修改为访问器属性 。默认是 true
  • Enumerable : 表示能否通过 for-in 循环返回属性。 默认为 true
  • Writable : 表示能否修改属性的值。 默认为 true
  • Value : 包含这个属性的数据值, 默认为 undefined

要修改属性默认的特性 , 必须使用 ES5 的 Object.defineProperty()方法。

var person = {};
Object.defineProperty(person, "name", {
    writable : false,
    value : 'zs'
})
console.log(person.name); // 'zs'
person.name = 'hw'
// 不可修改
console.log(person.name); // 'zs'

把writable 设置为 false。 这个属性的值是不可修改的,在非严格模式下,赋值操作将被忽略;在严格模型下,将报错。

var person = {};
Object.defineProperty(person , 'name', {
    configurable : false,
    value : 'zs'
})
console.log(person.name)
delete person.name;
console.log(person.name)

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

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

2.访问器属性

访问器属性不包含数据值; 他们包含一对 getter 和 setter 函数。 访问器属性有如下4个特性:

  • Configuable : 表示通过 delete 删除属性从而重新定义属性 , 能否修改属性的特性 , 或者能否把属性修改为数据属性, 特性为默认值为 true
  • Enumerable : 表示能否 通过 for-in 返回循环。 默认为 true
  • GET : 默认为 undefined
  • SET : 默认为 undefined

定义多个属性

由于为对象定义多个属性的可能性很大 , ES5 又定义了一个 Object.defineProperties()方法。 利用这个方法可以通过描述符一次定义多个属性。 这个方法接收两个对象参数:

  • 第一个对象是要添加和修改的其属性的对象
  • 第二个对象的属性和第一个对象中要添加或修改的属性

读取属性的特性

使用 ES5 的 Object.getOwnPropertyDescriptor()方法, 可以获取给定属性的描述符。这个方法接收两个参数 : 属性所在的对象和要读取其描述符的属性名称

var book = {};
Object.defineProperties(person, {
    _year : {
        writable : true,
        value : 2004
    },
    edition : {
        writable : true,
        value : 1
    },
    year : {
        get : function() {
            return this._year;
        },
        set : function(newValue) {
            if(newValue > 2004) {
                this._year = newValue;
                this.edition += newValue;
            }
        }
    }
})
var descriptor = Object.getOwnPropertyDescriptor(book, "_year");
console.log(descriptor);
//{ value: 2004, writable: true, enumerable: false, configurable: false }

创建对象

虽然 Object 构造函数或对象字母量都可以用来创建单个对象 , 但这些方式有个明显的缺点 : 使用同一个接口创建很多对象 , 会产生大量的重复代码。 为解决这个问题 , 我们可以使用工厂模式的一种变体。

工厂模式

function createPerson(name , age ,job) {
    var o = new Object();
    o.name = name;
    o.age = age;
    o.job = job;
    o.sayName = function() {
        console.log(this.name)
    }
    return o;
}

构造函数模式

ES中构造函数可用来创建特点类型的对象。 像 Object 和 Array这样。此外 , 也可以创建自定义的构造函数, 从而定义对象类型的属性和方法。例如:

function Person(name , age, job) {
    this.name = name;
    this.age = age;
    this.job = job;
    this.sayName = function() {
        console.log(this.name)
    }
}
var p1 = new Person('zs',29,'sf');

通过 new 操作符。 以这种方式调用构造函数实际上会经历以下 4 步:

function mynew(Con , ...args) {
    var obj = {};
    obj.__proto__ = Con.prototype;
    let res = Con.apply(obj , args);
    return res instanceof Object ? res : obj;
}
  • 创建一个新对象
  • 将构造函数的作用域赋给新对象
  • 执行构造函数值的代码
  • 返回新对象