深入解读 Js 中的面向对象编程
前言:今天看了一篇文章觉得很不错,所以给大家分享一下,也许很多人都看过面向对象编程甚至写过这样博客,觉得面向对象编程就那样,没啥好说的,那可能是因为你对这方面知识已经了解,可以选择性跳过。那如果有更通俗易懂的解读欢迎分享给我。或者有更好的学习技术书籍推荐也可以在评论下方留言,谢谢。
面向对象的几个概念
在进行面向对象编程,首先了解传统的面向对象编程(例如Java)中常会涉及到的概念,大致可以包括:
- 类:定义对象的特征。它是对象的属性和方法的模板定义。
- 对象(或称实例):类的一个实例。
- 属性:对象的特征,比如颜色、尺寸、大小等。
- 方法:对象的行为,比如走路、说话等。
- 构造函数:对象初始化的瞬间被调用的方法。
- 继承:子类可以继承父类的特征。例如,猫继承了动物的一般特性。
- 封装:一种把数据和相关的方法绑定在一起使用的方法。
- 抽象:结合复杂的继承、方法、属性的对象能够模拟现实的模型。
- 多态:不同的类可以定义相同的方法或属性。
在 JavaScript 的面向对象编程中大体也包括这些。不过在称呼上可能稍有不同,例如,JavaScript 中没有原生的“类”的概念,
而只有对象的概念。因此,随着你认识的深入,我们会混用对象、实例、构造函数等概念。
对象的创建
在js里,我们通常可以使用构造函数来创建特定类型的对象。诸如 Object 和 Array 这样的原生构造函数。此外,我们也可以创建自定义的构造函数。例如:
function Person(name, age, job) {
this.name = name;
this.age = age;
this.job = job;
}
var person1 = new Person('Excellent', 18, 'Student');
var person2 = new Person('wangli', 20, 'Doctor');
构造函数应该以一个大写字母开头(和Java中定义的类一样),普通函数则小写字母开头。
要创建 Person 的新实例,必须使用 new 操作符。
以这种方式调用构造函数实际上会经历以下4个步骤:
- 创建一个新对象(实例)
- 将构造函数的作用域赋给新对象(也就是重设了
this的指向,this就指向了这个新对象) - 执行构造函数中的代码(为这个新对象添加属性)
- 返回新对象
在上面的例子中,我们创建了 Person 的两个实例 person1 和 person2 。
原型模式定义对象的方法
//创建面向对象
function Person(age,name,job){
this.name=name;
this.age=age;
this.job=job;
}
Person.prototype.sayName = function () {
console.log(this.name);
/*Person.prototype={
constructor:Person,// 这里重新将构造函数指回Person构造函数
sayname:function(){
console.log(this.name);
}
}*///也可以这样定义
var person1=new Person("38","黎明","明星");
var person2=new Person("18","Excellent","前端开发");
console.log(person1.sayname===person2.sayname);//true
person1.sayname();//黎明
person2.sayname();//Excellent
通过原型模式定义的方法sayName()为所有的实例所共享。也就是,person1和person2访问的是同一个sayName()函数。同样的,公共属性也可以使用原型模式进行定义:
function Chinese (name) {
this.name = name;
}
Chinese.prototype.shcool= '实验中学'; // 公共属性,所有实例共享
组合使用构造函数模式和原型模式
创建自定义类型的最常见方式,就是组合使用构造函数模式与原型模式。构造函数模式用于定义实例属性,
而原型模式用于定义方法和共享的属性。
继承
大多的面向对象语言都支持两种继承方式:接口继承和实现继承。ECMAScript只支持实现继承,而且其实现继承主要依靠原型链来实现。
原型链继承
使用原型链作为实现继承的基本思想是:利用原型让一个引用类型继承另一个引用类型的属性和方法。首先我们先回顾一些基本概念:
- 每个构造函数都有一个原型对象(
prototype) - 原型对象包含一个指向构造函数的指针(
constructor) - 实例都包含一个指向原型对象的内部指针(
[[Prototype]])
如果我们让原型对象等于另一个类型的实现,结果会怎么样?显然,此时的原型对象将包含一个指向另一个原型的指针,
相应的,另一个原型中也包含着一个指向另一个构造函数的指针。假如另一个原型又是另一个类型的实例,那么上述关系依然成立,
如此层层递进,就构成了实例与原型的链条。可参考:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Inheritance_and_the_prototype_chain
简单的例子,演示了使用原型链实现继承的基本框架:
//原型继承
function Father(name){
this.name=name;
}
Father.prototype.sayfname=function(){
console.log(this.name);
}
function Child(cname){
this.cname=cname;
}
Child.prototype=new Father('父级');//继承父级Father
Child.prototype.constructor=Child;
//会切断原型链,导致无法进行继承,变成 Child -> Object
/*Child.prototype={
saycname:function(){
console.log(this.cname);
}
}*/
Child.prototype.saycname=function(){
console.log(this.cname);
}
var child1=new Child('子级');
child1.saycname();
child1.sayfname();
原型链继承的核心语句是Child.prototype = new Father('父级');
,它实现了Child对Father的继承,
而继承是通过创建Father的实例,并将该实例赋给Child.prototype实现的。

ps:原型链的问题:
1.首先是顺序,一定要先继承父类,然后为子类添加新方法。
2.其次,使用原型链实现继承时,不能使用对象字面量创建原型方法。因为这样做就会重写原型链.如上面注释一样。
借用构造函数继承
借用构造函数(constructor stealing)的基本思想如下:即在子类构造函数的内部调用超类型构造函数。
//构造函数
function Parent(name){
this.name=name;
this.colors=['blue','pink','yellow']
}
function Childs(name){
Parent.call(this,name);
}
var instance1 =new Childs('Excellent');
instance1.colors.push('black');
console.log(instance1.colors); // [ 'blue', 'pink', 'yellow', 'black' ]
console.log(instance1.name); // Excellent
var instance2 = new Childs("wangli");
console.log(instance2.colors); // ['blue','pink','yellow']
console.log(instance2.name); // wangli
缺点:同构造函数一样,无法实现方法的复用(所有的方法会被重复创建一份)
组合使用原型链和借用构造函数,混合模式
我们会组合使用原型链继承和借用构造函数来实现继承。也就是说,使用原型链实现对原型属性和方法的继承,
而通过借用构造函数来实现对实例属性的继承。这样,既通过在原型上定义方法实现了函数复用,又能够保证每个实例都有它自己的属性。
//组合使用原型链和借用构造函数
// 父类构造函数
function Person1(name,age,job){
this.name=name;
this.age=age;
this.job=job;
}
// 父类方法
Person1.prototype.saypname=function(){
console.log(this.name);
}
// 子类构造函数
function Student(name,age,job,school){
Person1.call(this,name,age,job);//继承父级的属性
this.school=school;
}
//createObject()对传入其中的对象执行了一次浅复制。
function createObject(proto) {
function F() { }
F.prototype = proto;
return new F();
}
// 继承父类的原型方法(获得父类原型链上的方法)
Student.prototype = createObject(Person1.prototype);
Student.prototype.constructor=Student;// 设置 constructor 属性指向 Student
// 子类方法
Student.prototype.sayschool=function(){
console.log(this.school);
}
var person1 = new Person1('wangli', 27, 'Student');
var student1=new Student('Lili','16','学生','第一实验中学');
var student2=new Student('Excellent','17','学生','第二实验中学');
person1.saypname();//wangli
student1.saypname();//Lili
student1.sayschool();//第一实验中学
student2.saypname();//Excellent
我们用些更简单的东西去解决,比如ES6中的面向对象语法
S6中引入了一套新的关键字用来实现class。
但它并不是映入了一种新的面向对象继承模式。JavaScript仍然是基于原型的,这些新的关键字包括class、
constructor、
static、
extends、
和super。
class关键字不过是提供了一种在本文中所讨论的基于原型模式和构造器模式的面向对象的继承方式的语法糖(syntactic sugar)。
前面继承修改
//ES6 class关键字 面向对象的继承方式的语法糖(syntactic sugar)。
"user strict";
class Person2{
constructor(name,age,job){
this.name=name;
this.age=age;
this.job=job;
}
sayName(){
console.log(this.name);
}
}
class Student2 extends Person2{
constructor(name,age,job,school){
super(name,age,job,"Studen2");
this.school=school;
}
saySchool(){
console.log(this.school);
}
}
var stu1 = new Student2('weiwei', 20,'学生','Southeast University');
var stu2 = new Student2('lily', 22, '学生','Nanjing University');
stu1.sayName(); // weiwei
stu1.saySchool(); // Southeast University
stu2.sayName(); // lily
stu2.saySchool(); // Nanjing University
如果还有不太了解ES6的,可以看看阮一峰Es6入门:http://es6.ruanyifeng.com/
了解更多js知识,也可以到这里看:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript
深入解读 Js 中的面向对象编程的更多相关文章
- Day046--JavaScript-- DOM操作, js中的面向对象, 定时
一. DOM的操作(创建,追加,删除) parentNode 获取父级标签 nextElementSibling 获取下一个兄弟节点 children 获取所有的子标签 <!DOCTYPEhtm ...
- 前端 ---JS中的面向对象
JS中的面向对象 创建对象的几种常用方式 1.使用Object或对象字面量创建对象 2.工厂模式创建对象 3.构造函数模式创建对象 4.原型模式创建对象 1.使用Object或对象字面量创建对象 ...
- python 全栈开发,Day52(关于DOM操作的相关案例,JS中的面向对象,定时器,BOM,client、offset、scroll系列)
昨日作业讲解: 京东购物车 京东购物车效果: 实现原理: 用2个盒子,就可以完整效果. 先让上面的小盒子向下移动1px,此时就出现了压盖效果.小盒子设置z-index压盖大盒子,将小盒子的下边框去掉, ...
- 前端JavaScript(3)-关于DOM操作的相关案例,JS中的面向对象、定时器、BOM、位置信息
小例子: 京东购物车 京东购物车效果: 实现原理: 用2个盒子,就可以完整效果. 先让上面的小盒子向下移动1px,此时就出现了压盖效果.小盒子设置z-index压盖大盒子,将小盒子的下边框去掉,就可以 ...
- 《JS中的面向对象技术》
内容要点: 1.什么是对象:JS权威指南学习总结-第六章 ,(有句话:一切都是对象) 2.什么面向对象 使用对象时,只关注对象提供的功能,不关注其内部细节,比如jQuery.面向对象是一种通用思想,并 ...
- 洗礼灵魂,修炼python(41)--巩固篇—从游戏《绝地求生-大逃杀》中回顾面向对象编程
声明:本篇文章仅仅以游戏<绝地求生>作为一个参考话题来介绍面向对象编程,只是作为学术引用,其制作的非常简易的程序也不会作为商业用途,与蓝洞公司无关. <绝地求生>最近很火,笼络 ...
- JavaScript中的面向对象编程,详解原型对象及prototype,constructor,proto,内含面向对象编程详细案例(烟花案例)
面向对象编程: 面向:以什么为主,基于什么模式 对象:由键值对组成,可以用来描述事物,存储数据的一种数据格式 编程:使用代码解决需求 面向过程编程: 按照我们分析好的步骤,按步 ...
- 深入理解javascript中实现面向对象编程方法
介绍Javascript中面向对象编程思想之前,需要对以下几个概念有了解: 1. 浅拷贝和深拷贝:程序在运行过程中使用的变量有在栈上的变量和在堆上的变量,在对象或者变量的赋值操作过程中,大多数情况先是 ...
- python中的面向对象编程
在python中几乎可以完成C++里所有面向对象编程的元素. 继承:python支持多继承: class Derived(base1, base2, base3): pass 多态:python中的所 ...
随机推荐
- 面向对象的线程池Threadpool的封装
线程池是一种多线程处理形式,预先创建好一定数量的线程,将其保存于一个容器中(如vector), 处理过程中将任务添加到队列,然后从容器中取出线程后自动启动这些任务,具体实现如下. 以下是UML图,展示 ...
- Ubuntu 11.04安装arm-linux-gcc-4.4.3/arm-none-linux-gnueabi-gcc安装包
准备工具和系统 arm-linux-gcc-4.4.3.tar.gz arm-linux-gcc-4.4.3下载地址: 下载在Linux公社的1号FTP服务器里,下载地址: FTP地址:ftp://w ...
- java定时任务(三):timerTask定时任务
这种方式是纯粹的java代码,需要继承timerTask接口并重写run方法,创建这个类的时候就会调用run方法. 基本的使用逻辑是: 把自己需要处理的业务逻辑放在自己写的这个继承了timerTask ...
- windows下python3.4安装lxml提示"Unable to find vcvarsall.bat"
"https://pypi.python.org/pypi/lxml/3.6.0"从这个网址直接下载对应的lxml包,exe格式的,直接安装,问题解决!
- Extjs 4.0 Tab页
1.JSON代码 Ext.MyTabs=Ext.extend(Ext.TabPanel ,{ xtype:"tabpanel", activeTab:2, width:694, h ...
- VxWorks启动流程
镜像种类不同,VxWorks的启动过程会有所不同. 我们项目中使用的是加载型VxWorks镜像 函数 函数功能 所在文件 bootTask() (a) 通过createBootLineFromF ...
- ArgumentError: Error #1063: BasicChart/dataFunc() 的参数数量不匹配。应该有 2 个,当前为 3 个。
1.错误描述 ArgumentError: Error #1063: BasicChart/dataFunc() 的参数数量不匹配.应该有 2 个,当前为 3 个. at mx.charts.char ...
- jquery 获取上传图片的大小(或者本张图片的其它属性)
<input type="file" name="upload" style="display:none;" src="${ ...
- 说说你对用SSH框架进行开发的理解
SSH框架指的是Struts,Spring,Hibernate.其中,Struts主要用于流程控制:Spring的控制反转能祈祷解耦合的作用:Hibernate主要用于数据持久化.
- SVN的安装以及和eclipse的结合使用
SVN概述 l 通常软件开发由多人协作开发,如果对代码文件.配置文件.文档等没有进行版本控制,将会出现很多问题: l 备份多个版本,占用磁盘空间大 l 解决代码冲突困难 l 容易引发BUG l 难于追 ...