JavaScript面向对象继承原理与实现方法分析


Posted in Javascript onAugust 09, 2018

本文实例讲述了JavaScript面向对象继承原理与实现方法。分享给大家供大家参考,具体如下:

1、构造函数、原型和实例的关系

构造函数有一个原型属性prototype指向一个原型对象。

原型对象包含一个指向构造函数的指针constructor

实例包含一个指向原型对象的内部指针[[prototype]]

2、通过原型链实现继承

基本思想:利用原型让一个引用类型继承另一个引用类型的属性和方法,子类型可以访问超类型的所有属性和方法。原型链的构建是将一个类型的实例赋值给另一个构造函数的原型实现的。实现的本质是重写原型对象,代之以一个新类型的实例。

function Person(name) {
  this.name = name;
}
Person.prototype.sayHello = function() {
  alert("Hello, " + this.name);
}
var person = new Person("Alice");
person.sayHello(); // Hello, Alice
function Student() {
}
Student.prototype = new Person("Bruce");
Student.prototype.id = 16;
Student.prototype.showId = function() {
  alert(this.id);
}
var student = new Student();
student.sayHello(); // Hello, Bruce
student.showId(); // 16

注意:不能用对象字面量创建原型方法,这样会重写原型链,导致继承无效。

function Person(name) {
  this.name = name;
}
Person.prototype.sayHello = function() {
  alert("Hello, " + this.name);
}
var person = new Person("Alice");
person.sayHello(); // Hello, Alice
function Student() {
}
Student.prototype = new Person("Bruce");
Student.prototype.id = 16;
Student.prototype = {
  showId: function() {
    alert(this.id);
  }
};
var student = new Student();
student.sayHello(); // 报错:student.sayHello is not a function
student.showId(); // 16

student指向Student的原型,Student的原型又指向Person的原型。

student.sayHello()原型链搜索机制:

1)搜索student实例中是否有sayHello()

2)搜索Student.prototype是否有sayHello()

3)搜索Person.prototype是否有sayHello()

子类型有时候需要覆盖超类型的某个方法,或者需要添加超类型中不存在的某个方法。

function Person(name) {
  this.name = name;
}
Person.prototype.sayHello = function() {
  alert("Hello, " + this.name);
}
var person = new Person("Alice");
person.sayHello(); // Hello, Alice
function Student() {
}
Student.prototype = new Person("Bruce");
Student.prototype.id = 16;
Student.prototype.showId = function() {
alert(this.id);
}
Student.prototype.sayHello = function() {
  alert("Hi, " + this.name);
}
var student = new Student();
student.sayHello(); //Hi, Bruce
student.showId(); // 16

注意:给原型覆盖或添加方法的代码一定要放在替换原型的语句之后。

function Person(name) {
  this.name = name;
}
Person.prototype.sayHello = function() {
  alert("Hello, " + this.name);
}
var person = new Person("Alice");
person.sayHello(); // Hello, Alice
function Student() {
}
Student.prototype.sayHello = function() {
  alert("Hi, " + this.name);
}
Student.prototype = new Person("Bruce");
Student.prototype.id = 16;
Student.prototype.showId = function() {
alert(this.id);
}
var student = new Student();
student.sayHello(); // Hello, Bruce
student.showId(); // 16

确定实例和原型的关系:

(1)instanceof

alert(student instanceof Object); // true
alert(student instanceof Student); // true
alert(student instanceof Person); // true

(2)isProtptypeOf

alert(Object.prototype.isPrototypeOf(student)); // true
alert(Student.prototype.isPrototypeOf(student)); // true
alert(Person.prototype.isPrototypeOf(student)); // true

(3)getPrototypeOf

Object.getPrototypeOf(student1) == Student.prototype

使用原型链实现继承的问题:

(1)引用类型的属性会被实例共享,原型实现继承时,原型会变成另外一个类型的实例,实例的属性则变成了现在的原型属性,从而被共享。

function Person(name, age) {
  this.friends = ["Cindy","David"];
}
function Student() {
}
Student.prototype = new Person();
var student1 = new Student();
student1.friends.push("Bruce");
alert(student1.friends); // "Cindy","David","Bruce"
var student2 = new Student();
alert(student1.friends); // "Cindy","David","Bruce"

(2)在创建子类型的实例时,不能向超类型的构造函数中传递参数,实际上,应该是没有办法在不影响所有对象实例的情况下,给超类型的构造函数传递参数。

实际中很少单独使用原型链实现继承。

3、通过构造函数实现继承

基本思想:在子类型构造函数的内部调用超类型构造函数。通过使用apply()call()方法也可以在新创建的对象上执行构造函数。

function Person(name, age) {
  this.name = name;
  this.age = age;
}
function Student() {
  Person.call(this,"Alice",22); // 继承了构造函数Person,同时还传递了参数
  this.id = 16; // 实例属性
}
var student = new Student();
alert(student.name); // "Alice"
alert(student.age); // 22
alert(student.id); // 16

使用构造函数实现继承的问题:

(1)在超类型的原型中定义的方法,对子类型而言是不可见的,结果所有类型都只能使用构造函数模式。

(2)要想子类能够访问超类定义的方法,方法只能在构造函数中定义,但方法在构造函数中定义时,函数复用无从谈起。

function Person(name, age) {
  this.name = name;
  this.age = age;
}
Person.prototype.showName = function() {
  alert(this.name);
};
function Student() {
  Person.call(this,"Alice",22);
  this.id = 16;
}
var student = new Student();
alert(student.showName()); // 报错:student.showName is not a function

实际中很少单独使用使用构造函数实现继承。

4、组合使用原型链和构造函数实现继承

思路:使用原型链继承共享的属性和方法,使用构造函数继承实例属性。

效果:既通过在原型上定义方法实现了函数复用,又能够保证每个实例都有自己的属性。

function Person(name, age) {
  this.name = name;
  this.age = age;
  this.friends = ["Cindy","David"];
}
Person.prototype.sayHello = function() {
  alert("Hello, " + this.name);
}
function Student(name, age, id) {
  Person.call(this, name, age);
  this.id = id;
}
Student.prototype = new Person();
Student.prototype.showId = function() {
  alert(this.id);
}
var student1 = new Student("Alice", 22, 16);
student1.friends.push("Emy");
alert(student1.friends); // "Cindy","David","Emy"
student1.sayHello(); // Hello, Alice
student1.showId(); // 16
var student2 = new Student("Bruce", 23, 17);
alert(student2.friends); // "Cindy","David"
student2.sayHello(); // Hello, Bruce
student2.showId(); // 17

希望本文所述对大家JavaScript程序设计有所帮助。

Javascript 相关文章推荐
!DOCTYPE声明对JavaScript的影响分析
Apr 12 Javascript
一个简单的jQuery插件制作 学习过程及实例
Apr 25 Javascript
基于jQuery的history历史记录插件
Dec 11 Javascript
ExtJs Excel导出并下载IIS服务器端遇到的问题
Sep 16 Javascript
JAVASCRIPT函数作用域和提前声明 分享
Aug 22 Javascript
Javascript与jQuery方法的隐藏与显示
Jan 19 Javascript
基于jquery实现的自动补全功能
Mar 12 Javascript
Backbone.js框架中Model与Collection的使用实例
May 07 Javascript
js改变css样式的三种方法推荐
Jun 28 Javascript
解决Jstree 选中父节点时被禁用的子节点也会选中的问题
Dec 27 Javascript
让Vue也可以使用Redux的方法
May 23 Javascript
JS原生带缩略图的图片切换效果
Oct 10 Javascript
vue使用ajax获取后台数据进行显示的示例
Aug 09 #Javascript
vue中Axios的封装与API接口的管理详解
Aug 09 #Javascript
JavaScript引用类型RegExp基本用法详解
Aug 09 #Javascript
基于bootstrap页面渲染的问题解决方法
Aug 09 #Javascript
Vue实现按钮旋转和移动位置的实例代码
Aug 09 #Javascript
解决vue数组中对象属性变化页面不渲染问题
Aug 09 #Javascript
JavaScript引用类型Function实例详解
Aug 09 #Javascript
You might like
PHP伪静态页面函数附使用方法
2008/06/20 PHP
PHP中文件上传的一个问题
2010/09/04 PHP
PHP速成大法
2015/01/30 PHP
CI框架中$this->load->library()用法分析
2016/05/18 PHP
php简单实现文件或图片强制下载的方法
2016/12/06 PHP
Laravel框架生命周期与原理分析
2018/06/12 PHP
Highslide.js是一款基于js实现的网页中图片展示插件
2020/03/30 Javascript
jquery的Theme和Theme Switcher使用小结
2010/09/08 Javascript
jQuery filter函数使用方法
2014/05/19 Javascript
jQuery实现点击表格单元格就可以编辑内容的方法【测试可用】
2016/08/01 Javascript
jQuery实现带遮罩层效果的blockUI弹出层示例【附demo源码下载】
2016/09/14 Javascript
nodejs个人博客开发第七步 后台登陆
2017/04/12 NodeJs
Angular客户端请求Rest服务跨域问题的解决方法
2017/09/19 Javascript
node+koa实现数据mock接口的方法
2017/09/20 Javascript
JS获取日期的方法实例【昨天,今天,明天,前n天,后n天的日期】
2017/09/28 Javascript
浅谈Node Inspector 代理实现
2017/10/19 Javascript
Python中类的继承代码实例
2014/10/28 Python
Python中使用Beautiful Soup库的超详细教程
2015/04/30 Python
Python全局变量与局部变量区别及用法分析
2018/09/03 Python
在python中使用requests 模拟浏览器发送请求数据的方法
2018/12/26 Python
Python删除n行后的其他行方法
2019/01/28 Python
如何使用python操作vmware
2019/07/27 Python
基于Python中isfile函数和isdir函数使用详解
2019/11/29 Python
春节到了 教你使用python来抢票回家
2020/01/06 Python
简单了解Python write writelines区别
2020/02/27 Python
解决Django提交表单报错:CSRF token missing or incorrect的问题
2020/03/13 Python
美国单身专业人士在线约会网站:EliteSingles
2019/03/19 全球购物
高一学生评语大全
2014/04/25 职场文书
四风问题自我剖析材料
2014/10/07 职场文书
道路交通事故人身损害赔偿协议书
2014/11/19 职场文书
停水通知
2015/04/16 职场文书
求职意向书范本
2015/05/11 职场文书
资金申请报告范文
2015/05/14 职场文书
办公经费申请报告
2015/05/15 职场文书
实施意见格式范本
2015/06/05 职场文书
2016年质量月活动总结报告
2016/04/05 职场文书