菜鸟快飞之JavaScript对象、原型、继承(三)
正文之前需要声明的一点是,菜鸟系列博文全是基于ES5的,不考虑ES6甚至更高版本。
继承
由于我个人不是学计算机的,所以对于很多东西只是知其然,不知其所以然。就像这个继承,刚开始学JavaScript就听人说了JavaScript几大核心,但是自己平时似乎都没怎么用到,所以一直不明白为什么需要这些东西,面试还总是问这些。
但是随着一点点学习,也有去看过jQuery源码,虽然到现在也没怎么看懂(主要也是有些懒),但慢慢还是对这些东西有了更深的了解。
为什么需要继承
举个很简单的例子,我在平时学习写一些页面的时候,里面的代码很少,而且更多还是用jQuery去写的,若非是专门为了练习JavaScript,否则根本用都用不上。
但是这只是一些很小的东西,如果你需要写一个jQuery这样的库呢,angular这样的框架呢,那么你必然会需要大量的优化你的代码,让能够写一次就解决的东西尽量不要再写第二次,否则几千行能写完的东西,你可能需要写上万行才行了。
这个时候继承就是一个很好的解决方法,让一个子类能够拥有父类的属性和方法,同时子类也能拥有自己的属性和方法。
所以什么是继承,就是让一个子类拥有父类的属性和方法,自己不用再去重复写一次。
原型链
JavaScript和其他语言不同,没有类,也就是class,所以不能用常规的方式实现继承。但作为一门面向对象的语言,JavaScript有其独特的实现方式——原型链。
之前说过,每个函数都有一个原型对象prototype,每个实例都有一个指向原型对象的内部指针__proto__。
function Fun(){}
var fun1 = new Fun();
fun1.__proto__ ----> Fun.prototype.__proto__ ----> Object.prototype.__proto__ ----> null
让一个类型的原型对象等于另一个类型的实例:
function Fun() {
}
function Sub() {
}
Sub.prototype = new Fun();
Sub.prototype.__proto__ === Fun.prototype; // true
var sub1 = new Sub();
sub1.__proto__ ----> Sub.prototype.__proto__ ----> Fun.prototype.__proto__ ----> Object.prototype.__proto__ ----> null
这样就形成了一条原型链,通过原型链,我们便可以实现继承,让子类拥有父类的属性和方法了。
function Fun() {
this.name = 'Mike';
this.age = 10;
this.sayHello = function() {
console.log('Hello! 我叫' + this.name + '今年' + this.age + '岁');
};
this.nums = [1,2,3,4];
}
function Sub() {
}
Sub.prototype = new Fun();
var sub1 = new Sub();
sub1.sayHello(); // Hello! 我叫Mike今年10岁
sub1.name = 'Jarry';
sub1.sayHello(); // Hello! 我叫Jarry今年10岁
var sub2 = new Sub();
sub2.sayHello(); //Hello! 我叫Mike今年10岁
sub2.nums; // [1,2,3,4]
sub1.nums.push(6,7);
sub2.nums; // [1,2,3,4,6,7]
但是单独使用原型链来继承会存在问题,就像上面的代码一样。
我们知道,通过原型链的方式,父类的方法和属性都是在子类的原型链上,原型链上的方法和属性是会被实例共享的,所以当一个引用类型的值被一个实例改变后,另外一个实例再次调用的时候,其值也会发生改变。而且还有个问题就是参数传递不方便。
组合继承
为了解决上面的问题,我们在原型链的基础上加上一些其他东西,call()或者apply().
function Fun(name,age) {
this.name = name;
this.age = age;
this.sayHello = function() {
console.log('Hello! 我叫' + this.name + '今年' + this.age + '岁');
};
this.nums = [1,2,3,4];
}
function Sub(name,age) {
Fun.apply(this,arguments);
}
Sub.prototype = new Fun();
var sub1 = new Sub('小红',10);
sub1.sayHello();
var sub2 = new Sub('小明',20);
sub2.sayHello();
sub1.nums.push(6,7);
sub1.nums; // [1,2,3,4,6,7]
sub2.nums; // [1,2,3,4]
这样问题就解决了,这个模式也是现在使用最多的模式,当然还有一些其他的,比如原型式继承,寄生式继承,各有优点,不过并不是很常见罢了。
对象的扩展
有时对于一些不是很复杂的项目,为了简单方便,我们可能会直接对通过字面量创建的对象进行扩展,只将公共的部分抽出来,比如:
// 公共部分
var commonObj = {
identity: 'student',
color: ['red','blue']
}; // 对象a
var a = Object.create(commonObj )
a.name = 'Mike'; // 对象b
var b = Object.create(commonObj )
b.name = 'Tom'; // 使用
b.identity // 'student'
b.color // ["red", "blue"] a.color.push('black') //
a.identity = 'teacher' b.identity // 'student'
b.color // ["red", "blue", "black"]
我们可以通过ES5的新方法Object.create(),来规范原型继承,不过通过上面的代码会发现一个问题,就是当公共的部分是直接通过字面量的方式创建的对象时,里面的引用类型的值会被不同的继承者给改变,因为Object.create()只是潜复制而已。
所以我们将公共部分换成函数,用构造函数来创建对象,然后使用new关键字,这样就能创建不同的实例了,不同的继承者之间就不会再相互影响:
// 公共部分
var commonObj = function () {
this.identity = 'student';
this.color = ['red','blue'];
}; // 对象a
var a = Object.create(new commonObj() )
a.name = 'Mike'; // 对象b
var b = Object.create(new commonObj() )
b.name = 'Tom'; // 使用
b.identity // 'student'
b.color // ["red", "blue"] a.color.push('black') //
a.identity = 'teacher' b.identity // 'student'
b.color // ["red", "blue"]
这样就好了,但是这样继承者的属性和方法只能一个一个的添加,还是有些麻烦,所以再改改,使用apply():
// 公共部分
var commonObj = function () {
this.identity = 'student';
this.color = ['red','blue'];
}; // 对象a
var a = {
name: 'Mike'
}
commonObj.apply(a) // 对象b
var b = {
name: 'Tom'
}
commonObj.apply(b)
// 使用
b.identity // 'student'
b.color // ["red", "blue"] a.color.push('black') //
a.identity = 'teacher' // 'teacher' b.identity // 'student'
b.color // ["red", "blue"]
这样,a对象和b对象都可以直接把属性和方法直接写在{}里了。
菜鸟快飞之JavaScript对象、原型、继承(三)的更多相关文章
- 菜鸟快飞之JavaScript对象、原型、继承(一)
有前辈说过,在JavaScript中,一切皆对象.由此可见,作为JavaScript的核心之一,对象是有多么重要.虽然今天走亲戚有点累,但还是得写写这个对象,免得吃几天好的,就又忘光了. 1.创建对象 ...
- 菜鸟快飞之JavaScript对象、原型、继承(二)
上一节写了创建对象的三种方法,而其中通过函数创建对象的方式又有三种模式,分别是工厂模式.构造函数模式.原型模式.而这三种模式最常用的则是原型模式.还是上栗子: 工厂模式: function Fun1( ...
- 菜鸟快飞之JavaScript函数
1.复制变量值 在说函数前,我觉得需要先说说关于变量值的复制,以便后面的理解. 复制基本类型的值: 当一个变量复制另外一个值为基本类型的变量时,两个变量可以参与任何操作而不会互相影响 var num1 ...
- #JavaScript对象与继承
JavaScript对象与继承 JavaScript是我在C语言之后接触的第二门编程语言,大一暑假的时候在图书馆找了一本中国人写的JavaScript程序设计来看.那个时候在编程方面几乎还是小白,再加 ...
- JavaScript的原型继承
JavaScript是一门面向对象的语言.在JavaScript中有一句很经典的话,万物皆对象.既然是面向对象的,那就有面向对象的三大特征:封装.继承.多态.这里讲的是JavaScript的继承,其他 ...
- JavaScript大杂烩4 - 理解JavaScript对象的继承机制
JavaScript是单根的完全面向对象的语言 JavaScript是单根的面向对象语言,它只有单一的根Object,所有的其他对象都是直接或者间接的从Object对象继承.而在JavaScript的 ...
- 关于js的对象原型继承(一)
javascript中,对象的继承是通过原型去继承. 可以这样理解:js中的对象,包含的除了属性和方法,还有一个最基本的原型__proto__对象.这个原型__proto__指向谁,这个对象就继承谁. ...
- JavaScript对象的继承
原文 简书原文:https://www.jianshu.com/p/78ce11762f39 大纲 前言 1.原型链继承 2.借用构造函数实现继承 3.组合模式继承 4.原型式继承 5.寄生式继承 6 ...
- JavaScript对象原型
一.MDN上的解释(有点抽象) 基于原型的语言? JavaScript 常被描述为一种基于原型的语言 (prototype-based language)——每个对象拥有一个原型对象,对象以其原型为模 ...
随机推荐
- android Notification介绍
如果要添加一个Notification,可以按照以下几个步骤 1:获取NotificationManager: NotificationManager m_NotificationManager=(N ...
- 图解Spark API
初识spark,需要对其API有熟悉的了解才能方便开发上层应用.本文用图形的方式直观表达相关API的工作特点,并提供了解新的API接口使用的方法.例子代码全部使用python实现. 1. 数据源准备 ...
- ORACLE分区表梳理系列(二)- 分区表日常维护及注意事项(红字需要留意)
版权声明:本文发布于http://www.cnblogs.com/yumiko/,版权由Yumiko_sunny所有,欢迎转载.转载时,请在文章明显位置注明原文链接.若在未经作者同意的情况下,将本文内 ...
- ASP.NET Core Loves JavaScript
前言 在 ASP.NET 团队的 Github 的主页上,有这样一个开源项目叫:"JavaScriptsServices",那么 什么是 JavaScriptsServices 呢 ...
- Nodejs之MEAN栈开发(八)---- 用户认证与会话管理详解
用户认证与会话管理基本上是每个网站必备的一个功能.在Asp.net下做的比较多,大体的思路都是先根据用户提供的用户名和密码到数据库找到用户信息,然后校验,校验成功之后记住用户的姓名和相关信息,这个信息 ...
- Web API 强势入门指南
Web API是一个比较宽泛的概念.这里我们提到Web API特指ASP.NET Web API. 这篇文章中我们主要介绍Web API的主要功能以及与其他同类型框架的对比,最后通过一些相对复杂的实例 ...
- [翻译]AKKA笔记 - ACTOR生命周期 - 基本 -5
原文地址:http://rerun.me/2014/10/21/akka-notes-actor-lifecycle-basic/ (请注意这了讨论的生命周期并不包括 preRestart 或者pos ...
- Spring学习记录(十二)---AOP理解和基于注解配置
Spring核心之二:AOP(Aspect Oriented Programming) --- 面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术.AOP是OOP的延续,是软 ...
- redis数据结构详解之Hash(四)
序言 Hash数据结构累似c#中的dictionary,大家对数组应该比较了解,数组是通过索引快速定位到指定元素的,无论是访问数组的第一个元素还是最后一个元素,所耗费的时间都是一样的,但是数组中的索引 ...
- Happy New Year 2016
大学之前的时间都是按天来过的,期盼着一天一天地快快长大,期盼着过年穿新衣,阖家团聚,其乐融融: 大学的时间都是按周来过的,根据每周的课表周而复始,虽然单调但也是自由自在,简单充实: 刚工作的几年时间是 ...