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(); ...
随机推荐
- Java多线程基础学习(二)
9. 线程安全/共享变量——同步 当多个线程用到同一个变量时,在修改值时存在同时修改的可能性,而此时该变量只能被赋值一次.这就会导致出现“线程安全”问题,这个被多个线程共用的变量称之为“共享变量”. ...
- ExtJS 4.2 Grid组件的单元格合并
ExtJS 4.2 Grid组件本身并没有提供单元格合并功能,需要自己实现这个功能. 目录 1. 原理 2. 多列合并 3. 代码与在线演示 1. 原理 1.1 HTML代码分析 首先创建一个Grid ...
- JavaScript基础知识总结(二)
JavaScript语法 二.数据类型 程序把这些量.值分为几大类,每一类分别叫什么名称,有什么特点,就叫数据类型. 1.字符串(string) 字符串由零个或多个字符构成,字符包括字母,数字,标点符 ...
- __Block与__Weak区别
一.__block理解: Blocks可以访问局部变量,但是不能修改, 声明block的时候实际上是把当时的临时变量又复制了一份, 在block里即使修改了这些复制的变量,也不影响外面的原始变量.即所 ...
- oracle常用函数及示例
学习oracle也有一段时间了,发现oracle中的函数好多,对于做后台的程序猿来说,大把大把的时间还要学习很多其他的新东西,再把这些函数也都记住是不太现实的,所以总结了一下oracle中的一些常用函 ...
- git常用命令(持续更新中)
git常用命令(持续更新中) 本地仓库操作git int 初始化本地仓库git add . ...
- Android快乐贪吃蛇游戏实战项目开发教程-01项目概述与目录
一.项目简介 贪吃蛇是一个很经典的游戏,也很适合用来学习.本教程将和大家一起做一个Android版的贪吃蛇游戏. 我已经将做好的案例上传到了应用宝,无病毒.无广告,大家可以放心下载下来把玩一下.应用宝 ...
- excel常用技巧
复制表格时,如果要加上行标和列标.页面布局->工作表选项:标题,勾上打印->复制下拉框->复制为图片加上打印样式 一行长拆成几行短或几行短变成一行长的文本拆分,可以通过:填充-> ...
- Harmonic Number(调和级数+欧拉常数)
题意:求f(n)=1/1+1/2+1/3+1/4-1/n (1 ≤ n ≤ 108).,精确到10-8 (原题在文末) 知识点: 调和级数(即f(n))至今没有一个完全正确的公式, ...
- linux常用命令(2)pwd命令
pwd 命令1 命令格式:pwd [选项]2 命令功能查看当前工作目录的完整路径3 常用参数一般不带任何参数如果目录是链接时:pwd -P 显示实际路径,而非使用链接路径4 常用实例:4.1 用pwd ...