JS对象继承篇
JS对象继承篇
ECMAScript只支持实现继承,而且其实现继承主要是依靠原型链来实现的
原型链
其基本思路是利用原型让一个引用类型继承另一个引用类型的属性和方法
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.在创建子类型的实例时,不能向其父类型的构造函数传递参数。所以综上问题,实践中很少单独使用原型链
借用构造函数
其基本思路是在子类型构造函数的内部调用父类型的构造函数
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属性的副本
借用构造函数存在的问题:方法函数无法复用,实践上也很少单独使用
组合继承
其基本思路是使用原型链实现对原型属性和方法的继承,而通过借用构造函数来实现对实例属性的继承
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
这样,所有的实例都能拥有自己的属性,并且可以使用相同的方法
组合继承避免了原型链和借用构造函数的缺陷,结合了两个的优点,是最常用的继承方式,但是无论什么情况下都会调用两次父类型的构造函数
原型式继承
其基本思路是借助原型可以基于已有的对象创建新的对象
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"]
存在和原型模式一样的问题,包含引用类型属性都会被共享
寄生式继承
其基本思路是类似创建对象时的工厂模式,将继承过程封装在一个函数里,然后返回一个对象
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~
寄生式继承存在的问题:方法函数无法复用.适用于不考虑自定义类型和构造函数的情况下
寄生组合式继承
其基本思路是通过借用构造函数来继承属性,通过原型链的混成形式来继承方法,就是为了不必为了子类型的原型去调用父类型的构造函数
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对象继承篇的更多相关文章
- JS对象继承与原型链
1.以复制方式实现的继承 1.1浅拷贝 基本类型的复制 var parent = { lanage: "chinese" } var child = { name: "x ...
- Js对象继承小结
1.继承 对象的定义好用一些的一般是把实例对象的属性定义在类里面,通过this指针指向具体实例属性.定义对象的public方法时将其绑定到prototype中.子类在继承父类时可以通过对象冒充来继承父 ...
- js对象继承的问题
js继承方法有多种: 1.利用call()和apply()的方法. call()里面接受多个参数:apply()只能接受两个参数. call()第一个参数是本身,后面都是他的属性和方法. apply( ...
- js对象继承
方法: 1.原型链继承 2.使用对象冒充继承
- JS中对象继承方式
JS对象继承方式 摘自<JavaScript的对象继承方式,有几种写法>,作者:peakedness 链接:https://my.oschina.net/u/3970421/blog/28 ...
- Javascript高级编程学习笔记(22)—— 对象继承
继承是所有面向对象的语言最让人津津乐道的概念 许多面向对象的语言都支持两种实现继承的方式: 1.接口继承 2.实现继承 由于ECMAScript中没有函数签名,所以自然也是不支持接口继承 所以JS中能 ...
- js的继承实现方式
1. 使用call或者apply来实现js对象继承 function Animal(age){ this.age = age; this.say = function(){ console.log(' ...
- js 对象深复制,创建对象和继承
js 对象深复制,创建对象和继承.主要参考高级编程第三版,总结网上部分资料和自己的代码测试心得.每走一小步,就做一个小结. 1.对象/数组深复制 一般的=号传递的都是对象/数组的引用,如在控制台输入 ...
- js对象的几种创建方式和js实现继承的方式[转]
一.js对象的创建方式 1. 使用Object构造函数来创建一个对象,下面代码创建了一个person对象,并用两种方式打印出了Name的属性值. var person = new Object(); ...
随机推荐
- 【疯狂造轮子-iOS】JSON转Model系列之二
[疯狂造轮子-iOS]JSON转Model系列之二 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 上一篇<[疯狂造轮子-iOS]JSON转Model系列之一> ...
- 异步任务队列Celery在Django中的使用
前段时间在Django Web平台开发中,碰到一些请求执行的任务时间较长(几分钟),为了加快用户的响应时间,因此决定采用异步任务的方式在后台执行这些任务.在同事的指引下接触了Celery这个异步任务队 ...
- HTML中上传与读取图片或文件(input file)----在路上(25)
input file相关知识简例 在此介绍的input file相关知识为: 上传照片及文件,其中包括单次上传.批量上传.删除照片.增加照片.读取图片.对上传的图片或文件的判断,比如限制图片的张数.限 ...
- 如何快速优化手游性能问题?从UGUI优化说起
WeTest 导读 本文作者从自身多年的Unity项目UI开发及优化的经验出发,从UGUI,CPU,GPU以及unity特有资源等几个维度,介绍了unity手游性能优化的一些方法. 在之前的文 ...
- PHP的学习--RSA加密解密
PHP服务端与客户端交互或者提供开放API时,通常需要对敏感的数据进行加密,这时候rsa非对称加密就能派上用处了. 举个通俗易懂的例子,假设我们再登录一个网站,发送账号和密码,请求被拦截了. 密码没加 ...
- 谈谈JS的观察者模式(自定义事件)
呼呼...前不久参加了一个笔试,里面有一到JS编程题,当时看着题目就蒙圈...后来研究了一下,原来就是所谓的观察者模式.就记下来...^_^ 题目 [附加题] 请实现下面的自定义事件 Event 对象 ...
- 简单酷炫的canvas动画
作为一个新人怀着激动而紧张的心情写了第一篇帖子还请大家多多支持,小弟在次拜谢. 驯鹿拉圣诞老人动画效果图如下 html如下: <div style="width:400px;heigh ...
- 如何dos命令打开服务窗口?
1.输入services.msc点击<确定>进入服务窗口.如图:
- Mysql - 增删改
因为项目原因, mysql用了两年了, 但是一直都未曾去总结过. 最近也是领导让总结项目, 才想起把mysql的使用小结一下. 一. Create 1. 单条插入, sql格式: insert int ...
- T-SQL学习记录
T-sql是对SQL(structure query language )的升级.可以加函数. 系统数据库:master管理数据库.model模版数据库,msdb备份等操作需要用到的数据库,tempd ...