构造函数、原型对象、继承

构造函数

构造函数就是我们用new创建对象时调用的函数。到目前为止,我们已经学过好多内置的构造函数了,例如,Object,Array和Function。使用同一个构造函数创建的对象都具有相同的属性和方法。除了这些内置的构造函数外,我们也可以创建自己的构造函数。

构造函数也是函数,和普通函数的定义方式一样。唯一的区别是构造函数名的首字母应该大写,以此区分于其他函数。下面定义了一个空的Person函数。

function Person() {
    
}

定义好构造函数以后,你就可以用它来创建对象了,例如,下面使用Person构造函数创建了2个对象。

var person1 = new Person();
var person2 = new Person();

当我们使用 new 操作符调用函数时,函数内部会自动创建一个该类型的新对象。当函数调用完成时,该对象会被自动的返回到函数外部。我们可以使用 instanceof 操作符检查 person1 和 person2 是否是 Person 类型的对象实例:

console.log(person1 instanceof Person);  // true
console.log(person2 instanceof Person);  // true

由于person1和person2是通过Person构造函数创建的,因此使用instanceof操作符检查它们是否为Person类型的实例时返回true。

声明一个空的构造函数其实没有什么用。使用构造函数的目的是为了轻松创建许多拥有相同属性和方法的对象。我们可以在函数内部通过 this 关键字使用新创建的对象,如下例:

function Person(name) {
    this.myName = name;
    this.sayName = function() {
        console.log(this.myName);
    }
}

每个对象都有自己的myName属性,所以sayName()方法可以根据不同对象返回不同的值。

原型对象

prototype属性

一个对象实例通过内部属性 __proto__ 跟踪其原型对象。该属性的值是一个内存地址(指针),指向该实例使用(继承)的原型对象。当我们使用 new 创建一个新的对象时,构造函数的prototype对象会被赋值给新对象的__proto__属性。下图描绘了__proto__属性的指向:

原型对象链

由于原型对象也是一个对象,它也有自己的原型对象并继承原型对象中的属性。这就是原型对象链:对象继承其原型对象,而原型对象继承它的原型对象,依此类推。

当读取一个对象的属性时,JavaScript引擎首先在该对象的自有属性中查找属性名字。如果找到则返回。如果自有属性中不包含该属性,则JavaScript会沿着原型对象链搜索原型对象中的属性。如果找到则返回,否则返回undefined。

继承

学习如何创建对象是理解面向对象编程的第一步。第二步是理解继承。在传统的面向对象语言中,类从其他类继承属性。然而在JS中,在没有类的情况下,继承可以发生在对象之间。这种继承的机制你已经熟悉了,就是继承原型对象中属性。

原型对象继承

JS内置的继承方式被称为原型对象链继承,又可称为原型对象继承。就像我们前面讲的那样,原型对象的属性可以被对象实例访问,这就是继承的一种形式。对象实例继承了原型对象中的属性。

所有对象,包括那些我们通过自定义构造函数创建的对象都自动继承自Object,除非我们另有指定。更确切地说,所有对象都继承自Object.prototype。任何以Object的字面量形式创建的对象,其__proto__属性的值都被自动设置为Object.prototype,这意味着它继承Object.prototype的属性。

修改Object.prototype

所有对象都会继承Object.prototype对象的属性和方法。如下例所示,给Object.prototype添加方法:

Object.prototype.add = function (value) {
    return this + value;
};

添加到Object.prototype对象上的属性会被所有类型的对象所继承,有些时候这样写是没有意义的,并且还可能会出错。不要轻易修改Object.prototype对象。

对象继承

对象继承是最简单的继承方式。我们唯一需要做的就是指定哪一个对象是新对象的原型对象。对象字面量形式会隐式指定Object.prototype为其原型对象,我们也可以使用Object.create()方法显式指定原型对象。

Object.create()方法接受两个参数。第一个参数是需要被设置为新对象的原型对象。第二个参数是选的,用来为新对象添加属性。

两种声明具有相同的效果,第一种声明使用对象字面量形式来定义一个具有单一属性title的对象。该对象自动继承自Object.prototype,且其属性被默认设置为可配置、可枚举和可写。第二种声明使用Object.create()方法显式做了同样的操作。两个book对象的行为完全一致。但这样写没啥意义,使用字面量定义的对象默认就继承Object.prototype,因此我们没有必要这样写。继承自其他对象则更有趣。

猜你喜欢

转载自www.cnblogs.com/zhengedeboke/p/12076216.html