Javascript继承,再谈
说到Javascript的继承,相信只要是前端开发者都有所了解或应用,因为这是太基础的知识了。但不知各位有没有深入去理解其中的玄机与奥秘。今本人不才,但也想用自己的理解来说一说这其中的玄机和奥秘。
一、类继承的发展吏
- function实现的继承
function的继承是完全模仿了OOP的编程思想。实现的是类的继承
- object.create实现的继承
用object.create来修改其原型
- es6的继承
增加了class来模拟OOP的继承实现。上述两种继承实现,他都还是支持的。
二、各时期类继承的实现
- function继承方式的实现(OOP)
function Animate(name){
this.name = name;
}
Animate.prototype.getName = function(){
return this.name;
}
function Dog(name){
Animate.apply(this,arguments);
this.leg = 4;
}
Dog.prototype = Inherit(Animate, Dog);
Dog.prototype.say = function(){
return 'wang';
}
//function模式的继承
function Inherit(parent, child){
//创建一个无原型方法的类
function f(){}
f.prototype = parent.prototype; //将父对象的原型赋给临时对象
f.prototype.constructor = child; //将子类构造函数绑定到 临时对象的 prototype原型上,保持子类构造函数与prototype上的一致。
return new f(); //执行了f的构造函数,而没有执行prototype.constructor指向的构造函数
}
var dog = new Dog('dog');
console.log('getName:' + dog.getName()); //dog
console.log("say:" + dog.say()); //wang
console.log( 'dog instanceof Animate:' + (dog instanceof Animate)); //true
console.log( 'dog instanceof Animate: ' + (dog instanceof Dog)); //true
OOP方式的继承实现网上有很多种,如:原型链,实现、组合、寄生组合继承等。上述实现为寄生组合继承在,算比较通用且完美的一种方案了。
- object.create实现继承 这是一个升级版本的类式继承,需要了解object.create方法。Object.create(proto, [propertiesObject]),其中proto是新创建对象的原型对象,而propertiesObject是可选的,要添加到新创建对象的可枚举属性(即其自身定义的属性,而不是原型链接上的属性)。 我们还需要了解的方法:Object.setPrototypeOf(内部原型的写方法);Object.getPrototypeOf(内部原型的读方法)。内部原型:[[prototype]] == proto 上述继承代码的改造后
function Animate(name){
this.name = name;
}
Animate.prototype.getName = function(){
return this.name;
}
function Dog(name){
Animate.apply(this,arguments);
this.leg = 4;
}
Inherit(Animate, Dog); //调用点改造
Dog.prototype.say = function(){
return 'wang';
}
//继承实现方法改造
function Inherit(parent, child){
child.prototype = Object.create(parent.prototype); //create实现parent上的原型复制
child.prototype.constructor = child; //将构造函数指回子类
}
var dog = new Dog('dog');
console.log('getName:' + dog.getName()); //dog
console.log("say:" + dog.say()); //wang
console.log( 'dog instanceof Animate:' + (dog instanceof Animate)); //true
console.log( 'dog instanceof Animate: ' + (dog instanceof Dog)); //true
2.1 对prototype的尝试
上述示例中用了Object.create方法创建一个对象,然后再赋值给Prototype,而为什么不用Object.setPrototypeOf方法直接改变其Prototype的值呢。原因摘录来源于MDN:
由于现代 JavaScript 引擎优化属性访问所带来的特性的关系,更改对象的 [[Prototype]]在各个浏览器和 JavaScript 引擎上都是一个很慢的操作。其在更改继承的性能上的影响是微妙而又广泛的,这不仅仅限于 obj.proto = ... 语句上的时间花费,而且可能会延伸到任何代码,那些可以访问任何[[Prototype]]已被更改的对象的代码。如果你关心性能,你应该避免设置一个对象的 [[Prototype]]。相反,你应该使用 Object.create()来创建带有你想要的[[Prototype]]的新对象。
对象继承的实现:
var animate = {
name: "name"
};
Object.setPrototypeOf(animate,{
getName: function(){
return this.name;
}
});
var dog = {
leg: 4
};
Object.setPrototypeOf(dog,{
say: function(){
return 'wang';
}
});
Object.setPrototypeOf(Object.getPrototypeOf(dog),Object.getPrototypeOf(animate));
console.log('getName:' + dog.getName()); //dog
console.log("say:" + dog.say()); //wang
三、ES6类继承的实现
es6对类继承提供了原生的支持,这让Javascript更像后端语言了,简单使用如下:
class Animate{
constructor(name){
this.name = name
}
getName(){
return this.name;
}
}
class Dog extends Animate{
constructor(name){
super(name);
this.leg = 4;
}
say(){
return "wang";
}
}
var dog = new Dog('dog');
console.log('getName:' + dog.getName()); //dog
console.log("say:" + dog.say()); //wang
console.log( 'dog instanceof Animate:' + (dog instanceof Animate)); //true
console.log( 'dog instanceof Animate: ' + (dog instanceof Dog)); //true
四、总结及疑问
经过本文梳理,你是否发现Javascript的类继承实现越来越简单,更接近于Java,.net这类静态编译语言了,或许这就是所谓的万物归一的哲学道理。但在此还是存在一个极大的疑问:Object.setPrototypeOf方法在MDN不建议使用,说是更改内部的[[prototype]]属性存在性能问题 和 影响。不知道其影响为何,望大神们指定。
- spring使用Email邮件系统
- discuz论坛apache日志hadoop大数据分析项目:清洗数据核心功能解说及代码实现
- mybatis 对于基本类型数据传值的问题
- Guava------------Cache使用方法
- hadoop安装及配置入门篇
- 剖析Go编写的Socket服务器模块解耦及基础模块的设计
- hihocoder-平衡树·SBT
- mysql 查询数据库表结构
- Go语言基于Socket编写服务器端与客户端通信的实例
- 前端游戏编程基础-如何实现Canvas图像的拖拽、点击等操作
- 使用Go开发一个简单的服务器程序
- Golang URL解析
- golang实现基于redis和consul的可水平扩展的排行榜服务范例
- golang学习之旅:使用go语言操作mysql数据库
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Android 功耗(4)---MTK平台待机功耗分析流程
- 使用iframe实现在pc端预览移动端页面的效果
- html+css实现彩色渐变滑动条
- 项目实战 01:将唐诗三百首写入 Elasticsearch 会发生什么?
- 装饰器和代理模式的区别,从一碗小米粥谈起
- EasyNVR部署在centos虚拟机上出现无法访问情况,该如何排查?
- RTSP协议网页无插件直播平台EasyNVR视频广场无法搜索纯数字关键词的通道,该如何解决的?
- RTSP协议网页无插件直播平台EasyNVR通道管理搜索纯数字关键词,返回结果为空如何解决?
- Mysql如何选择唯一索引和普通索引
- Python自学成才之路 多线程开发
- Mysql为什么会抖一下呢
- Python自学成才之路 线程间协作 lock,condition,event的使用
- Java 语言基础 (初识Java语言, 变量和数据类型, 运算符, 流程控制语句, 数组)
- python自学成才之路 线程间协作之Semaphore,threading.local()
- jenkins基础