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 相关文章推荐
jQuery 工具函数学习资料
Apr 29 Javascript
JavaScript事件委托技术实例分析
Feb 06 Javascript
jQuery实现自定义右键菜单的树状菜单效果
Sep 02 Javascript
用JS动态改变表单form里的action值属性的两种方法
May 25 Javascript
js将json格式的对象拼接成复杂的url参数方法
May 25 Javascript
JSON字符串和JSON对象相互转化实例详解
Jan 05 Javascript
AngularJS constant和value区别详解
Feb 28 Javascript
JS自动生成动态HTML验证码页面
Jun 14 Javascript
canvas绘制爱心的几种方法总结(推荐)
Oct 31 Javascript
vue里面父组件修改子组件样式的方法
Feb 03 Javascript
javascript实现弹出层效果
Dec 10 Javascript
addEventListener()和removeEventListener()追加事件和删除追加事件
Dec 04 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实现插入排序
2015/03/29 PHP
PHP SPL标准库之文件操作(SplFileInfo和SplFileObject)实例
2015/05/11 PHP
Javascript 通过json自动生成Dom的代码
2010/04/01 Javascript
javascript 窗口加载蒙板 内嵌网页内容
2010/11/19 Javascript
基于jQuery的360图片展示实现代码
2012/06/14 Javascript
JS实现同一个网页布局滑动门和TAB选项卡实例
2015/09/23 Javascript
详解JavaScript表单验证(E-mail 验证)
2016/03/31 Javascript
js实现为a标签添加事件的方法(使用闭包循环)
2016/08/02 Javascript
关于JSON与JSONP简单总结
2016/08/16 Javascript
JS优化与惰性载入函数实例分析
2017/04/06 Javascript
Angular(5.2->6.1)升级小结
2018/12/27 Javascript
Vue.js路由实现选项卡简单实例
2019/07/24 Javascript
[01:03:47]VP vs NewBee Supermajor 胜者组 BO3 第一场 6.5
2018/06/06 DOTA
[01:00:14]DOTA2官方TI8总决赛纪录片 真视界True Sight
2019/01/16 DOTA
跟老齐学Python之字典,你还记得吗?
2014/09/20 Python
Python打造出适合自己的定制化Eclipse IDE
2016/03/02 Python
Django使用AJAX调用自己写的API接口的方法
2019/03/06 Python
Python远程视频监控程序的实例代码
2019/05/05 Python
python 列表转为字典的两个小方法(小结)
2019/06/28 Python
Python列表元素常见操作简单示例
2019/10/25 Python
python剪切视频与合并视频的实现
2020/03/03 Python
Python爬取微信小程序Charles实现过程图解
2020/09/29 Python
python实现双人五子棋(终端版)
2020/12/30 Python
一款纯css3实现的竖形二级导航的实例教程
2014/12/11 HTML / CSS
Html5百叶窗效果的示例代码
2017/12/11 HTML / CSS
全世界最美丽的四星和五星级酒店预订:Prestigia.com
2017/11/15 全球购物
GafasWorld西班牙:购买太阳镜、眼镜和隐形眼镜
2019/09/08 全球购物
波兰品牌鞋履在线商店:Eastend.pl
2020/01/11 全球购物
类的核心特性有哪些
2014/01/01 面试题
会计系毕业个人自荐信格式
2013/09/23 职场文书
中文专业毕业生自荐书范文
2014/01/04 职场文书
工作检讨书大全
2015/01/26 职场文书
青年教师个人总结
2015/02/11 职场文书
售后前台接待岗位职责
2015/04/03 职场文书
保留意见审计报告
2015/06/05 职场文书
赢在执行观后感
2015/06/16 职场文书