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 相关文章推荐
asp.net网站开发中用jquery实现滚动浏览器滚动条加载数据(类似于腾讯微博)
Mar 14 Javascript
html向js方法传递参数具体实现
Aug 08 Javascript
jquery判断单选按钮radio是否选中的方法
May 05 Javascript
Angularjs的ng-repeat中去除重复数据的方法
Aug 05 Javascript
JS判断两个对象内容是否相等的方法示例
Apr 10 Javascript
vue中使用vue-router切换页面时滚动条自动滚动到顶部的方法
Nov 28 Javascript
webpack多入口文件页面打包配置详解
Jan 09 Javascript
JavaScript实现读取与输出XML文件数据的方法示例
Jun 05 Javascript
layui 解决form表单点击无反应的问题
Oct 25 Javascript
jQuery实现鼠标移入显示蒙版效果
Jan 11 jQuery
vue 子组件watch监听不到prop的解决
Aug 09 Javascript
11个Javascript小技巧帮你提升代码质量(小结)
Dec 28 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
codeigniter集成ucenter1.6双向通信的解决办法
2014/06/12 PHP
使用Codeigniter重写insert的方法(推荐)
2017/03/23 PHP
PHP操作MySQL中BLOB字段的方法示例【存储文本与图片】
2017/09/15 PHP
PHP7扩展开发之hello word实现方法详解
2018/01/15 PHP
Laravel5.5以下版本中如何自定义日志行为详解
2018/08/01 PHP
flexigrid 参数说明
2010/11/23 Javascript
NodeJS框架Express的模板视图机制分析
2011/07/19 NodeJs
JS比较两个时间大小的简单示例代码
2013/12/20 Javascript
JS实现网页上随机产生超链接地址的方法
2015/11/09 Javascript
深入理解bootstrap框架之第二章整体架构
2016/10/09 Javascript
JavaScript实现图片轮播组件代码示例
2016/11/22 Javascript
jQuery选择器之子元素过滤选择器
2017/09/28 jQuery
JavaScript 日期时间选择器一些小结
2018/04/02 Javascript
微信小程序实现跑马灯效果
2020/10/21 Javascript
使用react render props实现倒计时的示例代码
2018/12/06 Javascript
Vue学习之常用指令实例详解
2020/01/06 Javascript
原生JS运动实现轮播图
2021/01/02 Javascript
Python单链表的简单实现方法
2014/09/23 Python
浅谈Python浅拷贝、深拷贝及引用机制
2016/12/15 Python
你应该知道的python列表去重方法
2017/01/17 Python
python中pandas.DataFrame的简单操作方法(创建、索引、增添与删除)
2017/03/12 Python
使用Python3制作TCP端口扫描器
2017/04/17 Python
Python OS模块实例详解
2019/04/15 Python
python制作填词游戏步骤详解
2019/05/05 Python
Django admin 实现search_fields精确查询实例
2020/03/30 Python
如何用Python编写一个电子考勤系统
2021/02/08 Python
亲子拓展活动方案
2014/02/20 职场文书
优秀班集体先进事迹材料
2014/05/28 职场文书
复兴之路观后感
2015/06/02 职场文书
2015年卫生院健康教育工作总结
2015/07/24 职场文书
新郎父亲婚礼致辞
2015/07/27 职场文书
2015年文秘个人工作总结
2015/10/14 职场文书
2016年清明节期间群众祭祀活动工作总结
2016/04/01 职场文书
详解MongoDB的条件查询和排序
2021/06/23 MongoDB
python常见的占位符总结及用法
2021/07/02 Python
详解Vue中$props、$attrs和$listeners的使用方法
2022/02/18 Vue.js