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 相关文章推荐
如何制作浮动广告 JavaScript制作浮动广告代码
Dec 30 Javascript
javascript根据时间生成m位随机数最大13位
Oct 30 Javascript
js仿淘宝和百度文库的评分功能
May 15 Javascript
js验证框架之RealyEasy验证详解
Jun 08 Javascript
完美解决IE9浏览器出现的对象未定义问题
Sep 29 Javascript
jQuery中$.ajax()方法参数解析
Oct 22 Javascript
基于JavaScript实现自定义滚动条
Jan 25 Javascript
React.js中常用的ES6写法总结(推荐)
May 09 Javascript
zTree节点文字过多的处理方法
Nov 24 Javascript
一些手写JavaScript常用的函数汇总
Apr 16 Javascript
Vue过渡效果之CSS过渡详解(结合transition,animation,animate.css)
Feb 05 Javascript
JavaScript实现京东快递单号查询
Nov 30 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二进制流 逐bit的低位在前算法(详解)
2013/06/13 PHP
PHP将session信息存储到数据库的类实例
2015/03/04 PHP
使用PHP如何实现高效安全的ftp服务器(二)
2015/12/30 PHP
深入解析WordPress中加载模板的get_template_part函数
2016/01/11 PHP
PHP数组函数知识汇总
2016/05/12 PHP
PHP使用 Pear 进行安装和卸载包的方法详解
2019/07/08 PHP
php中关于换行的实例写法
2019/09/26 PHP
JS getStyle获取最终样式函数代码
2010/04/01 Javascript
jQuery 菜单随滚条改为以定位方式(固定要浏览器顶部)
2012/05/24 Javascript
jQuery Ajax中的事件详细介绍
2015/04/16 Javascript
JS模拟按钮点击功能的方法
2015/12/22 Javascript
设置jQueryUI DatePicker默认语言为中文
2016/06/04 Javascript
Bootstrap Table表格一直加载(load)不了数据的快速解决方法
2016/09/17 Javascript
原生JS简单实现ajax的方法示例
2016/11/29 Javascript
nodejs实例解析(输出hello world)
2017/01/03 NodeJs
Easyui使用Dialog行内按钮布局的实例
2017/07/27 Javascript
angularjs下ng-repeat点击元素改变样式的实现方法
2018/09/12 Javascript
Vue如何提升首屏加载速度实例解析
2020/06/25 Javascript
解决vue项目运行npm run serve报错的问题
2020/10/26 Javascript
vue添加自定义右键菜单的完整实例
2020/12/08 Vue.js
python list语法学习(带例子)
2013/11/01 Python
Python使用MONGODB入门实例
2015/05/11 Python
python打印9宫格、25宫格等奇数格 满足横竖斜相加和相等
2019/07/19 Python
pytorch 中pad函数toch.nn.functional.pad()的用法
2020/01/08 Python
python实现井字棋小游戏
2020/03/04 Python
Django添加bootstrap框架时无法加载静态文件的解决方式
2020/03/27 Python
大唐电信科技股份有限公司java工程师面试经历
2016/12/09 面试题
请写出 float x 与"零值"比较的 if 语句
2016/01/04 面试题
文件中有一组整数,要求排序后输出到另一个文件中
2012/01/04 面试题
团日活动总结书格式
2014/05/08 职场文书
教师节感谢信
2015/01/22 职场文书
代理词怎么写
2015/05/25 职场文书
2016年第32个教师节红领巾广播稿
2015/12/18 职场文书
2016大一新生入学教育心得体会
2016/01/23 职场文书
护士医德医风心得体会
2016/01/25 职场文书
oracle删除超过N天数据脚本的方法
2022/02/28 Oracle