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 相关文章推荐
JS返回上一页实例代码通过图片和按钮分别实现
Aug 16 Javascript
纯js简单日历实现代码
Oct 05 Javascript
jquery1.9 下检测浏览器类型和版本的方法
Dec 26 Javascript
Javascript中的数据类型之旅
Oct 18 Javascript
JS实现浏览器状态栏文字闪烁效果的方法
Oct 27 Javascript
jQuery弹簧插件编写基础之“又见弹窗”
Dec 11 Javascript
利用Js的console对象,在控制台打印调式信息测试Js的实现
Nov 26 Javascript
JavaScript正则表达式函数总结(常用)
Feb 22 Javascript
Vue不能检测到Object/Array更新的情况的解决
Jun 26 Javascript
vue页面更新patch的实现示例
Mar 25 Javascript
微信小程序自定义扫码功能界面的实现代码
Jul 02 Javascript
vue+elementUI中表格高亮或字体颜色改变操作
Nov 02 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类(查找/修改)xml文档
2013/03/26 PHP
php生成随机密码自定义函数代码(简单快速)
2014/05/10 PHP
Ubuntu12下编译安装PHP5.3开发环境
2015/03/27 PHP
屏蔽F1~F12的快捷键的js函数
2010/05/06 Javascript
js截取函数(indexOf,join等)
2010/09/01 Javascript
javascript小组件 原生table排序表格脚本(兼容ie firefox opera chrome)
2012/07/25 Javascript
向当前style sheet中插入一个新的style实现方法
2013/04/01 Javascript
JavaScript中的函数重载深入理解
2014/08/04 Javascript
原生js和jQuery随意改变div属性style的名称和值
2014/10/22 Javascript
一款基jquery超炫的动画导航菜单可响应单击事件
2014/11/02 Javascript
JS逆序遍历实现代码
2014/12/02 Javascript
深入理解JavaScript系列(49):Function模式(上篇)
2015/03/04 Javascript
无需 Flash 使用 jQuery 复制文字到剪贴板
2016/04/26 Javascript
前端js文件合并的三种方式推荐
2016/05/19 Javascript
Nodejs进阶:如何将图片转成datauri嵌入到网页中去实例
2016/11/21 NodeJs
RequireJS 依赖关系的实例(推荐)
2017/01/21 Javascript
angularJS利用ng-repeat遍历二维数组的实例代码
2017/06/03 Javascript
mui back 返回刷新页面的实例
2017/12/06 Javascript
JavaScript惰性求值的一种实现方法示例
2019/01/11 Javascript
CKEditor扩展插件:自动排版功能autoformat插件实现方法详解
2020/02/06 Javascript
node+multer实现图片上传的示例代码
2020/02/18 Javascript
Vue 3自定义指令开发的相关总结
2021/01/29 Vue.js
pandas 选择某几列的方法
2018/07/03 Python
python and or用法详解
2019/06/26 Python
Python Django框架模板渲染功能示例
2019/11/08 Python
DRF使用simple JWT身份验证的实现
2021/01/14 Python
CSS3实现复选框动画特效示例代码
2016/09/27 HTML / CSS
Viking比利时:购买办公用品
2019/10/30 全球购物
CLR与IL分别是什么含义
2016/08/23 面试题
中学教师自我鉴定
2014/02/07 职场文书
最新大学生创业计划书写作攻略
2014/04/02 职场文书
关于保护环境的标语
2014/06/09 职场文书
七年级地理教学计划
2015/01/22 职场文书
vue点击弹窗自动触发点击事件的解决办法(模拟场景)
2021/05/25 Vue.js
详解Python为什么不用设计模式
2021/06/24 Python
Golang数据类型和相互转换
2022/04/12 Golang