
- 作 用
- 软件开发
- 使用领域
- CAD技术、人工智能等
- 中文名
- 面向对象
- 外文名
- Object Oriented
-
2022-05-05 15:48:09
如何实现面向对象
面向对象的定义
对象是指具体的某一事物,在现实生活中能够看得见摸得着的事物。在面向对象程序设计中,对象指的是计算机系统中的某一个成分。
在面向对象程序设计中,对象包含两个含义,其中一个是数据,另一个是动作。对象是数据和动作的结构体。
面向对象是在对象这一层次。面向对象的三大特征、面向对象的基础
封装、继承、多态
封装:在面向对象中,对数据和动作进行包装,其中的某些数据动作,可以是私有的,不能被外界访问,以此来实现对数据和动作不同级别的访问权限进行信息隐藏防止程序相互依赖带来的变动和影响。
继承:在面向对象中,继承可以说是一种层次模型,这种层次模型能够被重用。层次结构的上层具有通用性,但是下层结构具有特殊性。在继承的过程中子类(下层结构)可以从父类(上层结构)中继承一些动作和数据.子类除了可以继承以外,自己也可以添加自己的数据和动作。
多态:指的是不同事物具有不同表现形式的能力。多态是指不同的子类在继承父类后分别都重写覆盖了父类的方法,即父类同一个方法,在继承的子类中表现出不同的形式。面向对象的基础:抽象
为什么说面向对象的基础是抽象呢?
抽象从众多事物中抽取出共同特征的过程,在面向对象中,我们将数据和动作抽象出来进行封装、有了封装才有了继承,有了继承才有了多态。实现面向对象
基本准则
1)我们要注重多少人来干事,而不是干多少事。
2)我们要注重谁来干事,而不是怎么干事。
在抽象的过程中,我们要注重的是对象,而不是过程实例
业务:打水
对打水这个业务进行面向对象。第一步抽象(罗列):对象包括:打水人、打水地点、打水工具、受水人。
第二步抽象:参与者(打水人、受水人)、场所、打水工具。在抽象的过程中,我们要注重的是对象,而不是过程
更多相关内容 -
易康eCognition面向对象分类详细步骤
2018-06-04 11:03:53易康软件面向对象分类,PDF格式,支持下载。可用于遥感影像分类 -
设计模式 - 可复用面向对象软件的基础(高清版PDF)
2018-09-26 11:27:13设计模式 - 可复用面向对象软件的基础(高清版PDF)设计模式可复用面向对象软件的基础高清版 -
JS面向对象
2021-08-02 10:19:47第一节 面向对象的思想概述 什么类和对象 了解 第二节 类和对象 什么是类和对象 了解 创建对象 了解 属性和方法 了解 第三节 原型 什么是原型 掌握 第四节 原型链 原型链 掌握 第五节 原型继承 原型...类、对象、原型与设计模式
本节主要内容:
(文章转载自乐字节)
学习目标:
节数 知识点 要求 第一节 面向对象的思想概述 什么类和对象 了解 第二节 类和对象 什么是类和对象 了解 创建对象 了解 属性和方法 了解 第三节 原型 什么是原型 掌握 第四节 原型链 原型链 掌握 第五节 原型继承 原型继承 掌握 第六节 设计模式 设计模式 掌握 第七节 this总结 this问题总结 掌握 问题思考:求两个数的和
方案:
1、pop:需要两个变量保存两个数,
需要一个算式计算求和,
需要一个变量保存结果
需要一个打印语句输出结果。
var a=1;
var b=2;
var sum = a+b;
console.log(sum);
2、利用函数求两数之和:
function sum(x,y){
return x + y;
}
3、oop:封装,继承,多态
private(私有的),public(公有的),protected(受保护的)
4、需要两个变量保存两个数
需要创建一个对象
对象中需要一个能计算加和的方法
对象中这个方法需要能打印计算结果
调用对象执行这个方法
var obj = { sum:function(num1,num2){ console.log(num1+num2); } } obj.sum(10,20);
面向对象思想概述
面向对象程序设计(Object-oriented programming,缩写:OOP)是种具有对象概念的程序编程典范,同时也是一种程序开发的抽象方针。它可能包含数据、属性、与方法。对象则指的是类的实例。它将对象作为程序的基本单元,将程序和数据封装其中,以提高软件的重用性、灵活性和扩展性,对象里的程序可以访问经常修改对象相关连的数据。
举个最简单点的例子来区分 面向过程和面向对象
有一天你想吃鱼香肉丝了,怎么办呢?你有两个选择
1、自己买材料,肉,鱼香肉丝调料,蒜苔,胡萝卜等等然后切菜切肉,开炒,盛到盘子里。
2、去饭店,张开嘴:老板!来一份鱼香肉丝!
看出来区别了吗?这就是1是面向过程,2是面向对象。
面向对象有什么优势呢?首先你不需要知道鱼香肉丝是怎么做的,降低了耦合性。如果你突然不想吃鱼香肉丝了,想吃洛阳白菜,对于1你可能不太容易了,还需要重新买菜,买调料什么的。对于2,太容易了,大喊:老板!那个鱼香肉丝换成洛阳白菜吧,提高了可维护性。总的来说就是降低耦合,提高维护性!
oop:则会创建一个对象,让对象拥有做某件事情的能力(给对象属性和方法)。
然后命令对象做某件事。(封装、继承、多态)
面向过程——步骤化
面向过程就是分析出实现需求所需要的步骤,通过函数一步一步实现这些步骤,接着依次调用即可
面向对象——行为化
面向对象是把整个需求按照特点、功能划分,将这些存在共性的部分封装成对象,创建了对象不是为了完成某一个步骤,而是描述某个事物在解决问题的步骤中的行为。
面向过程:
优点:性能比面向对象好,因为类调用时需要实例化,开销比较大,比较消耗资源。
缺点:不易维护、不易复用、不易扩展.面向对象:
优点:易维护、易复用、易扩展,由于面向对象有封装、继承、多态性的特性,可以设计出低耦合的系统,使系统 更加灵活、更加易于维护 .
缺点:性能比面向过程差类和对象
JavaScript 中的所有事物都是对象:字符串(new String)、布尔(new Boolean())、数值(Number)、数组(Array)、函数(Function)等。
类:就是具有相同的属性和方法的集合。人类,动物类,家电类等。
对象:就类中的一个具体的实物。人类-具体某一个人(张三丰)。
动物类-(一个具体的动物-东北虎),家电类-(具体一个比如说电视。)
js 中我们包含哪些对象呢?
-
内置对象(本地对象):Math对象,Number对象,Date对象等,系统给我们提供好的,我们拿过来用就可以了。
-
宿主对象:dom(文档对象模型),bom(浏览器对象)。
-
自定义对象:我们自己定义和开发的对象。
对象(object)是大括号定义的无序的数据集合,由键值对构成,键与值之间用冒号分隔,大括号末尾要使用分号表示对象定义结束。
什么是类和对象
1.类是具有相同的属性和方法的集合。
2.对象是类中具体一个实例。
类是一种抽象的,并不实际存在的,表示一种事物共有特征的描述。
对象是一种具体的,实际存在的,类中的某一个个体。
创建对象
字面式对象
1、声明字面式对象
语法: var 对象={};
2、调用对象的成员:属性和方法
(1)对象.属性,对象.方法()
(2)对象[‘属性’],对象[‘方法’]()
3、给对象添加属性和方法
对象.属性,对象.方法()
通过Object类创建对象
Object类是所有类的父类。
总结说明:Object,O要大写
语法:var obj=new Object();
属性和方法
私有属性和私有方法
私有属性 : 在对象的定义中定义的非全局变量
构造函数:能够实例化对象的函数,就是构造函数
私有的属性,对象不能直接访问,必须通过公有的方法才可以访问私有的属性。
function Person(firstName,lastName){ var name=firstName+" "+lastName;//私有属性-private this.getFullName =function(){//公有方法-public return name; } } var person=new Person("Si" ,"Li");//**实例化一个对象** alert(person.getFullName()); alert(person.name); //undefined
公有属性和公有方法
实例(公有)属性 : 使用this为对象附加实例属性/对象名称.属性名
function Person(name,sex,num){
this.name=name;
this[“sex”]=sex;
this[‘50’]=num;
}
var person1=new Person(“lisi”,“男”,11);
person1.age=22;
alert(person1.name);//lisi
alert(person1[“sex”]);//男
alert(person1[‘50’]);//11
alert(person1.age);//22
类的属性和方法
类属性 : "类"名.属性名/类名.prototype.属性名
function Person (){};
Person.name=“lisi”;//这种方式定义的属性,类的实例不能访问;只能通过 类名.属性名访问
alert(Person.name)
实例:使用字面量对象创建一个div元素并添加样式
原型(重点)
任何对象都是默认存在构造器的,此时我们的Person()只是普通函数,它其实是js内置方法Function()构造出来的,而p此时是Person() new出来的,只有new 过了,才叫构造函数
原型引入:不使用原型,
解决办法:
任何一个函数都有一个原型的属性。
在js中任何一个函数都有一个prototype属性,原型(prototype)就是函数的一个属性,它指向一个对象。
原型的作用其实就是为类(函数)提供了一个【公共区域】,在这个公共区域中声明的属性和方法能够被所有通过这个类所创建的对象所访问到。减少内存消耗。
ps:在原型中声明的属性和方法,有时也被称为是类的公有属性和公有方法
原型是一个对象,在原型中通常拥有两个属性:
(1)构造器constructor:该属性指向了这个类(函数)本身
(2)原型指向__proto__:该属性指向原型本身,提供给通过类创建的对象使用。
原型分为隐式原型和显式原型
所有引用类型(函数,数组,对象)的实例对象都拥有**__proto__属性(隐式原型)**
所有函数都拥有prototype属性(显式原型)(仅限函数)
也就是说每个函数都有一个prototype属性,每个对象都有一个__proto__属性。
原型的使用
原型对象(p1.__proto__)就是构造函数的原型(person.prototype)
实例:使用原型来求圆的面积
实例:利用原型给数组对象添加一个方法,这个方法实现给成绩从小到大排序。
什么是原型链
由【对象的__proto__属性】和【对象的构造函数的原型的__proto__属性】构成的链式结构称为原型链。
ps:原型链的顶端是Object对象。
pss:Object对象没有__proto__属性,或者说Object对象的__proto__属性指向了自身。
function Person(userName, sex) { this.userName = userName; this.sex = sex; } var df = new Person('杜甫','男'); Object.prototype.show = '呵呵'; console.log(df.show); //对象构造函数的原型 console.log(df.__proto__); //对象构造函数原型的原型 --->Object的原型 console.log(df.__proto__.__proto__); //Object已经到达 顶层 没有比他更高的类 console.log(df.__proto__.__proto__.__proto__); // console.log(df.__proto__.__proto__==Object.prototype);
构造函数继承
原型继承(重点)
函数.prototype.成员名称=值 //继承的单一成员
函数.prototype=对象 //继承的是对象
组合继承
组合继承:指的就是构造函数继承和原型继承的组合。
设计模式(重点)
工厂模式
原型模式(prototype)
构造函数模式
构造函数 ,是一种特殊的方法。主要用来在创建对象时初始化对象, 即为对象成员变量赋初始值,总与new运算符一起使用在创建对象的语句中。
可以通过new命令,生成对象的函数称为构造函数。构造函数一般首字母大写。
例如:
function Car(lun1,lun2,lun3,lun4,abiliity){
this.lun1 = lun1;
this.lun2 = lun2;
this.lun3 = lun3;
this.lun4 = lun4;
this.ability = ability;
}
var myCar1 = new Car(‘左前轮1’, ‘右前轮1’, ‘左后轮1’, ‘右后轮1’, ‘会跑1’);
var myCar2 = new Car(‘左前轮2’, ‘右前轮2’, ‘左后轮2’, ‘右后轮2’, ‘会跑2’);
ps:new命令在这里的作用是先创建一个对象,然后让对象调用构造函数。
所以构造函数中的this指的是new创建的这个对象。
简单地说构造函数是类函数,函数名与类名完全相同
用new操作符创建对象时发生的事情:
(1)创建一个新对象;
(2)将构造函数的作用域赋给新对象(因此this就指向了这个新对象);
(3)执行构造函数中的代码(为这个新对象添加属性和方法);
(4)返回 this
通过new操作符后跟构造函数的方式创建的对象(实例),这个对象有一个constructor(构造函数)属性,该属性指向构造函数Person。
创建的对象,毫无疑问是Person的实例,同时也是Object的实例;所有对象皆继承自Object。
**注意:**原本的构造函数是window对象的方法,如果不用new操作符而直接调用,那么构造函数的执行对象就 是window,即this指向了window。现在用new操作符后,this就指向了新生成的对象。理解这一步至关重要。
如果被调用的函数没有显式的 return 表达式(仅限于返回对象),则隐式的会返回 this 对象 - 也就是新创建的对象。
function Person(username,age){
this.username = username;
this.age = age;
console.log(this.username,this.age,this);
}Person(“peter”,25);
一个对象就这么被创建出来了。
实际上,var p = new Person();
和
var p = new Object();
Person.apply§;
是一样的效果。构造函数也是函数
任何函数,只要通过new操作符来调用,那么它就可以作为构造函数;任何函数,如果不通过new操作符来调用,那它与普通函数并无区别。
(1)当做构造函数调用
var person = new Person(“CC”,23);
(2)当做普通函数使用
Person(“CC”,23); //添加到window对象
console.log(window.name); //“CC”
console.log(window.age); //23
(3)在另一个对象的作用域中调用
var person = new Object();
Person.call(person,“CC”,23);
console.log(person.name); //“CC”
console.log(person.age); //23
1.构造函数有什么用?
当你需要大批量的写对象的时候,就需要用到构造函数,它可以方便创建多个对象的实例,并且创建的对象可以被标识为特定的类型,可以通过继承扩展代码
2.构造函数的特点
a:构造函数的首字母必须大写,用来区分于普通函数
b:内部使用的this对象,来指向即将要生成的实例对象
c:使用New来生成实例对象
语法:函数类(构造函数)
function Person(){
This.name=”贾诩”;
This.sex=”男”;
}
普通函数:
function person(){
var name=”贾诩”;
var sex=”男”;
}
3、通过构造函数创建元素并添加样式
function Dom(){ this.odiv = document.createElement("div"); this.show = function(){ this.odiv.style.width = "200px"; this.odiv.style.height = "200px"; this.odiv.style.background = "red"; document.body.appendChild(this.odiv); } } var d1 = new Dom(); d1.show();
实例:小女孩走动
小女孩的运动-对象版
混合模式
混合模式:是构造函数模式和原型模式的混合
this总结
this代表【函数运行时】【自动生成的】一个【用来指代函数调用者】的对象,this只能在函数内部使用。
根本原则:函数的调用者是谁,this就是谁
this关键字可以说在js中使用频率是一个较高的东西,而this的使用场景更是复杂多样。
因此对于this,我们需要更好的掌握
下面是对于this的使用场景,我们都逐一学习和使用过。那么下面我们就来看一下this关键字在如下场景中都发挥了什么样子的作用。
(1)this在正常函数中: 谁调用了函数,this指向谁
(2)this在闭包中: 闭包中的this指向window
(3)间隔调用和延迟调用:间隔调用和延迟调用中的this指向window
(4)事件中的this
HTML:this指向window
DOM0:this指向绑定该事件的元素
DOM2级:IE指向window 非IE中指向指向绑定该事件的元素
(5)自执行函数: this指向window
(6)call和apply函数: 第一个参数是谁,this指向谁
this归纳:
1.在文档中直接使用this,this代表window对象
2.html事件处理程序中将this放在事件处理函数的实参位置,这个this代表window对象
3.DOM0级事件处理程序、DOM2级事件处理程序的事件函数中使用this,代表当前事件所处的元素
4.字面量形式创建的对象中,如果在函数内部使用this,这个this代表当前对象,如果不是在函数内部使用,则this代表window对象
5.构造方法中使用this(属性名称前面的this),代表构造方法创建出来的对象。如果是在函数中使用this,this代表调用该函数的实例
6.定时器中的this代表window对象
7.如果在原型的某个属性或方法中使用,这个this代表调用该方法的对象
8.借用构造方法继承时,在call和apply中使用this,这个this代表当前构造方法创建的实例
9.如果在闭包中使用this,this代表window对象(文章转载自乐字节)
-
-
UML面向对象建模与设计(第2版)
2012-01-18 14:34:23UML面向对象建模与设计(第2版)(“面向对象建模与设计”领域的经典著作) 作者: (美)Michael Blaha,James Rumbaugh [作译者介绍] 译者: 车皓阳 杨眉 上架时间:2006-1-24 本书是“面向对象建模与设计”领域的... -
python面向对象
2022-04-15 21:18:35一、面向过程和面向对象 1.面向过程:是一种以事件为中心的编程思想,更关注过程。简单的问题可以用面向过程的思路来解决,直接有效,但是当问题的规模变得更大时,用面向过程的思想是远远不够的。所以慢慢就出现了...一、面向过程和面向对象
1.面向过程:是一种以事件为中心的编程思想,更关注过程。简单的问题可以用面向过程的思路来解决,直接有效,但是当问题的规模变得更大时,用面向过程的思想是远远不够的。所以慢慢就出现了面向对象的编程思想。
优点:性能比面向对象高,因为类调用时需要实例化,开销比较大,比较消耗资源;比如单片机、嵌入式开发、 Linux/Unix等一般采用面向过程开发,性能是最重要的因素。
缺点:不易维护、复用和拓展
2.面向对象:世界上的每个人或事务都能看成一个对象,每个对象都有自己的属性和行为,对象与对象之间通过方法来交互。面向对象是一种以“对象”为中心的编程思想,把要解决的问题分解成各个对象,建立对象的目的不是为了完成一个步骤,而是为了描叙某个对象在整个解决问题的步骤中的属性和行为。优点:易维护、易复用、易扩展,由于面向对象有封装、继承、多态性的特性,可以设计出低耦合的系统,使系统 更加灵活、更加易于维护
缺点:性能比面向过程低
3.扩展:高内聚、低耦合①内聚:模块内部的代码,例如方法,变量,对象,或者是功能模块。相互之间的联系越强,内聚就越高,模块的独立性就越好。一个模块应该尽量的独立,去完成独立的功能
②耦合:模块与模块之间有些操作是有关联的,例如水桶效应,一个水桶若是有一块木板比其他木板短,那么这个水桶装的水也就会相应减少,因此模块与模块之间的关系越是紧密,独立性就越不好,就容易产生连锁反应
③模块:就是将大型系统的复杂问题,分成不同的小模块,去处理问题
二、类和对象
1.类:
①定义:类是抽象的,在使用的时候通常会找到这个类的一个具体的存在,使用这个具体的存在。一个类可以找到多个对象
②构成:三部分
类的名称:类名
类的属性:一组数据
类的方法(行为):允许对其进行操作的方法
③举例:人类名称:人
属性:姓名、身高、年纪
方法:吃饭、睡觉、上厕所
④抽象类:拥有相同(或者类似)属性和行为的对象都可以抽像出一个类⑤举例:小明在公交车上牵着一只叼着热狗的狗
小明 --- 人类
公交车 --- 交通工具类
热狗 --- 实物类
狗 --- 狗类
⑥格式:说明:
- object是Python里所有类的最顶级父类
- 类名的命名规则按照"大驼峰命名法"
- cat和dog是实例方法
- 第一个参数一般是self,表示实例对象本身,也可以使用其它的名字,其作用是设置一个变量,这个变量指向了实例对象
三.魔法方法:
1.介绍:Python的类里提供的,两个下划线开始,两个下划线结束的方法,就是魔法方法
2.__init__():
①定义:
__init__()就是一个魔法方法,通常用来做属性初始化或赋值操作,在实例化对象的时候会被自动调用
__init__(self)中的self参数,不需要开发者传递,python解释器会自动把当前的对象引用传递过去。
如果类面没有写__init__方法,Python会自动创建,但是不执行任何操作
一个类里无论自己是否编写__init__方法一定有__init__方法 -
JavaScript 进阶教程(1)--面向对象编程
2020-08-16 18:13:37理解面向对象开发思想 掌握 JavaScript 面向对象开发相关模式 2 面向对象介绍 2.1什么是对象 Everything is object (一切皆对象) 我们可以从两个层次来理解对象: (1) 对象是单个事物的抽象。...目录
1 学习目标
-
理解面向对象开发思想
-
掌握 JavaScript 面向对象开发相关模式
2 面向对象介绍
2.1 什么是对象
Everything is object (一切皆对象)
我们可以从两个层次来理解对象:
(1) 对象是单个事物的抽象。
一本书、一辆汽车、一个人都可以是对象,一个数据库、一张网页、一个与远程服务器的连接也可以是对象。当实物被抽象成对象,实物之间的关系就变成了对象之间的关系,从而就可以模拟现实情况,针对对象进行编程。
(2) 对象是一个容器,封装了属性(property)和方法(method)。
属性是对象的状态,方法是对象的行为(完成某种任务)。比如,我们可以把动物抽象为animal对象,使用“属性”记录具体是那一种动物,使用“方法”表示动物的某种行为(奔跑、捕猎、休息等等)。
在实际开发中,对象是一个抽象的概念,可以将其简单理解为:数据集或功能集。ECMAScript-262 把对象定义为:无序属性的集合,其属性可以包含基本值、对象或者函数。 严格来讲,这就相当于说对象是一组没有特定顺序的值。对象的每个属性或方法都有一个名字,而每个名字都 映射到一个值。
提示:每个对象都是基于一个引用类型创建的,这些类型可以是系统内置的原生类型,也可以是开发人员自定义的类型。
2.2 什么是面向对象
面向对象不是新的东西,它只是过程式代码的一种高度封装,目的在于提高代码的开发效率和可维护性。
面向对象编程 —— Object Oriented Programming,简称 OOP ,是一种编程开发思想。 它将真实世界各种复杂的关系,抽象为一个个对象,然后由对象之间的分工与合作,完成对真实世界的模拟。
在面向对象程序开发思想中,每一个对象都是功能中心,具有明确分工,可以完成接受信息、处理数据、发出信息等任务。 因此,面向对象编程具有灵活、代码可复用、高度模块化等特点,容易维护和开发,比起由一系列函数或指令组成的传统的过程式编程(procedural programming),更适合多人合作的大型软件项目。
面向对象与面向过程区别:
-
面向过程就是亲力亲为,事无巨细,面面俱到,步步紧跟,有条不紊。
-
面向对象就是找一个对象,指挥得结果。
-
面向对象将执行者转变成指挥者。
-
面向对象不是面向过程的替代,而是面向过程的封装。
面向对象的特性:
-
封装性
-
继承性
-
多态性
扩展阅读:
2.3 JavaScript 中面向对象的基本体现
在 JavaScript 中,所有数据类型都可以视为对象,当然也可以自定义对象。 自定义的对象数据类型就是面向对象中的类( Class )的概念。
我们以一个例子来说明面向过程和面向对象在程序流程上的不同之处。
假设我们要处理学生的成绩表,为了表示一个学生的成绩,面向过程的程序可以用一个对象表示:
var std1 = { name: '张三', score: 98 } var std2 = { name: '李四', score: 81 }
而处理学生成绩可以通过函数实现,比如打印学生的成绩:
function printScore (student) { console.log('姓名:' + student.name + ' ' + '成绩:' + student.score) }
如果采用面向对象的程序设计思想,我们首选思考的不是程序的执行流程, 而是
Student
这种数据类型应该被视为一个对象,这个对象拥有name
和score
这两个属性(Property)。 如果要打印一个学生的成绩,首先必须创建出这个学生对应的对象,然后,给对象发一个printScore
消息,让对象自己把自己的数据打印出来。抽象数据行为模板(Class):
function Student (name, score) { this.name = name this.score = score } Student.prototype.printScore = function () { console.log('姓名:' + this.name + ' ' + '成绩:' + this.score) }
根据模板创建具体实例对象(Instance):
var std1 = new Student('张三', 98) var std2 = new Student('李四', 81)
实例对象具有自己的具体行为(给对象发消息):
std1.printScore() // => 姓名:张三 成绩:98 std2.printScore() // => 姓名:李四 成绩 81
面向对象的设计思想是从自然界中来的,因为在自然界中,类(Class)和实例(Instance)的概念是很自然的。 Class 是一种抽象概念,比如我们定义的 Class——Student ,是指学生这个概念, 而实例(Instance)则是一个个具体的 Student ,比如, 张三 和 李四 是两个具体的 Student 。
面向对象的设计思想是:
-
抽象出 Class
-
根据 Class 创建 Instance
-
指挥 Instance 得结果
面向对象的抽象程度比函数要高,因为一个 Class 既包含数据,又包含操作数据的方法。
3 JavaScript 如何创建对象
3.1 字面量方式
我们可以直接通过
new Object()
创建:var person = new Object() person.name = '张三' person.age = 18 person.sayName = function () { console.log(this.name) }
每次创建通过
new Object()
比较麻烦,所以可以通过它的简写形式对象字面量来创建:var person = { name: '张三', age: 18, sayName: function () { console.log(this.name) } }
上面的写法是没有问题的,但是假如我们要生成两个
person
实例对象呢?var person1 = { name: '张三', age: 18, sayName: function () { console.log(this.name) } } var person2 = { name: '李四', age: 16, sayName: function () { console.log(this.name) } }
通过上面的代码我们不难看出,这样写的代码太过冗余,重复性太高。
3.2 简单方式的改进:工厂函数
我们可以写一个函数,解决上边代码重复的问题:
function createPerson (name, age) { return { name: name, age: age, sayName: function () { console.log(this.name) } } }
生成实例对象:
var p1 = createPerson('张三', 18) var p2 = createPerson('李四', 18)
这样封装比上边的方式好多了,通过工厂模式我们解决了创建多个相似对象代码冗余的问题, 但却没有解决对象识别的问题(即怎样知道一个对象的类型)。
3.3 更优雅的工厂函数:构造函数
一种更优雅的工厂函数就是下面这样,构造函数:
function Person (name, age) { this.name = name this.age = age this.sayName = function () { console.log(this.name) } } var p1 = new Person('张三', 18) p1.sayName() // => 张三 var p2 = new Person('李四', 23) p2.sayName() // => 李四
在上面的示例中,
Person()
函数取代了createPerson()
函数,但是实现效果是一样的。 这是为什么呢?我们注意到,
Person()
中的代码与createPerson()
有以下几点不同之处:-
没有显示的创建对象
-
直接将属性和方法赋给了
this
对象 -
没有
return
语句 -
函数名使用的是大写的
Person
3.4 构造函数代码执行过程
要创建
Person
实例,则必须使用new
操作符。 以这种方式调用构造函数会经历以下 4 个步骤:-
创建一个新对象。
-
将构造函数的作用域赋给新对象(因此 this 就指向了这个新对象)。
-
执行构造函数中的代码。
-
返回新对象。
下面是具体的伪代码:
function Person (name, age) { // 当使用 new 操作符调用 Person() 的时候,实际上这里会先创建一个对象 // var instance = {} // 然后让内部的 this 指向 instance 对象 // this = instance // 接下来所有针对 this 的操作实际上操作的就是 instance this.name = name this.age = age this.sayName = function () { console.log(this.name) } // 在函数的结尾处会将 this 返回,也就是 instance // return this }
3.5 构造函数和实例对象的关系
使用构造函数的好处不仅仅在于代码的简洁性,更重要的是我们可以识别对象的具体类型了。 在每一个实例对象中的_proto_中同时有一个
constructor
属性,该属性指向创建该实例的构造函数:console.log(p1.constructor === Person) // => true console.log(p2.constructor === Person) // => true console.log(p1.constructor === p2.constructor) // => true
对象的
constructor
属性最初是用来标识对象类型的, 但是,如果要检测对象的类型,还是使用instanceof
操作符更可靠一些:console.log(p1 instanceof Person) // => true console.log(p2 instanceof Person) // => true
总结:
1 构造函数是根据具体的事物抽象出来的抽象模板。
2 实例对象是根据抽象的构造函数模板得到的具体实例对象。
3 每一个实例对象都具有一个
constructor
属性,指向创建该实例的构造函数。( 此处constructor
是实例的属性的说法不严谨,具体后面的原型会讲到)4 可以通过实例的
constructor
属性判断实例和构造函数之间的关系。(这种方式不严谨,推荐使用instanceof
操作符,后面学原型会解释为什么)3.6 构造函数的问题
使用构造函数带来的最大的好处就是创建对象更方便了,但是其本身也存在一个浪费内存的问题:
function Person (name, age) { this.name = name this.age = age this.type = '学生' this.sayHello = function () { console.log('hello ' + this.name) } } var p1 = new Person('王五', 18) var p2 = new Person('李四', 16)
上边的代码,从表面看上好像没什么问题,但是实际上这样做,有一个很大的弊端。 那就是对于每一个实例对象,
type
和sayHello
都是一模一样的内容, 每一次生成一个实例,都必须为重复的内容,多占用一些内存,如果实例对象很多,会造成极大的内存浪费。console.log(p1.sayHello === p2.sayHello) // => false
对于这种问题我们可以把需要共享的函数定义到构造函数外部:
function sayHello = function () { console.log('hello ' + this.name) } function Person (name, age) { this.name = name this.age = age this.type = '学生' this.sayHello = sayHello } var p1 = new Person('王五', 18) var p2 = new Person('李四', 16) console.log(p1.sayHello === p2.sayHello) // => true
这样确实可以了,但是如果有多个需要共享的函数的话就会造成全局命名空间冲突的问题。如何解决这个问题呢?你肯定想到了可以把多个函数放到一个对象中用来避免全局命名空间冲突的问题:
var fns = { sayHello: function () { console.log('hello ' + this.name) }, sayAge: function () { console.log(this.age) } } function Person (name, age) { this.name = name this.age = age this.type = '学生' this.sayHello = fns.sayHello this.sayAge = fns.sayAge } var p1 = new Person('王五', 18) var p2 = new Person('李四', 16) console.log(p1.sayHello === p2.sayHello) // => true console.log(p1.sayAge === p2.sayAge) // => true
至此,我们利用自己的方式基本上解决了构造函数的内存浪费问题。 但是代码看起来还是那么的格格不入,那有没有更好的方式呢?
4 原型
4.1 更好的解决方案:
prototype
Javascript 规定,每一个构造函数都有一个
prototype
属性,指向另一个对象。 这个对象的所有属性和方法,都会被构造函数的实例继承。这也就意味着,我们可以把所有对象实例需要共享的属性和方法直接定义在
prototype
对象上。function Person (name, age) { this.name = name this.age = age } console.log(Person.prototype) Person.prototype.type = '学生' Person.prototype.sayName = function () { console.log(this.name) } var p1 = new Person(...) var p2 = new Person(...) console.log(p1.sayName === p2.sayName) // => true
这时所有实例的
type
属性和sayName()
方法, 其实都是同一个内存地址,指向prototype
对象,因此就提高了运行效率。构造函数、实例、原型三者之间的关系:
任何函数都有一个
prototype
属性,该属性是一个对象。function F () {} console.log(F.prototype) // => object F.prototype.sayHi = function () { console.log('hi!') }
构造函数的
prototype
对象默认都有一个constructor
属性,指向prototype
对象所在函数。console.log(F.constructor === F) // => true
通过构造函数得到的实例对象内部会包含一个指向构造函数的
prototype
对象的指针__proto__
。var instance = new F() console.log(instance.__proto__ === F.prototype) // => true
`__proto__` 是非标准属性。
实例对象可以直接访问原型对象成员:
instance.sayHi() // => hi!
总结:
-
任何函数都具有一个
prototype
属性,该属性是一个对象。 -
构造函数的
prototype
对象默认都有一个constructor
属性,指向prototype
对象所在函数。 -
通过构造函数得到的实例对象内部会包含一个指向构造函数的
prototype
对象的指针__proto__。
-
所有实例都直接或间接继承了原型对象的成员。
4.2 属性成员的搜索原则:原型链
了解了 构造函数-实例-原型对象 三者之间的关系后,接下来我们来解释一下为什么实例对象可以访问原型对象中的成员。
每当代码读取某个对象的某个属性时,都会执行一次搜索,目标是具有给定名字的属性。
-
搜索首先从对象实例本身开始。
-
如果在实例中找到了具有给定名字的属性,则返回该属性的值。
-
如果没有找到,则继续搜索指针指向的原型对象,在原型对象中查找具有给定名字的属性。
-
如果在原型对象中找到了这个属性,则返回该属性的值。
也就是说,在我们调用
person1.sayName()
的时候,会先后执行两次搜索:-
首先,解析器会问:“实例 person1 有 sayName 属性吗?”答:“没有。
-
然后,它继续搜索,再问:“ person1 的原型有 sayName 属性吗?”答:“有。
-
于是,它就读取那个保存在原型对象中的函数。
-
当我们调用 person2.sayName() 时,将会重现相同的搜索过程,得到相同的结果。
这就是多个对象实例共享原型所保存的属性和方法的基本原理。
总结:
-
先在自己身上找,找到即返回。
-
自己身上找不到,则沿着原型链向上查找,找到即返回。
-
如果一直到原型链的末端还没有找到,则返回
undefined。
4.3 实例对象读写原型对象成员
读取:
-
先在自己身上找,找到即返回。
-
自己身上找不到,则沿着原型链向上查找,找到即返回。
-
如果一直到原型链的末端还没有找到,则返回
undefined。
值类型成员写入(
实例对象.值类型成员 = xx
):-
当实例期望重写原型对象中的某个普通数据成员时实际上会把该成员添加到自己身上。
-
也就是说该行为实际上会屏蔽掉对原型对象成员的访问。
引用类型成员写入(
实例对象.引用类型成员 = xx
):同上。复杂类型修改(
实例对象.成员.xx = xx
):-
同样会先在自己身上找该成员,如果自己身上找到则直接修改。
-
如果自己身上找不到,则沿着原型链继续查找,如果找到则修改。
-
如果一直到原型链的末端还没有找到该成员,则报错(
实例对象.undefined.xx = xx
)。
4.4 更简单的原型语法
我们注意到,前面例子中每添加一个属性和方法就要敲一遍
Person.prototype
。 为减少不必要的输入,更常见的做法是用一个包含所有属性和方法的对象字面量来重写整个原型对象:function Person (name, age) { this.name = name this.age = age } Person.prototype = { type: '学生', sayHello: function () { console.log('我叫' + this.name + ',我今年' + this.age + '岁了') } }
在该示例中,我们将
Person.prototype
重置到了一个新的对象。 这样做的好处就是为Person.prototype
添加成员简单了,但是也会带来一个问题,那就是原型对象丢失了constructor
成员。所以,我们为了保持
constructor
的指向正确,建议的写法是:function Person (name, age) { this.name = name this.age = age } Person.prototype = { constructor: Person, // => 手动将 constructor 指向正确的构造函数 type: '学生', sayHello: function () { console.log('我叫' + this.name + ',我今年' + this.age + '岁了') } }
4.5 原生对象的原型
所有函数都有 prototype 属性对象。
- Object.prototype
- Function.prototype
- Array.prototype
- String.prototype
- Number.prototype
- Date.prototype
- ...
为数组对象和字符串对象扩展原型方法:
//为内置对象添加原型方法 //我们在系统的对象的原型中添加方法,相当于在改变源码 //我希望字符串中有一个倒序字符串的方法 String.prototype.myReverse = function() { for (var i = this.length - 1; i >= 0; i--) { console.log(this[i]); } }; var str = "abcdefg"; str.myReverse(); //为Array内置对象的原型对象中添加方法 Array.prototype.mySort = function() { for (var i = 0; i < this.length - 1; i++) { for (var j = 0; j < this.length - 1 - i; j++) { if (this[j] < this[j + 1]) { var temp = this[j]; this[j] = this[j + 1]; this[j + 1] = temp; } //end if } // end for } //end for }; var arr = [100, 3, 56, 78, 23, 10]; arr.mySort(); console.log(arr); String.prototype.sayHi = function() { console.log(this + "哈哈,我又变帅了"); }; //字符串就有了打招呼的方法 var str2 = "小杨"; str2.sayHi();
4.6 原型对象的一些问题
-
共享数组
-
共享对象
如果真的希望可以被实例对象之间共享和修改这些共享数据那就不是问题。但是如果不希望实例之间共享和修改这些共享数据则会出现问题。一个更好的建议是,最好不要让实例之间互相共享数组或者对象成员,一旦修改的话会导致数据的走向很不明确而且难以维护。
原型对象使用建议:
-
私有成员(一般就是非函数成员)放到构造函数中。
-
共享成员(一般就是函数)放到原型对象中。
-
如果重置了
prototype
记得修正constructor
的指向。
今天的学习就到这里,你可以使用今天学习的技巧来改善一下你曾经的代码,如果想继续提高,欢迎关注我,每天学习进步一点点,就是领先的开始。如果觉得本文对你有帮助的话,欢迎点赞,评论,转发!!!
-
-
python 面向对象全面详解
2019-01-12 14:25:23一、对面向对象的理解 1、面向对象的编程---object oriented programming 2、python面向对象的重要术语: 3、函数和面向对象编程的区别 二、封装、继承、多态 1、封装(Encapsulation) 2、继承(Inheritance... -
面向过程、基于对象、面向对象、分析
2022-05-13 16:11:54面向对象编程(Object Oriented Programming,OOP,面向对象程序设计)的主要思想是把构成问题的各个事务分解成各个对象,建立对象的目的不是为了完成一个步骤,而是为了描叙一个事物在整个解决问题的步骤中的行为。... -
《面向对象葵花宝典:思想、技巧与实践》样章
2015-12-22 10:29:03《面向对象葵花宝典:思想、技巧与实践》样章。 本书内容主要分为4部分: 面向对象基础:通过对面向对象的历史、发展,与面向过程的对比等相关背景知识的介绍,让读者对面向对象有一个更完整的认识;并深入地阐述了... -
面向对象基本概念
2019-02-06 21:56:15面向对象就是:把数据及对数据的操作方法放在一起,作为一个相互依存的整体——对象。对同类对象抽象出其共性,形成类。类中的大多数数据,只能用本类的方法进行处理。类通过一个简单的外部接口与外界发生关系,对象... -
面向过程和面向对象区别
2022-05-13 15:47:30面向对象:程序设计的重点是把构成问题的事物分解成对象,从局部着手,通过迭代的方式逐步构建出整个程序,是一种以数据为核心,以类设计为主的自下而上的程序设计方法。 (2)从适用范围来看。 面向过程:由于不... -
关于面向对象的真面目
2021-02-25 16:45:32关于面向对象的真面目 面向对象是软件开发的综合技术 我们先从一个简单的问题开始介绍。 “为什么要基于面向对象来开发软件?” 不管谁问这样的问题,笔者都会这样回答: “为了轻松地开发软件。” 可能有的人听到... -
Python程序设计 第7章:Python面向对象编程
2022-02-18 18:55:54Python程序设计 第7章:Python面向对象编程7.1 面向对象编程概述7.1.1 OOP的产生7.1.2 OOP核心思想7.1.3 OOP特征7.2 类和对象7.2.1 类的创建7.2.2 对象的创建7.2.3 类的属性7.2.4 类的方法7.2.5 内部类7.2.6 魔术... -
【C/C++面试必备】面向对象与面向过程的区别
2021-07-14 07:29:01这篇文章来说下面向对象编程! 那什么是面向对象编程呢? 是这样? 还是这样? 当然,都不是! 介绍面向对象之前,那必须先说一下面向过程。 什么是面向过程呢? 面向过程(Procedure-Oriented ... -
面向对象的基础-抽象
2022-05-05 19:35:35面向对象的三大特征? 封装、继承、多态 面向对象的基础是什么? 抽象 为什么说抽象是面向对象的基础? 先来看两句话: 1、我们要注重多少人干事,而不是干多少事 2、我们要注重谁来干事,而不是怎么干事... -
为什么面向对象糟透了?
2019-09-26 14:57:49Lisp 赞赏地点头, C语言向Java投去了钦佩的目光,这家伙经常做面向对象的设计,还是有两把刷子的,他通过特性的方式把变化给隔离了, 各个特性可以通过组合的方式,像插件一样随意替换, 嗯,这才是面向对象的真正... -
JavaScript高级教程(面向对象编程)
2022-01-14 09:13:01面向对象编程 有两大编程思想:面向过程和面向对象; 面向过程编程POP(Process-oriented programming) 面向过程即分析出解决问题所需要的步骤,然后用函数将这些步骤一步步实现,使用的时候再一个个的一次调用就... -
面向对象程序设计
2020-12-09 15:37:28之前复习面向对象的时候整理的,丢出来一起分享一下。因为复习得很赶,只是大致的整理,且大部分图片来自老师的ppt,可能不是很准确。如果要详细了解其中的某个知识点请另外搜索。 但是老师不讲武德啊,明明提纲给了... -
写给大家看的面向对象编程书(第3版).pdf
2012-12-31 11:26:23《写给大家看的面向对象编程书(第3版)》是一部独具特色的面向对象技术著作。书中结合代码示例生动透彻地讲述了面向对象思想的精髓,让读者真正学会以对象方式进行思考。此外,《写给大家看的面向对象编程书(第3版)》... -
面向对象和面向过程
2019-03-07 22:19:30什么是面向对象? 如果面试的时候问面向对象和面向过程的区别,就用Action、Service、 Dao去答。 1.什么是面向过程 仔细思考一下,我们在学习和工作中,当我们去实现某项功能或 完成某项任务时,是不是会... -
C++面向对象程序设计 面向对象编程
2018-09-12 22:39:501.1 面向过程的编程风格与面向对象的编程风格 C语言是面向过程语言,也称为命令型语言,面向过程通常采用自顶向下设计,问题复杂时不断运用自顶向下设计(即函数分解法)直到容易处理。自顶向下设计优点是直观有... -
面向对象
2018-05-19 16:59:57Java语言的面向对象技术包括了面向对象和面向过程的基本概念,面向对象的特征,Java语言的类,对象,修饰符,抽象类等一系列的知识点首先让我们来了解一下什么是对象? 没错!面向对象我们肯定需要先知道对象到底是... -
( UML面向对象建模与设计(第二版)【出版日期2011.7】
2012-12-26 12:46:06【书名】 UML面向对象建模与设计(第二版) 【作 者】(美)布莱哈,(美)朗博著 【出版发行】 北京市:人民邮电出版社 , 2011.06 【ISBN号】978-7-115-22424-8 【页 数】 378 ; 26cm 【原书定价】59.00 【内容提要... -
C++之面向对象
2022-03-23 17:46:17面向对象的三大特性:封装、继承、多态。 首先我们先介绍一下 面向对象的建立: class 类名{ //类里面包含 属性和行为 //属性和行为可以分成三种状态:public protected private; //属性就是定义数值、行为就是函数... -
C 语言实现面向对象编程
2018-08-14 18:36:38C 语言实现面向对象编程 1、引言 面向对象编程(OOP)并不是一种特定的语言或者工具,它只是一种设计方法、设计思想。它表现出来的三个最基本的特性就是封装、继承与多态。很多面向对象的编程语言已经包含这三... -
什么是面向对象编程?面向对象和面向过程有什么区别?
2019-10-25 16:58:58面向对象的程序设计(Object-Oriented Programming,简记为OOP),是当下最流行的程序设计方式之一,它将程序 -
java什么是面向对象
2021-02-12 11:15:58java面向对象是指在计算机程序中,模拟现实世界中的概念,借助对象的描述在计算机程序中用类似的实体模拟现实世界中的实体。什么是对象和面向对象的编程?对象就是存在的具体实体,具有明确定义的状态和行为,是面向... -
面向对象 和 面向过程 的区别
2022-03-28 15:02:53一、面向对象与面向过程的区别 面向过程就是分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候一个一个依次调用就可以了;面向对象是把构成问题事务分解成各个对象,建立对象的目的不是... -
面向对象与面向过程的本质的区别
2018-01-10 20:19:04如果你很想搞明白面向对象是什么,面向过程是什么,或者说二者之间的区别是什么,那么就花费一点时间来研读一下这篇博客,你一定会有很大的收获的! 一、面向对象与面向过程的区别 面向过程就是分析出解决问题所...