JS对象继承篇

ECMAScript只支持实现继承,而且其实现继承主要是依靠原型链来实现的

  1. 原型链

其基本思路是利用原型让一个引用类型继承另一个引用类型的属性和方法

function Person(){
this.name = "Person";
}
Person.prototype.getName = function(){
return this.name;
};
function SuperPerson(name,sex){
this.name = name;
this.sex = sex;
}
SuperPerson.prototype = new Person();//重写原型 //在添加新方法或重写原型中的方法时,一定要在重写原型的语句后面,而且不能使用字面量添加新方法,不然又会再一次重写原型,原型链被切断
SuperPerson.prototype.getSex = function(){
return this.sex;
};
var Tom = new SuperPerson("Tom","man");
console.log(Tom.getName());//Tom
console.log(Tom.getSex());//man

在上述代码中,先定义了一个Person类型,其中有一个属性和定义在其原型对象上的一个方法,接着定义了一个SuperPerson类型,其中有两个属性,然后重写了它的原型对象,将Person的实例赋值给SuperPerson的原型。然后又在新的原型对象上添加了一个方法。

当然别忘记了默认的原型,因为所有引用类型默认都继承了Object

console.log(Tom instanceof Object);//true
console.log(Tom instanceof Person);//true
console.log(Tom instanceof SuperPerson);//true

原型链存在的问题:1.包含引用类型的原型属性被所有的实例所共享,我们在继承的时候,原先的实例属性就顺理成章的变成了现在的原型属性,那么后来的其中一个实例中修改值,其他实例都会反映出来 2.在创建子类型的实例时,不能向其父类型的构造函数传递参数。所以综上问题,实践中很少单独使用原型链

  1. 借用构造函数

其基本思路是在子类型构造函数的内部调用父类型的构造函数

function Person(name){
this.name = name;
this.friends = ["Jack","John","Kim"];
}
function SuperPerson(name,sex){
//继承Person
Person.call(this,name);//call()将Person的运行作用域绑定到了SuperPerson上
//如果要屏蔽父类型中的属性,要在继承语句之后添加
//实例属性
this.sex = sex;
}
var Tom = new SuperPerson("Tom","man");
Tom.friends.push("Amy");
console.log(Tom.friends);// ["Jack", "John", "Kim", "Amy"]
var David = new SuperPerson("David","man");
console.log(David.friends);//["Jack", "John", "Kim"]
console.log(David.name);//David

通过调用call()方法(apply()方法也可以),实际上是在将来要新创建SuperPerson的实例上调用了Person构造函数,这样就会在新SuperPerson对象上执行Person构造函数中定义的所有对象初始化代码,结果SuperPerson的每个实例都会具有自己的friends属性的副本
借用构造函数存在的问题:方法函数无法复用,实践上也很少单独使用

  1. 组合继承

其基本思路是使用原型链实现对原型属性和方法的继承,而通过借用构造函数来实现对实例属性的继承

function Person(name){
this.name = name;
this.friends = ["Jack","John","Kim"];
}
Person.prototype.getName = function(){
console.log(this.name);
}
function SuperPerson(name,sex){
//继承Person
Person.call(this,name);/*第二次调用父类型的构造函数,在实例上又创建了一次属性name和frieds,屏蔽第一次调用时创建的*/
//实例属性
this.sex = sex;
}
SuperPerson.prototype = new Person();//重写原型,第一次调用父类型的构造函数
SuperPerson.prototype.constructor = SuperPerson;
//添加新方法
SuperPerson.prototype.getSex = function(){
console.log(this.sex);
};
var Tom = new SuperPerson("Tom","man");
Tom.friends.push("Amy");
console.log(Tom.friends);// ["Jack", "John", "Kim", "Amy"]
Tom.getName();// Tom
Tom.getSex();// man var David = new SuperPerson("David","man");
console.log(David.friends);// ["Jack", "John", "Kim"]
David.getName();// David
David.getSex();// man

这样,所有的实例都能拥有自己的属性,并且可以使用相同的方法
组合继承避免了原型链和借用构造函数的缺陷,结合了两个的优点,是最常用的继承方式,但是无论什么情况下都会调用两次父类型的构造函数

  1. 原型式继承

其基本思路是借助原型可以基于已有的对象创建新的对象

function object(o){
function F(){}
F.prototype = o;
return new F();
}

object()对传入的对象执行了一次浅复制

var person = {
name: "Tom",
friends: ["Jack", "John", "Kim"]
};
var David = object(person);
David.name = "David";
David.friends.push("Amy");
console.log(David.friends);// ["Jack", "John", "Kim", "Amy"]
var Rob = object(person);
Rob.name = "Rob";
console.log(Rob.friends);// ["Jack", "John", "Kim", "Amy"]


这意味着person.friends会被其他对象共享
ECMAScript5新增的Object.create()规范化了原型式继承,这个方法接受两个参数:一个用于新对象原型的对象和(可选)一个为新对象定义额外属性的对象,在传入一个参数时跟object()方法行为相同

var person = {
name: "Tom",
friends: ["Jack", "John", "Kim"]
};
var David = Object.create(person);
/*
使用两个参数:
var David = Object.create(person,{
name: {
value:"David"
});
*/
David.name = "David";
David.friends.push("Amy");
console.log(David.friends);//["Jack", "John", "Kim", "Amy"]
var Rob = Object.create(person);
Rob.name = "Rob";
console.log(Rob.friends);// ["Jack", "John", "Kim", "Amy"]

存在和原型模式一样的问题,包含引用类型属性都会被共享

  1. 寄生式继承

其基本思路是类似创建对象时的工厂模式,将继承过程封装在一个函数里,然后返回一个对象

function createObject(o){
var clone = Object.create(o);
clone.sayHi = function(){
console.log("Hi~");
};
return clone;
}
var person = {
name: "Tom",
friends: ["Jack", "John", "Kim"]
};
var David = createObject(person);
David.sayHi();//Hi~

寄生式继承存在的问题:方法函数无法复用.适用于不考虑自定义类型和构造函数的情况下

  1. 寄生组合式继承

其基本思路是通过借用构造函数来继承属性,通过原型链的混成形式来继承方法,就是为了不必为了子类型的原型去调用父类型的构造函数

function inheritPrototype(superPerson,person)
{
var prototype=Object.create(person.prototype);
prototype.construtor = superPerson;
superPerson.prototype = prototype;
}
function Person(name)
{
this.name = name;
this.frieds = ["Jack", "John", "Kim"];
}
Person.prototype.getName = function(){
console.log(this.name);
};
function SuperPerson(name,sex){
Person.call(this,name);
this.sex = sex;
}
inheritPrototype(SuperPerson,Person);
SuperPerson.prototype.getSex = function(){
console.log(this.sex);
};
var Tom=new SuperPerson("Tom","man");
Tom.getName();//Tom

这个的高效率体现在它值调用了一次Person构造函数,避免了创建不必要的属性,开发人员普遍认为寄生组合继承是引用类型最理想的继承范式

参考书籍《Javascript高级程序设计》

JS对象继承篇的更多相关文章

  1. JS对象继承与原型链

    1.以复制方式实现的继承 1.1浅拷贝 基本类型的复制 var parent = { lanage: "chinese" } var child = { name: "x ...

  2. Js对象继承小结

    1.继承 对象的定义好用一些的一般是把实例对象的属性定义在类里面,通过this指针指向具体实例属性.定义对象的public方法时将其绑定到prototype中.子类在继承父类时可以通过对象冒充来继承父 ...

  3. js对象继承的问题

    js继承方法有多种: 1.利用call()和apply()的方法. call()里面接受多个参数:apply()只能接受两个参数. call()第一个参数是本身,后面都是他的属性和方法. apply( ...

  4. js对象继承

    方法: 1.原型链继承 2.使用对象冒充继承

  5. JS中对象继承方式

    JS对象继承方式 摘自<JavaScript的对象继承方式,有几种写法>,作者:peakedness 链接:https://my.oschina.net/u/3970421/blog/28 ...

  6. Javascript高级编程学习笔记(22)—— 对象继承

    继承是所有面向对象的语言最让人津津乐道的概念 许多面向对象的语言都支持两种实现继承的方式: 1.接口继承 2.实现继承 由于ECMAScript中没有函数签名,所以自然也是不支持接口继承 所以JS中能 ...

  7. js的继承实现方式

    1. 使用call或者apply来实现js对象继承 function Animal(age){ this.age = age; this.say = function(){ console.log(' ...

  8. js 对象深复制,创建对象和继承

    js 对象深复制,创建对象和继承.主要参考高级编程第三版,总结网上部分资料和自己的代码测试心得.每走一小步,就做一个小结. 1.对象/数组深复制 一般的=号传递的都是对象/数组的引用,如在控制台输入 ...

  9. js对象的几种创建方式和js实现继承的方式[转]

    一.js对象的创建方式 1. 使用Object构造函数来创建一个对象,下面代码创建了一个person对象,并用两种方式打印出了Name的属性值. var person = new Object(); ...

随机推荐

  1. RestTemplate发送请求并携带header信息

    1.使用restTemplate的postForObject方法 注:目前没有发现发送携带header信息的getForObject方法. HttpHeaders headers = new Http ...

  2. FFmpeg + SoundTouch实现音频的变调变速

    本文使用FFmpeg + SoundTouch实现将音频解码后,进行变调变速处理,并将处理后的结果保存为WAV文件. 主要有以下内容: 实现一个FFmpeg的工具类,保存多媒体文件所需的解码信息 将解 ...

  3. [EasyUI美化换肤]更换EasyUi图标

    前言 本篇文章主要是记录一些换EasyUI皮肤的过程,备忘.也欢迎美工大神各路UI给点好意见,EasyUI我就不介绍了,自行百度吧..(So..所以别问我是不是响应式..本身EasyUI就不是响应式. ...

  4. Java类访问权限修饰符

    一.概要 通过了解Java4种修饰符访问权限,能够进一步完善程序类,合理规划权限的范围,这样才能减少漏洞.提高安全性.具备表达力便于使用. 二.权限表 修饰符 同一个类 同一个包 不同包的子类 不同包 ...

  5. 太多选择——企业如何选择合适的BI工具?

    在没认清现状前,企业当然不能一言不合就上BI. BI不同于一般的企业管理软件,不能简单归类为类似用于提高管理的ERP和WMS,或用于提高企业效率的OA.BPM.BI的本质应该是通过展现数据,用于加强企 ...

  6. Linux 利用Google Authenticator实现ssh登录双因素认证

    1.介绍 双因素认证:双因素身份认证就是通过你所知道再加上你所能拥有的这二个要素组合到一起才能发挥作用的身份认证系统.双因素认证是一种采用时间同步技术的系统,采用了基于时间.事件和密钥三变量而产生的一 ...

  7. 烂泥:数据库管理之phpmyadmin免密码配置

    本文由ilanniweb提供友情赞助,首发于烂泥行天下 想要获得更多的文章,可以关注我的微信ilanniweb 其实这篇文章很早就想写了,但是一直没有时间.刚好今天下午稍微空了点,就把这篇文章整理出来 ...

  8. Spring MVC入门

    1.什么是SpringMvc Spring MVC属于SpringFrameWork的后续产品,已经融合在Spring Web Flow里面.Spring 框架提供了构建 Web 应用程序的全功能 M ...

  9. .NET Core性能测试组件BenchmarkDotNet 支持.NET Framework Mono

    .NET Core 超强性能测试组件BenchmarkDotNet 支持Full .NET Framework, .NET Core (RTM), Mono. BenchmarkDotNet支持 C# ...

  10. 我对BFC的理解

    最初这篇文章打算回答寒冬大神的第一问,谈谈CSS布局.本来呢我以为布局主要涉及float跟display相关属性,以及他们的包含框.静态位置等等.后来看了大神的一片面试文章,嗯?这里怎么还有个BFC, ...