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插件开发的两种方法及$.fn.extend的详解
Jan 16 Javascript
键盘上一张下一张兼容IE/google/firefox等浏览器
Jan 28 Javascript
jQuery Validate插件实现表单强大的验证功能
Dec 18 Javascript
微信小程序的分类页面制作
Jun 27 Javascript
jQuery实现手势解锁密码特效
Aug 14 jQuery
基于javascript中的typeof和类型判断(详解)
Oct 27 Javascript
基于vue-cli 打包时抽离项目相关配置文件详解
Mar 07 Javascript
微信小程序实现倒计时补零功能
Jul 09 Javascript
vue轻量级框架无法获取到vue对象解决方法
May 12 Javascript
node.js中 mysql 增删改查操作及async,await处理实例分析
Feb 11 Javascript
JavaScript arguments.callee作用及替换方案详解
Sep 02 Javascript
js实现电灯开关效果
Jan 19 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/08/18 PHP
提高PHP性能的编码技巧以及性能优化详细解析
2013/08/24 PHP
十幅图告诉你什么是PHP引用
2015/02/22 PHP
py文件转exe时包含paramiko模块出错解决方法
2016/08/12 PHP
微信公众平台开发(五) 天气预报功能开发
2016/12/03 PHP
PHP实现深度优先搜索算法(DFS,Depth First Search)详解
2017/09/16 PHP
jQuery怎么解析Json字符串(Json格式/Json对象)
2013/08/09 Javascript
js实现遮罩层划出效果是生成div而不是显示
2014/07/29 Javascript
JavaScript中的条件判断语句使用详解
2015/06/03 Javascript
通过js获取上传的图片信息(临时保存路径,名称,大小)然后通过ajax传递给后端的方法
2015/10/01 Javascript
详解JavaScript对象序列化
2016/01/19 Javascript
jquery基础知识第一讲之认识jquery
2016/03/17 Javascript
jQuery Chart图表制作组件Highcharts用法详解
2016/06/01 Javascript
AngularJS ng-controller 指令简单实例
2016/08/01 Javascript
深入浅出ES6之let和const命令
2016/08/25 Javascript
利用ES6语法重构React组件详解
2017/03/02 Javascript
js正则表达式验证密码强度【推荐】
2017/03/03 Javascript
AngularJS ui-router (嵌套路由)实例
2017/03/10 Javascript
完美解决浏览器跨域的几种方法(汇总)
2017/05/08 Javascript
ReactNative页面跳转Navigator实现的示例代码
2017/08/02 Javascript
详解使用nvm管理多版本node的方法
2017/08/30 Javascript
ajax跨域访问遇到的问题及解决方案
2019/05/23 Javascript
JS数组方法reverse()用法实例分析
2020/01/18 Javascript
Python实现变量数值交换及判断数组是否含有某个元素的方法
2017/09/18 Python
浅谈使用Python内置函数getattr实现分发模式
2018/01/22 Python
浅谈Python采集网页时正则表达式匹配换行符的问题
2018/12/20 Python
Python设计模式之适配器模式原理与用法详解
2019/01/15 Python
对Python3 goto 语句的使用方法详解
2019/02/16 Python
东方电视购物:东方CJ
2016/10/12 全球购物
英国亚马逊官方网站:Amazon.co.uk
2019/08/09 全球购物
教师先进工作者事迹材料
2014/05/01 职场文书
生产操作工岗位职责
2014/09/16 职场文书
公务员政审个人总结
2015/02/12 职场文书
反腐倡廉学习心得体会范文
2015/08/15 职场文书
你知道哪几种MYSQL的连接查询
2021/06/03 MySQL
LeetCode189轮转数组python示例
2022/08/05 Python