`
winxpxt
  • 浏览: 28357 次
  • 性别: Icon_minigender_2
  • 来自: 厦门
社区版块
存档分类

javascript代码复用--继承

 
阅读更多

由于javascript没有类的概念,因此无法通过接口继承,只能通过实现继承。实现继承是继承实际的方法,javascript中主要是依靠原型链要实现。

原型链继承

原型链继承是基本的继承模式,其本质是重写原型对象,使其为新对象的实例。代码实现如下:

复制代码
function Person(){

    this.name = "default";

    var temp = "temp";

}

Person.prototype.age=0;

Person.prototype.getName = function(){

    return this.name;

}

Person.prototype.getAge = function(){

    return this.age;

}

console.log(Person.prototype.age);//0

console.log(Person.age);//undefined

console.log(Person.prototype.name);//undefined

console.log(Person.name);//Person, if other property, should be undefined

function Student(){

    this.type = "student";

}

//inheritance

Student.prototype = new Person();

console.log(Student.prototype.constructor);//Person(){}

console.log(Student.prototype.name);//default

Student.prototype.constructor = Student;

var student1 = new Student();

console.log(student1.getName());//default

console.log(student1.name);//default

console.log(student1.getAge());//0

console.log(student1.age);//0

console.log(student1.__proto__.age);//0

console.log(student1.temp);//undefined

console.log(student1 instanceof Object);//true

console.log(student1 instanceof Person);//true

console.log(student1 instanceof Student);//true

console.log(Student instanceof Person);//false
复制代码

 

以上代码主要注意两个问题:

1.函数局部变量,内部属性及原型属性的区别。var temp定义了一个局部变量,this.name定义了一个内部属性,prototype.age则定义了一个原型属性。

对于局部变量,无法在函数以外的地方调用,包括实例。

之前说过,函数本身的prototype属性仅仅用于函数实例的属性继承,而函数本身不会使用这个关联的prototype,在prototype中设置的属性将直接作用于所有实例。(比如Person的实例Student.prototype和student1,注意Student并不是Person的实例

而对于函数内部属性,函数实例将直接拥有对应的内部属性(初始值),而无法通过函数本身使用内部属性。这一点其实跟prototype属性有所区别。

2.利用重写原型对象实现继承的时候,Student.prototype = new Person(), Student.prototype将指向了另一个对象Person.prototype,因此此时Student.prototype.constructor将指向Person函数。通过Student.prototype.constructor = Student 可以将其constructor重新指向Student。

通过原型链可以更好的理解上面的代码:

clip_image001

 

原型链继承的缺点

关于原型链继承的问题,其实就是跟通过原型方式创建对象的问题一样,就是原型中包含引用类型所带来的共享问题。

还有就是创建实例的时候,无法向构造器中传递参数。

 

构造函数继承

另一种经典的继承便是通过构造函数实现继承,即通过apply()和call()方法在子类构造函数内部调用父类构造函数。具体实现如下:

复制代码
function Person(name){

    this.name = name;

    this.friends = new Array();

}

Person.prototype.age = 0;

function Student(name){

    Person.call(this, name);

}

var student1 = new Student("Huge");

student1.friends.push("Alan");

console.log(student1.name);//Huge

console.log(student1.age);//undefined

console.log(student1.friends);//["Alan"]

var student2 = new Student("Heri");

student2.friends.push("Amly");

console.log(student2.name);//Heri

console.log(student2.friends);//["Amly"]

console.log(student1 instanceof Person);//false

console.log(student1 instanceof Student);//true
复制代码

 

通过构造函数继承的问题除了构造函数模式本身存在的缺点之外(重复实例化方法),也无法类型识别,因此在父类原型中定义的方法和属性无法在子类中调用。

 

组合继承

由于通过原型链继承和构造函数继承都有其优缺点,因此将这两种继承方式组合起来,使用原型链继承实现原型中方法和属性的继承,通过构造函数继承实现参数传递和引用类型继承,是javascript中最常用的继承模式。代码实现如下:

复制代码
function Person(name, age){

    this.name = name;

    this.age = age;

    this.friends = new Array();

}

Person.prototype.getName = function(){

    return this.name;

}

function Student(name, age){

    this.type = "student";

    Person.call(this, name, age);

}

Student.prototype = new Person();

Student.prototype.constructor = Student;

var student1 = new Student("Huge", 15);

student1.friends.push("Alan");

console.log(student1.name);//Huge

console.log(student1.age);//15

console.log(student1.friends);//["Alan"]

console.log(student1.getName());//Huge

console.log(student1 instanceof Person);//true

console.log(student1 instanceof Student);//true

var student2 = new Student("Heri", 16);

student2.friends.push("Amly");

console.log(student2.name);//Heri

console.log(student2.age);//16

console.log(student2.friends);//["Amly"]

console.log(Student.prototype.name);//undefined

console.log(Student.prototype.friends);//[]
复制代码

 

从代码可以看出,组合继承会调用两次父类的构造函数:创建子类原型的时候和在子类构造函数内部调用。实际上,第一次创建子类原型的时候,子类已经包含了父类对象的全部实例属性,因此当通过调用子类构造函数创建实例的时候,将会重写这些属性。即同时存在两组属性,一组在实例上,一组在子类原型中,如上代码中Student.prototype.friends返回的空数组。这就是调用两次父类构造函数的结果

 

其他继承方式

Crockford曾经提出了prototypal inheritance以及与之结合的parasitic inheritance。通过原型创建基于原有对象的新对象,并为新对象增加功能。

复制代码
//prototypal inhertance

function createObject(obj){

    function F(){}

    F.prototype = obj;

    return new F();

}

//parasitic inheritance

function enhanceObject(obj){

    var enhanceObj = createObject(obj);

    enhanceObj.getName = function(){

       return this.name;

    }

    return enhanceObj;

}

var person = {

    name : "Alan"

};

var person1 = enhanceObject(person);

console.log(person1.getName());//Alan
复制代码

 

更进一步,为了避免组合继承模式两次调用父类构造函数的问题,可以利用parasitic inheritance来继承父类的原型,再将其指定给子类的原型。如下代码:

复制代码
//prototypal inhertance

function createObject(obj){

    function F(){}
    
    F.prototype = obj;

    return new F();

}

//parasitic inheritance

function inheritPrototype(superObj, subObj){

    var obj = createObject(superObj.prototype);

    obj.constructor = subObj;

    subObj.prototype = obj;

}

function Person(name, age){

    this.name = name;

    this.age = age;

    this.friends = new Array();

}

Person.prototype.getName = function(){

    return this.name;

}

function Student(name, age){

    this.type = "student";

    Person.call(this, name, age);

}

inheritPrototype(Person, Student);

var student1 = new Student("Huge", 15);

student1.friends.push("Alan");

console.log(student1.name);//Huge

console.log(student1.age);//15

console.log(student1.friends);//["Alan"]

console.log(student1.getName());//Huge

console.log(student1 instanceof Person);//true

console.log(student1 instanceof Student);//true

var student2 = new Student("Heri", 16);

student2.friends.push("Amly");

console.log(student2.name);//Heri

console.log(student2.age);//16

console.log(student2.friends);//["Amly"]\

console.log(Student.prototype.name);//undefined

console.log(Student.prototype.friends);//undefined
复制代码

 

可以看出,子类只调用了父类一次构造函数,避免在子类原型中创建不必要的属性。同时,原型链也保持不便,可以说是实现类型继承的最有效方式。

0
1
分享到:
评论

相关推荐

    javascript实例应用---综合类.rar

    9. **模块化**:通过export和import关键字,JavaScript支持模块化开发,可以将代码组织成独立的模块,提高代码复用性和可维护性。 10. **ES6及后续版本的新特性**:ECMAScript(ES)是JavaScript的标准,每个新版本...

    简单谈谈javascript代码复用模式

    在探讨JavaScript代码复用模式时,首先需要了解代码复用的原则,以及JavaScript中对象的创建和继承机制。在软件工程中,代码复用是一种提高开发效率、降低软件维护成本的有效方式。GoF(设计模式的四位作者,即Erich...

    JavaScript代码复用模式详解

    JavaScript代码复用是提高效率和减少冗余的关键实践。它主要依赖于对象组合和原型继承等机制。在JavaScript中,由于没有传统的类概念,而是基于原型的面向对象模型,因此,代码复用的方式与C++或Java等使用类的语言...

    JavaScript教程--从入门到精通

    理解原型和原型链是掌握JavaScript面向对象编程的关键,这涉及到对象的继承、方法的调用以及如何使用Object.create()、__proto__和prototype属性。 事件处理是JavaScript在网页交互中不可或缺的部分。你将学习如何...

    javascript基础-->中级-->高级-->面向对象

    6. Mixins(混合):通过组合多个组件,实现代码复用,尤其在没有类的JavaScript中,是一种重要的面向对象设计模式。 总结,JavaScript从基础到高级,再到面向对象的深入学习,对于任何参与Web建设的IT人员来说都是...

    javascript网页开发-张孝祥.pdf

    - **原型链**:JavaScript使用原型继承机制实现对象之间的继承关系,通过原型链查找属性和方法。 - **异步编程**:JavaScript支持异步编程模型,包括回调函数、Promise、async/await等技术。 - **模块化**:ES6引入...

    javascript-高性能javascript模版引擎-templateEngine.zip

    5. **模板继承和部分**:通过父模板和子模板,实现代码复用。 常见的JavaScript模板引擎有: 1. **EJS**:简单易用,支持内联和外部模板,提供丰富的控制流和辅助函数。 2. **Mustache**:无逻辑的模板引擎,遵循...

    javascript继承之为什么要继承.docx

    然而,在 JavaScript 中,继承机制并不是唯一的代码复用方法。组合也是一个非常重要的机制,它可以通过将多个对象组合成一个对象来实现代码复用。例如,我们可以创建一个 Walk 对象和一个 Fly 对象,然后将它们组合...

    JavaScript-Core-and-Practice

    函数是可重复使用的代码块,能够提高代码的模块化和复用性。 在深入JavaScript的核心时,我们不能忽视对象和原型。JavaScript中的对象是键值对的集合,原型则是实现继承的关键机制。通过原型链,一个对象可以继承另...

    Javascript教程--从入门到精通.rar

    1. **面向对象编程**:JavaScript支持基于原型的对象导向编程,包括构造函数、原型链、继承和封装等概念,对于编写复用性更强的代码至关重要。 2. **闭包**:闭包是JavaScript中的一个高级特性,它能保留内部函数的...

    javascript_lessons-源码.rar

    JavaScript代码通常嵌入到HTML文档中,由浏览器解释执行,但随着Node.js的出现,它也能够用于服务器端开发。 JavaScript_lessons-源码.zip文件很可能包含了多个JavaScript学习示例、练习或项目,这对于初学者和进阶...

    javascript网页开发-张孝祥_lesson3

    学习如何创建对象、继承和封装是提升代码复用性和可维护性的关键。 9. **ES6新特性**:ECMAScript 6(也称ES2015)引入了许多新特性,如let和const、解构赋值、箭头函数、类和模块等,这些都极大地提升了JavaScript...

    JavaScript代码复用模式实例分析

    JavaScript代码复用是提高开发效率和维护软件质量的重要手段,在日常的前端开发中,开发者经常需要利用已有的代码段来实现新的功能,而不是每次都从头开始编写。代码复用能够减少重复代码的编写,降低出错的几率,...

    JavaScript继承

    继承的主要目的是代码复用和降低耦合度。通过继承,可以在已有类的基础上扩展功能,而不是从零开始编写代码。当需要修改共享的方法时,只需要在一个地方进行,提高了代码维护性。例如,如果多个类都需要`toString`...

    JavaScript面向对象-动力节点共7页.pdf.z

    一个对象可以继承另一个对象的属性和方法,从而实现代码复用。有多种继承方式,包括经典继承(使用`new`和`prototype`)、原型式继承(`Object.create`)、寄生式继承、寄生组合式继承等。例如,使用`prototype`实现...

Global site tag (gtag.js) - Google Analytics