资讯专栏INFORMATION COLUMN

JavaScript创建对象与继承方法(笔记)

go4it / 720人阅读

摘要:因而可更改为增加属性这种写法要注意,创建实例一定要在定义原型之后,因为重写原型对象就切断了构造函数与最初原型的联系。借用构造函数的问题还是和构造函数创建对象一样,方法都在构造函数定义,函数复用就无从谈起了。

一.创建对象
虽然Object构造函数或对象字面量可以用来创建单个对象,但有个明显缺点:使用同一个接口创建很多对象会产生大量重复代码。因而大家开始探索其他方式。
1.工厂模式

function createPerson (name, age) {
    var o = new Object():
    o.name = name;
    o.age = age;
    o.sayName = function () {
        console.log(this.name);
    }
    return o;
}
var person = createPerson("Lily", 12);

工厂模式特点:虽然解决了创建多个相似对象的问题,但却无法识别一个对象的类型。(instance of)
2.构造函数模式

function Person (name, age) {
    this.name = name;
    this.age = age;
    this.sayName = function () {
        console.log(this.name);
    }
}
var person = new Person("Lily", 12); //使用构造函数模式创建实例,必须使用new操作符。

构造函数模式特点:可以将它的实例标识为一种特定类型,但每个方法都要在实力上重新创建一遍。
3.原型模式

function Person () {}
Person.prototype.name = "Lily";
Person.prototype.age = 12;
Person.prototype.sayName = function () {
    console.log(this.name);
}
var person = new Person(); //使用hasOwnProperty方法可以检测一个属性存在于实例还是原型。
console.log(person.hasOwnProperty("name")); //false
person.name = "Tom"; //来自实例
console.log(person.hasOwnProperty("name")); //true

更简单的原型语法:

function Person () {}
Person.prototype = {
    name: "Lily",
    age: 12,
    sayName: function () {
        console.log(this.name);
    }
} //这样写会导致constructor属性不再指向Person了。(无论何时创建一个新函数A,都会为它创建一个prototype属性,指向函数的原型对象,默认情况下,所有原型对象都会获得一个constructor属性,包含一个指向A的指针。)

因而可更改为:

function Person () {}
Person.prototype = {
    constructor: Person, //增加constructor属性
    name: "Lily",
    age: 12,
    sayName: function () {
        console.log(this.name);
    }
} //这种写法要注意,创建实例一定要在定义原型之后,因为重写原型对象就切断了构造函数与最初原型的联系。

原型模式的特点:实现了让所有实例共享原型对象所包含的属性和方法。但缺点也在于这种共享对于包含引用类型值的属性而言,存在一些问题,即所有实例会共享一个数组或者对象。
4.组合构造函数模式和原型模式

function Person (name, age) {
    this.name = name;
    this.age = age;
    this.friends = ["Tom", "Bob"];
}
Person.prototype = {
    constructor: Person,
    sayName: function () {
        console.log(this.name);
    }
}

构造函数模式用于定义实例属性,而原型模式用于定义方法和共享的属性。这是目前最广泛,认同度最高的方法。
5.动态原型模式
有其他OO语言经验的开发人员看到独立的构造函数和原型,可能会困惑。动态原型模式则是致力于解决此问题的一个方案,它把所有信息都封装在了构造函数中,在必要情况下,通过在构造函数中初始化原型,保持了组合使用构造函数和原型的优点。

function Person (name, age) {
    this.name = name;
    this.age = age;
    this.friends = ["Tom", "Bob"];
    if (type of this.sayName != "function") {
        Person.prototype.sayName = function () {
            console.log(this.name);
        }
    } //if语句只需检查一个初始化应该存在的共享属性或方法即可。
}

使用动态原型模式要记得不能用对象字面量重写原型,因为如果在创建了实例的情况下重写原型。那么就会切断现有实例与新原型的联系。
关于寄生构造模式和稳妥构造模式,在工程实践用的不多且稍显过时,就不赘述了。有时间可以了解es6的class。
二.继承
1.原型链

function SuperType(){
    this.property = true;
}
SuperType.prototype.getSuperValue = function () {
    return this.property;
}
function SubType(){
    this.property = false;
}
SubType.prototype = new SuperType();
SubType.prototype.getSubValue = function () {
    return this.property;
}

需要注意的是,在通过原型链实现继承时,不能用对象字面量创建原型方法,因为这样会重写原型链。如下所示:

function SuperType(){
    this.property = true;
}
SuperType.prototype.getSuperValue = function () {
    return this.property;
}
function SubType(){
    this.property = false;
}
SubType.prototype = new SuperType();
SubType.prototype = {
    getSubValue: function () {
        return this.subproperty;
    },
    someOtherMethod: function () {
        return false;
    }
} //这样会导致SubType的实例无法访问到getSuperValue()方法了。

原型链继承的问题:
1.共享实例属性,如果SupeType中定义一个数组colors,当subType通过原型链继承SuperType后,它也会拥有一个colors属性(就像专门创建了一个subType.prototype.colors属性一样),结果是SubType所有实例都会共享这个属性。对其中一个实例.colors属性会影响到所有其他实例。
2.在创建子类型的实例时,没办法在不影响所有对象实例的情况下,向超类型的构造函数传递参数。
因此实践中很少多带带使用原型链继承。
2.借用构造函数

function SuperType (name) {
    this.name = name;
    this.colors = ["red", "blue", "yellow"];
}
function SubType () 
    SuperType.call(this, "Lily");
    this.age = 12;
} //使用这种方式就可以向超类型的构造函数传参啦。

借用构造函数的问题:还是和构造函数创建对象一样,方法都在构造函数定义,函数复用就无从谈起了。
3.组合继承
使用原型链实现对原型属性和方法的继承,而通过构造函数实现对实例属性的继承。

function SuperType (name) {
    this.name = name;
    this.colors = ["red", "blue", "yellow"];
}
SuperType.prototype.sayName = function () {
    console.log(this.name);
};
function SubType (name, age) 
    // 继承实例属性
    SuperType.call(this, name); //第二次调用SuperType()
    this.age = age;
}
//继承方法
SubType.prototype = new SuperType(); //第一次调用SuperType()
SubType.prototype.constructor = SubType;
SubType.prototype.sayAge = function () {
    console.log(this.age);
}
var instance1 = new SubType("Lily", 12);
instance1.colors.push("green");
console.log(instance1.colors); // "red,blue,yellow,green"
var instance2 = new SubType("Lucy", 22);
console.log(instance1.colors); // "red,blue,yellow"

组合继承避免了原型链和借用构造函数的缺陷,是一种较为流行的继承方式。但是它还存在一个缺点:在第一次调用superType时,SubType.prototype会得到两个属性:name和colors,当调用SubType的构造函数时又会再调用一次SuperType构造函数,在对象实例上创建了实例属性name和colors屏蔽了SubType原型中的同名属性。
寄生组合式继承
寄生组合式是组合式继承的改进,思路是不必为了指定子类的原型而调用超类的构造函数,仅复制超类的原型即可。

function SuperType (name) {
    this.name = name;
    this.colors = ["red", "blue", "yellow"];
}
SuperType.prototype.sayName = function () {
    console.log(this.name);
};
function SubType (name, age) 
    // 继承实例属性
    SuperType.call(this, name); 
    this.age = age;
}
//继承方法
SubType.prototype = Object.create(SuperType.prototype);
//Object.create(obj)相当于 function F(){}; F.prototype = obj;return new F();
SubType.prototype.constructor = SubType;
SubType.prototype.sayAge = function () {
    console.log(this.age);
}

开发人员普遍认为寄生组合式继承是引用类型最理想的继承方法。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/97987.html

相关文章

  • JavaScript面向对象编程学习笔记---概念定义

    摘要:子类继承自父类的方法可以重新定义即覆写,被调用时会使用子类定义的方法什么是多态青蛙是一个对象,金鱼也是一个对象,青蛙会跳,金鱼会游,定义好对象及其方法后,我们能用青蛙对象调用跳这个方法,也能用金鱼对象调用游这个方法。 1、专用术语 面向对象编程程序设计简称:OOP,在面向对象编程中常用到的概念有:对象、属性、方法、类、封装、聚合、重用与继承、多态。 2、什么是对象? 面向对象编程的重点...

    mikasa 评论0 收藏0
  • 《你不知道的javascript笔记_对象&原型

    摘要:上一篇你不知道的笔记写在前面这是年第一篇博客,回顾去年年初列的学习清单,发现仅有部分完成了。当然,这并不影响年是向上的一年在新的城市稳定连续坚持健身三个月早睡早起游戏时间大大缩减,学会生活。 上一篇:《你不知道的javascript》笔记_this 写在前面 这是2019年第一篇博客,回顾去年年初列的学习清单,发现仅有部分完成了。当然,这并不影响2018年是向上的一年:在新的城市稳定、...

    seasonley 评论0 收藏0
  • Javascript 设计模式读书笔记(三)——继承

    摘要:的继承方式属于原型式继承,非常灵活。当使用关键字执行类的构造函数时,系统首先创建一个新对象,这个对象会继承自构造函数的原型对象新对象的原型就是构造函数的属性。也就是说,构造函数用来对生成的新对象进行一些处理,使这个新对象具有某些特定的属性。 继承这个东西在Javascript中尤其复杂,我掌握得也不好,找工作面试的时候在这个问题上栽过跟头。Javascript的继承方式属于原型式继承,...

    cangck_X 评论0 收藏0
  • javascript高级程序设计》第六章 读书笔记javascript继承的6种方法

    摘要:继承的是超类型中构造函数中的属性,如上继承了属性,但没有继承原型中的方法。上述造成的结果是子类型实例中有两组超类型的构造函数中定义的属性,一组在子类型的实例中,一组在子类型实例的原型中。 ECMAScript只支持实现继承,主要依靠原型链来实现。与实现继承对应的是接口继承,由于script中函数没有签名,所以无法实现接口继承。 一、原型链 基本思想:利用原型让一个引用类型继承另一个引用...

    孙吉亮 评论0 收藏0
  • JavaScript学习第十天笔记继承

    摘要:继承原型链如果构造函数或对象的原型指向构造函数或对象,的原型再指向构造函数或对象,以此类推,最终的构造函数或对象的原型指向的原型。 继承 原型链 如果构造函数或对象A的原型指向构造函数或对象B,B的原型再指向构造函数或对象C,以此类推,最终的构造函数或对象的原型指向Object的原型。由此形成了一条链状结构,被称之为原型链。按照上述的描述,在B中定义的属性或方法,可以在A中使用并不需要...

    baiy 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<