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 浏览器判断实现函数
Aug 20 Javascript
Jquery 快速构建可拖曳的购物车DragDrop
Nov 30 Javascript
最常用的12种设计模式小结
Aug 09 Javascript
能说明你的Javascript技术很烂的五个原因分析
Oct 28 Javascript
jquery ajax对特殊字符进行转义防止js注入使用示例
Nov 21 Javascript
EasyUI加载完Html内容样式渲染完成后显示
Jul 25 Javascript
Vue.js框架路由使用方法实例详解
Aug 25 Javascript
vuex实现登录状态的存储,未登录状态不允许浏览的方法
Mar 09 Javascript
详解element-ui日期时间选择器的日期格式化问题
Apr 08 Javascript
如何在Vue中抽离接口配置文件
Oct 31 Javascript
JS检索下拉列表框中被选项目的索引号(selectedIndex)
Dec 17 Javascript
vue将文件/图片批量打包下载zip的教程
Oct 21 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/01/24 PHP
PHP使用Pear发送邮件(Windows环境)
2016/01/05 PHP
Yii2 加载css、js 载静态资源的方法
2017/03/10 PHP
javascript 静态对象和构造函数的使用和公私问题
2010/03/02 Javascript
30个经典的jQuery代码开发技巧
2014/12/15 Javascript
7个让JavaScript变得更好的注意事项
2015/01/28 Javascript
Node.js事件循环(Event Loop)和线程池详解
2015/01/28 Javascript
JavaScript使表单中的内容显示在屏幕上的方法
2015/06/29 Javascript
理解javascript封装
2016/02/23 Javascript
原生js实现addClass,removeClass,hasClass方法
2016/04/27 Javascript
webpack 1.x升级过程中的踩坑总结大全
2017/08/09 Javascript
JQuery 选择器、DOM节点操作练习实例
2017/09/28 jQuery
浅谈Angular HttpClient简单入门
2018/05/04 Javascript
微信小程序实现倒计时调用相机自动拍照功能
2018/06/10 Javascript
js实现自定义右键菜单
2020/05/18 Javascript
[05:05]第三天的dota2
2013/07/29 DOTA
[03:24]2014DOTA2国际邀请赛 神秘商店生意火爆
2014/07/18 DOTA
[36:19]2018DOTA2亚洲邀请赛 小组赛 A组加赛 Newbee vs LGD
2018/04/03 DOTA
[50:38]DOTA2-DPC中国联赛 正赛 Phoenix vs CDEC BO3 第二场 3月7日
2021/03/11 DOTA
django使用html模板减少代码代码解析
2017/12/12 Python
python2.7+selenium2实现淘宝滑块自动认证功能
2018/02/24 Python
PyQt5每天必学之创建窗口居中效果
2018/04/19 Python
Python实现FTP文件传输的实例
2019/07/07 Python
python函数的万能参数传参详解
2019/07/26 Python
python使用numpy实现直方图反向投影示例
2020/01/17 Python
html5 css3实例教程 一款html5和css3实现的小机器人走路动画
2014/10/20 HTML / CSS
罗兰·穆雷官网:Roland Mouret
2018/09/28 全球购物
美国领先的眼镜和太阳镜在线零售商:Glasses.com
2019/08/26 全球购物
测控技术与通信工程毕业生自荐信范文
2013/12/28 职场文书
化学教师教学反思
2014/01/17 职场文书
工厂保安员岗位职责
2014/01/31 职场文书
企业员工培训感言
2014/02/26 职场文书
公民授权委托书范本
2014/09/17 职场文书
离婚协议书怎样才有法律效力
2014/10/10 职场文书
小班下学期幼儿评语
2014/12/30 职场文书
研究生学习计划书应该怎么写?
2019/09/10 职场文书