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. .NET Core系列 :4 测试

    2016.6.27 微软已经正式发布了.NET Core 1.0 RTM,但是工具链还是预览版,同样的大量的开源测试库也都是至少发布了Alpha测试版支持.NET Core, 这篇文章 The Sta ...

  2. Partition:Partiton Scheme是否指定Next Used?

    在SQL Server中,为Partition Scheme多次指定Next Used,不会出错,最后一次指定的FileGroup是Partition Scheme的Next Used,建议,在执行P ...

  3. JS与APP原生控件交互

    "热更新"."热部署"相信对于混合式开发的童鞋一定不陌生,那么APP怎么避免每次升级都要在APP应用商店发布呢?这里就用到了混合式开发的概念,对于电商网站尤其显 ...

  4. JavaScript实现常用的排序算法

    ▓▓▓▓▓▓ 大致介绍 由于最近要考试复习,所以学习js的时间少了 -_-||,考试完还会继续的努力学习,这次用原生的JavaScript实现以前学习的常用的排序算法,有冒泡排序.快速排序.直接插入排 ...

  5. [.NET] 打造一个很简单的文档转换器 - 使用组件 Spire.Office

    打造一个很简单的文档转换器 - 使用组件 Spire.Office [博主]反骨仔 [原文]http://www.cnblogs.com/liqingwen/p/6024827.html 序 之前,& ...

  6. 创建APPID&&部署服务端教程

    创建APPID&&部署服务端 一.创建APPID 1.打开https://console.developers.google.com ,左击顶部Project,然后左击创建项目 2.输 ...

  7. 深入理解CSS六种颜色模式

    前面的话 赏心悦目的颜色搭配让人感到舒服,修改元素颜色的功能让人趋之若鹜.但颜色规划不当,会让网站用户无所适从.颜色从<font color="">发展至今,保留了很多 ...

  8. unity 3d 解析 json

    官网案例传送门 我这里不过是借花献佛,案例官网就有. using UnityEngine; using System.Collections; public class json : MonoBeha ...

  9. Java中常用集合操作

    一.Map 名值对存储的. 常用派生类HashMap类 添加: put(key,value)往集合里添加数据 删除: clear()删除所有 remove(key)清除单个,根据k来找 获取: siz ...

  10. 总结30个CSS3选择器

    或许大家平时总是在用的选择器都是:#id  .class  以及标签选择器.可是这些还远远不够,为了在开发中更加得心应手,本文总结了30个CSS3选择器,希望对大家有所帮助. 1 *:通用选择器 ;; ...