详解javascript的类
前言
生活有度,人生添寿。
原文地址:详解javascript的类
博主博客地址:Damonare的个人博客
Javascript从当初的一个“弹窗语言”,一步步发展成为现在前后端通吃的庞然大物。javascript的受欢迎程度也是与日俱增,今年最受欢迎编程语言又是花落javascript,这实在是一个充满了活力的语言。如今,随随便一个网页javascript代码量都不下数千行,要是node后端那更不止几千行了。(WTF)代码量的增加给编程带来的首要的问题就是如何去编写和维护如此庞大的代码呢?答案就是模块化思想,其实就是面向对象(OOP)编程,如今比较流行的三大前端框架(angular,react,vue)基本都实现了组件化编程,但组件化和我们所说的模块化又有所不同,应该可以这么理解,组件化是模块化的升级版,模块化是组件化的基础。那么,问题来了,javascript怎么面向对象编程呢?我想这很多老鸟也不定说的清楚吧,前端杂而活跃的各种社区,很多前端er一度依赖各种插件,根本不需要去了解这些深层的东西却照样能完成任务。但我想作为一个有追求的前端er还是很有必要去学习这些看似用不着的东西的,别的不说,就单单因为我们是前端er,只会用jquery一个稍微厉害的后端都能代替你。好吧,废话不多说,到底如何面向对象coding呢.....
很不幸,es5中并没有给出明确的定义‘类’的概念,所以传统的面向对象编程似乎是行不通的,那么又该肿么办呢?值得庆幸的是,前辈们通过不断探索总结,成功的用javascript模拟出了“类”。那么,javascript的类又该怎么定义呢?
在面向对象编程中,类(class)是对象(object)的模板,定义了同一组对象(又称"实例")共有的属性和方法。
正文
说到javascript中的“类”就不得不说原型链和继承了,因为javascript是没有真正意义上的类的,所谓的类就是基于原型链和继承来实现的,即使ES6中加入了class,extends关键字实现类和继承,但实际上还是基于原型链和继承, ES6 类(class)是 JavaScript 现有的原型继承的语法糖。
1. 原型链和继承
“
在 javaScript 中,每个对象都有一个指向它的原型(prototype)对象的内部链接。这个原型对象又有自己的原型,直到某个对象的原型为 null 为止(也就是不再有原型指向),组成这条链的最后一环。这种一级一级的链结构就称为原型链(prototype chain)。
”
原型链
实际上在定义一个对象的时候原型链本身就已经生成了,javascript处处皆对象的思想放在这里理解起来就很容易了,看完后你会发现万物始于Object.prototype。那么我们都是如何定义一个对象的呢,博主总结的方法如下几个:
先初步来个demo具体解释下原型链是咋回事吧:
//someObject.[[Prototype]] 符号是用于指派 someObject 的原型。这个等同于 JavaScript 的 __proto__ 属性(现已弃用)。。从 ES6 开始, [[Prototype]] 可以用Object.getPrototypeOf()和Object.setPrototypeOf()访问器来访问。这个方法可以放心使用博主亲测,主流浏览器已经支持了
// 假定有一个对象 o, 其自身的属性(own properties)有 a 和 b:
// {a: 1, b: 2}
// o 的原型 o.[[Prototype]]有属性 b 和 c:
// {b: 3, c: 4}
// 最后, o.[[Prototype]].[[Prototype]] 是 null.
// 这就是原型链的末尾,即 null,
// 根据定义,null 没有[[Prototype]].
// 综上,整个原型链如下:
// {a:1, b:2}---> {b:3, c:4} ---> null
来来来,撸袖子搞出个对象!!!(马上狗节,单身狗请自觉阅读完此篇博客)
- 使用普通方法来创建一个对象
demo如下:
var o={
a:0,
b:function(){
console.log(this.a)
}
}
//创建一个对象
//原型链如下:
//o--->Object.prototype--->null
var a = ["yo", "whadup", "?"];
//创建一个数组对象
//(indexOf, forEach等方法都是从它继承而来).
//原型链如下:
//a--->Array.prototype ---> Object.prototype ---> null
function f(){
return 1;
}
//创建一个函数对象
//(call, bind等方法都是从它继承而来):
//原型链如下:
//f ---> Function.prototype ---> Object.prototype ---> null
var date=new Date();
//创建一个日期对象
//原型链如下:
//date--->Date.prototype--->Object.pprototype--->null
- 使用构造函数的方法
在 JavaScript 中,构造器其实就是一个普通的函数。当使用 new 操作符 来作用这个函数时,它就可以被称为构造方法(构造函数)。------MDN
demo如下:
function fun(){
this.propA='prop';
this.propB=3;
}
fun.prototype={
methodA:function(){
console.log(this.propA)
}
}
var o=new fun();
o.methodA();//prop
// o是生成的对象,他的自身属性有'propA'和'propB'.
// 在o被实例化时,o.[[Prototype]]指向了fun.prototype.
- 使用Object.create创建对象
ECMAScript 5 中引入了一个新方法:Object.create()。可以调用这个方法来创建一个新对象。新对象的原型就是调用 create 方法时传入的第一个参数:
var a = {a: 1};
// a ---> Object.prototype ---> null
var b = Object.create(a);
// b ---> a ---> Object.prototype ---> null
console.log(b.a); // 1 (继承而来)继承概念下面会讲
var c = Object.create(b);
// c ---> b ---> a ---> Object.prototype ---> null
var d = Object.create(null);
// d ---> null
console.log(d.hasOwnProperty); // undefined, 因为d没有继承Object.prototype
- 使用 class 关键字
ECMAScript6 引入了一套新的关键字用来实现 class。使用基于类语言的开发人员会对这些结构感到熟悉,但它们是不一样的。 JavaScript 仍然是基于原型的。这些新的关键字包括 class, constructor, static, extends, 和 super.
"use strict";
class Polygon {
constructor(height, width) {
this.height = height;
this.width = width;
}
}
//定义一个类Polygon
class Square extends Polygon {
constructor(sideLength) {
super(sideLength, sideLength);
}//使用super引用父类
get area() {
return this.height * this.width;
}
set sideLength(newLength) {
this.height = newLength;
this.width = newLength;
}
}
//使用extends定义Squeare继承父类Polygon
var square = new Square(2);//实例对象
//此时的原型链为:
//square--->Square.prototype--->Polygon.prototype--->Object.prototype--->null
//如果不理解为什么是这样,不要紧接着往下看类的说明
继承
其实在上面讲原型链的时候难以避免的也提到了继承,比如来自MDN的这个实例:
// 假定有一个对象 o, 其自身的属性(own properties)有 a 和 b:
// {a: 1, b: 2}
// o 的原型 o.[[Prototype]]有属性 b 和 c:(someObject.[[Prototype]] 符号是用于指派 someObject 的原型。这个等同于 JavaScript 的 __proto__ 属性(现已弃用)。。从 ES6 开始, [[Prototype]] 可以用Object.getPrototypeOf()和Object.setPrototypeOf()访问器来访问。)
// {b: 3, c: 4}
// 最后, o.[[Prototype]].[[Prototype]] 是 null.
// 这就是原型链的末尾,即 null,
// 根据定义,null 没有[[Prototype]].
// 综上,整个原型链如下:
// {a:1, b:2} ---> {b:3, c:4} ---> null
console.log(o.a); // 1
// a是o的自身属性吗?是的,该属性的值为1
console.log(o.b); // 2
// b是o的自身属性吗?是的,该属性的值为2
// o.[[Prototype]]上还有一个'b'属性,但是它不会被访问到.这种情况称为"属性遮蔽 (property shadowing)".
console.log(o.c); // 4
// c是o的自身属性吗?不是,那看看o.[[Prototype]]上有没有.
// c是o.[[Prototype]]的自身属性吗?是的,该属性的值为4
console.log(o.d); // undefined
// d是o的自身属性吗?不是,那看看o.[[Prototype]]上有没有.
// d是o.[[Prototype]]的自身属性吗?不是,那看看o.[[Prototype]].[[Prototype]]上有没有.
// o.[[Prototype]].[[Prototype]]为null,停止搜索,
// 没有d属性,返回undefined
----以上内容来自MDN继承与原型链
我想看到这里还是有些似懂非懂吧,那么来个例子吧:
var object1={
a:1,
b:function(){
console.log(this.a+1);
}
}
//定义一个对象
var object2=Object.create(object1);
//调用Object.create来创建一个新对象,新对象的原型就是调用 create 方法时传入的第一个参数,现在的原型链是:
//object2--->object1--->object1.prototype--->null
object2.d=4;
object2.a;
//1
//继承了object1的属性a
object2.b();
//2
//继承了object1的方法b
Object.getPrototypeOf(object2);
//object1得到object2的原型object1
我想现在应该是明白了吧,再不明白博主也是无能为力了,表达能力实在有限。
2. 类
总算说到类了,由于javascript的类基于原型链和继承,因此在上面的内容中就已经定义了很多的类。咱们javascript的类同样能实现传统类的多态,封装,继承等特性,这里主要讲解了继承这个概念,但实际上很多时候不经意可能就用了这三个特性。很好玩不是么
首先,我们先看下在ES5中定义一个类的形式:
function Animal(name) {
this.name = name;
this.sleep = function() {
console.log(this.name+'正在睡觉');
}
}//定义Animal类
Animal.prototype = {
eat: function(food) {
console.log(this.name+"正在吃"+food);
}
}
function Cat() {
}
Cat.prototype = new Animal('Tom');
var Tom = new Cat('Tom');/Cat实例对象
Tom.eat('猫粮');
//Tom正在吃猫粮
//继承Animal方法
Tom.sleep();
//Tom正在睡觉
//继承Animal方法
//现在的原型链:
//Tom(Cat实例对象)--->Cat.prototype(Animal实例对象)--->Animal.prototype--->Object.prototype--->null
好的,然后我们看下在ES6中改写上面的类:
class Animal {
constructor(name) {
this.name = name;
}
sleep() {
console.log(this.name + ' 正在睡觉');
}
eat(food){
console.log(this.name+'正在吃'+food)
}
}
class Cat extends Animal {
}
const Tom = new Cat('Tom');
Tom.eat('猫粮');
//Tom正在吃猫粮
//继承Animal方法
Tom.sleep();
//Tom正在睡觉
//继承Animal方法
//现在的原型链:
//Tom(Cat实例对象)--->Cat.prototype(Animal实例对象)--->Animal.prototype--->Object.prototype--->null
定义一个类的方法实际上也是上面所说的定义一个对象的方法,类本身就是一个对象,只不过这个对象里面的方法和属性可以供许多实例对象调用而已。
后记
总的来说对于类的理解还是需要不断探索的,路漫漫其修远兮,吾将上下而求索。
详解javascript的类的更多相关文章
- 详解Javascript的继承实现(二)
上文<详解Javascript的继承实现>介绍了一个通用的继承库,基于该库,可以快速构建带继承关系和静态成员的javascript类,好使用也好理解,额外的好处是,如果所有类都用这种库来构 ...
- js对象详解(JavaScript对象深度剖析,深度理解js对象)
js对象详解(JavaScript对象深度剖析,深度理解js对象) 这算是酝酿很久的一篇文章了. JavaScript作为一个基于对象(没有类的概念)的语言,从入门到精通到放弃一直会被对象这个问题围绕 ...
- 详解javascript中的this对象
详解javascript中的this对象 前言 Javascript是一门基于对象的动态语言,也就是说,所有东西都是对象,一个很典型的例子就是函数也被视为普通的对象.Javascript可以通过一定的 ...
- (转载)详解Javascript中prototype属性(推荐)
在典型的面向对象的语言中,如java,都存在类(class)的概念,类就是对象的模板,对象就是类的实例.但是在Javascript语言体系中,是不存在类(Class)的概念的,javascript中不 ...
- 【转】详解JavaScript中的this
ref:http://blog.jobbole.com/39305/ 来源:foocoder 详解JavaScript中的this JavaScript中的this总是让人迷惑,应该是js众所周知的坑 ...
- CSS选择器详解(伪类) 转 http://blog.csdn.net/Panda_m/article/details/50084699
CSS选择器详解 之 伪类 伪类对大小写不敏感 结构伪类选择器 结构伪类是CSS3新增的类型选择器,利用DOM树实现元素过滤,通过文档结构的相互关系来匹配元素,可以减少class和id属性的定义,使文 ...
- 详解 javascript中offsetleft属性的用法(转)
详解 javascript中offsetleft属性的用法 转载 2015-11-11 投稿:mrr 我要评论 本章节通过代码实例介绍一下offsetleft属性的用法,需要的朋友可以做一 ...
- 详解 QT 主要类 QWidget
QWidget类是所有用户界面对象的基类,每一个窗口部件都是矩形,并且它们按Z轴顺序排列的.一个窗口部件可以被它的父窗口部件或者它前面的窗口部件盖住一部分. 先来看内容. AD: 2013云计算架构师 ...
- 详解JavaScript调用栈、尾递归和手动优化
调用栈(Call Stack) 调用栈(Call Stack)是一个基本的计算机概念,这里引入一个概念:栈帧. 栈帧是指为一个函数调用单独分配的那部分栈空间. 当运行的程序从当前函数调用另外一个函数时 ...
随机推荐
- Webpack 配置摘要
open-browser-webpack-plugin 自动打开浏览器 html-webpack-plugin 通过 JS 生成 HTML webpack.optimize.UglifyJsPlugi ...
- redis 学习笔记(2)
redis-cluster 简介 redis-cluster是一个分布式.容错的redis实现,redis-cluster通过将各个单独的redis实例通过特定的协议连接到一起实现了分布式.集群化的目 ...
- 【原创经验分享】WCF之消息队列
最近都在鼓捣这个WCF,因为看到说WCF比WebService功能要强大许多,另外也看了一些公司的招聘信息,貌似一些中.高级的程序员招聘,都有提及到WCF这一块,所以,自己也关心关心一下,虽然目前工作 ...
- 初学者看过来之JSON入门
1. 什么是JSON JSON---Javascript Object Notation,前两个单词大家应该都认识,最后一个notation,是"记号.标记法"的意思,连在一起,便 ...
- [原] KVM 虚拟化原理探究(6)— 块设备IO虚拟化
KVM 虚拟化原理探究(6)- 块设备IO虚拟化 标签(空格分隔): KVM [toc] 块设备IO虚拟化简介 上一篇文章讲到了网络IO虚拟化,作为另外一个重要的虚拟化资源,块设备IO的虚拟化也是同样 ...
- js面向对象学习 - 对象概念及创建对象
原文地址:js面向对象学习笔记 一.对象概念 对象是什么?对象是“无序属性的集合,其属性可以包括基本值,对象或者函数”.也就是一组名值对的无序集合. 对象的特性(不可直接访问),也就是属性包含两种,数 ...
- C#委托异步调用
参考页面: http://www.yuanjiaocheng.net/webapi/mvc-consume-webapi-get.html http://www.yuanjiaocheng.net/w ...
- MyBatis源码分析(二)语句处理器
StatementHandler 语句处理器,主要负责语句的创建.参数的设置.语句的执行.不负责结果集的处理. Statement prepare(Connection connection, Int ...
- Android系统默认对话框添加图片
开发工具Android Studio 今天公司UI要求软件对话框改成加图片的,以前没有做过,所以就学习了一下,废话不多说, 看效果: 创建XML文件dialog_lsit_item.xml <L ...
- 跨域问题,前端主动向后台发送cookie
跨域是什么? 从一个域名的网页访问另一个域名的资源,就会出现跨域.只要协议.端口.域名有一个不同就会出现跨域 例如: 1.协议不同 http://www.baidu.com:80 和 https:/ ...