JS面向对象系列教程 — 对象的基本操作
面向对象概述

面向对象(Object Oriented)简称OO,它是一种编程思维,用于指导我们如何应对各种复杂的开发场景。
这里说的对象(Object),意思就是事物,在面向对象的思维中,它将一切都看作是对象,并以对象为切入点去思考问题。
使用面向对象的思维去开发程序,我们首先思考的是这个系统中有哪些对象(事物),它们各自有什么属性(特征),又有什么方法(行为),这样一来,就可以把系统分解为一个一个的对象,然后对每个对象进行单独研究,以降低系统的整体复杂度。
学习面向对象,我们不仅要学习它的技术知识,更重要的是学习这种思考程序的方式,这种思维方式跟我们过去开发程序有很大的区别。在过去,我们完成一个功能的时候,往往思考的是完成该功能的步骤,先做什么,再做什么,如果怎么样,就怎么怎么样……,这种过去的思维模式,我们称之为面向过程。
面向过程并不是错误的,只是它面对复杂的问题时显得有些捉襟见肘。
面向过程和面向对象最大的区别在于,面向过程思考的重心和切入点是事情,面向对象思考的重心和切入点是事物。
在面向对象的世界中,它将一切都看作是对象。这里的对象,包罗万象,它可以是现实世界中看得见摸得着的实体:人、小猫、小狗、飞机、课桌、铅笔、电视等等等等,都可以看作是对象。它也可以是某些领域中的抽象体:订单、价格计算器、dom元素、日期等等等等,它们也被看作是对象。
因此,在OO的世界里,有一句至理名言——一切皆为对象。
javascript语言是支持面向对象开发的语言,本系列教程中,将一步步讲解如何使用它进行面向对象开发,同时会进一步探寻它背后深层次的原理。
注意:本系列教程的重心,将放在面向对象开发的技术层面(即面向对象编程,Object Oriented Programming,OOP)。
对于面向对象思想层面(即面向对象设计,Object Oriented Design,OOD),本教程不做过多讲解。因为面向对象思想的建立并非一朝一夕,它不是靠读文章读出来的,虽然好的文章可以对你有启发作用,但更多的,这种思想是靠常年累月的代码量练出来的,是靠不断的分析、重构想出来的。
本教程希望的是,你能够通过学习面向对象开发,激发你的思考,引起你对另一种开发方式的关注,逐渐建立起面向对象的思维。
创建对象
对象即事物,一切皆对象。
其实你在之前的开发中,应该不止一次的接触过对象,有些是浏览器自带的对象,比如:dom对象、window对象、document对象等;有些则是你根据功能需要自己创建的,比如:用户对象、学生对象等。
在JS中,创建一个对象非常的简单,通过一对{}即可创建一个对象,下面的代码你应该并不会陌生:
const user1 = { loginid: "bangbangji", loginpwd: "123456", name: "棒棒鸡"};const user2 = { loginid: "xiaobaitu", loginpwd: "654321", name: "小白兔"};
上面的代码应该这样理解,创建了两个对象,分别把它们赋值给了变量user1和user2。
为什么要强调这一点呢?因为真正的对象不是user1和user2,而是那一对大括号及其里面的内容{...},在后面讲解对象赋值原理时还会详细讲解这一点。
上面这种创建对象的写法,即使用两个大括号来表示对象{...},叫做对象的字面量表示法。
使用字面量表示法来创建对象的好处是简单易懂,但它不好的地方在于无法应用面向对象开发中的一些高级特性。
下面的代码,展现了另一种创建对象的方式,即使用关键字new来创建对象:
const user1 = new Object(); //相当于:const user1 = {};user1.loginid = "bangbangji"; user1.loginpwd = "123456"; user1.name = "棒棒鸡";const user2 = new Object(); //相当于:const user2 = {};user2.loginid = "xiaobaitu"; user2.loginpwd = "654321"; user2.name = "小白兔";
这样的代码虽然看似繁琐了很多,但实际上它才是对象原本的创建方式。上面的代码和第一种方式效果完全一致。
实际上,在JS语言中,所有的对象都是使用new关键字创建的。即便你使用的是字面量表示法,JS引擎最终也会将其转换为这种方式。因此,对象的字面量表示法仅仅是JS语言的一个语法糖,要创建对象,最终都是要使用new关键字的。因此,在后文中,每一个示例,我都会用两种方式来实现对象的创建。
语法糖(Syntactic sugar),也译为糖衣语法,是指语言层面的一些便捷语法,它仅仅是为开发者提供的一种高效的编码方式,并不改变底层的实现原理。
属性和方法
我们过去使用对象,往往是为了将多个变量整合到一个变量上,其实,这种思想就是面向对象的一种核心思想——封装。
面向对象有三大显著特征:封装、继承、多态
那些整合到一个对象中的变量,我们称之为对象的属性。属性往往是一个名词,表示对象所拥有的特征。
const user1 = { loginid: "bangbangji", //loginid为对象的属性,表示用户账号 loginpwd: "123456", //loginpwd为对象的属性,表示用户密码 name: "棒棒鸡" //name为对象的属性,表示用户姓名};const user2 = new Object(); user2.loginid = "xiaobaitu";//loginid为对象的属性,表示用户账号user2.loginpwd = "654321";//loginpwd为对象的属性,表示用户密码user2.name = "小白兔";//name为对象的属性,表示用户姓名
对象的属性还可以是一个对象或者数组或者其他任意类型,用于表示多层次的结构:
const user1 = { loginid: "bangbangji", loginpwd: "123456", name: "棒棒鸡", //属性address也是一个对象 address: { province: "四川省", city: "成都市" } };//输出:四川省-成都市console.log(`${user1.address.province}-${user1.address.city}`); const user2 = new Object(); user2.loginid = "xiaobaitu"; user2.loginpwd = "654321"; user2.name = "小白兔"; user2.address = new Object(); //属性address也是一个对象user2.address.province = "四川省"; user2.address.city = "南充市";//输出:四川省-南充市console.log(`${user2.address.province}-${user2.address.city}`);
对象除了有特征,还会有一些行为,这些行为我们称之为对象的方法。方法往往是一个动词,表示对象所拥有的行为,在代码层面,方法表现为函数。
const user1 = { loginid: "bangbangji", loginpwd: "123456", name: "棒棒鸡", //sayHello(打招呼)属于对象方法,它是一个函数,表示对象的行为 sayHello: function () { console.log("你好!"); } }; user1.sayHello(); //调用对象的方法,输出:你好!const user2 = new Object(); user2.loginid = "xiaobaitu"; user2.loginpwd = "654321"; user2.name = "小白兔";//sayHello(打招呼)属于对象方法,它是一个函数,表示对象的行为user2.sayHello = function () { console.log("你好!"); }; user2.sayHello(); //调用对象的方法,输出:你好!
可以看出,方法和属性在书写上并没有本质的差别,只不过属性是一个普通的值,方法是一个函数而已。
this关键字
我们现在考虑一下,在之前的示例中出现的sayHello方法,假设我们现在要对其功能做一点改造,我们希望该方法要输出对象的姓名和账号,于是,得到了下面的代码:
const user1 = { loginid: "bangbangji", loginpwd: "123456", name: "棒棒鸡", //sayHello(打招呼)属于对象方法,它是一个函数,表示对象的行为 sayHello: function () { console.log("你好!我是棒棒鸡,我的账号是bangbangji"); } }; user1.sayHello(); //调用对象的方法,输出:你好!我是棒棒鸡,我的账号是bangbangjiconst user2 = new Object(); user2.loginid = "xiaobaitu"; user2.loginpwd = "654321"; user2.name = "小白兔";//sayHello(打招呼)属于对象方法,它是一个函数,表示对象的行为user2.sayHello = function () { console.log("你好!我是小白兔,我的账号是xiaobaitu"); }; user2.sayHello(); //调用对象的方法,输出:你好!我是小白兔,我的账号是xiaobaitu
这种方式结果固然正确,但是考虑一下100个用户的场景……不敢想象是不?这还仅仅是一个打招呼的方法,如果方法里面代码多一点,复杂一点,会更加棘手。
由于同一类对象(比如这里的用户对象)都具有共同的行为——打招呼,我们何不把这个方法函数提出来呢?就像下面这样:
//提取出来的共同方法function sayHello(){ //怎么办?输出哪个对象的姓名和账号? console.log("你好!我是???,我的账号是???"); }const user1 = { loginid: "bangbangji", loginpwd: "123456", name: "棒棒鸡", sayHello }; user1.sayHello(); //输出:你好!我是???,我的账号是???const user2 = new Object(); user2.loginid = "xiaobaitu"; user2.loginpwd = "654321"; user2.name = "小白兔"; user2.sayHello = sayHello; user2.sayHello(); //输出:你好!我是???,我的账号是???
这样虽然解决了代码重复的问题,但新的问题又来了,虽然我们知道每个用户对象都具有打招呼的方法,但是每个对象的属性值不一样,打招呼的时候,我到底输出哪个对象的属性值呢?
于是,JS给我们提供了一个关键字this,它指代的是当前对象,即调用方法的对象,于是我们就可以解决这个问题了:
//提取出来的共同方法function sayHello(){ //this指代当前调用方法的对象 console.log(`你好!我是${this.name},我的账号是${this.loginid}`); }const user1 = { loginid: "bangbangji", loginpwd: "123456", name: "棒棒鸡", sayHello };//user1调用sayHello时,方法运行过程中的this指代user1user1.sayHello(); //输出:你好!我是棒棒鸡,我的账号是bangbangjiconst user2 = new Object(); user2.loginid = "xiaobaitu"; user2.loginpwd = "654321"; user2.name = "小白兔"; user2.sayHello = sayHello;//user2调用sayHello时,方法运行过程中的this指代user2user2.sayHello(); //输出:你好!我是小白兔,我的账号是xiaobaitu
我们在sayHello函数中使用了this关键字,当函数运行时,该关键字指代调用该函数的对象,即谁在调用我,我里面的this就指代谁。在阅读代码的时候,你可以把this读作我的,以便于你理解它。
借助了神奇的this关键字,就解决了重复代码的问题,之后无论创建多少个用户对象,我们都可以使用同一个方法了。
关于this关键字,目前你需要记住以下两点:
this关键字只能书写在函数内。
this关键字在函数运行的时候才能确定指代的是谁,函数运行前谁也无法知道它将指代谁。
由于javascript语言本身的特性,函数中的this关键字会带来很多坑(比如直接调用sayHello函数,this指代谁呢?)。后面会专门拿一章出来讲解this。
总结
面向对象(OO)是一种编程思维,以对象为切入点分析解决问题,这种思维需要长期的练习才能逐渐建立,而我们学习的是面向对象技术层面的东西。
创建对象可以使用字面量表示法和new关键字,字面量表示法是一个语法糖,JS引擎最终会将其变为new关键字方式创建对象。
对象包含属性和方法,分别表示对象的特征和行为,它们没有本质的区别,只是行为提现为一个函数
在函数中可以使用this关键字来指代**当前对象(调用函数的对象)
JS面向对象系列教程 — 对象的基本操作的更多相关文章
- [js高手之路] es6系列教程 - 对象功能扩展详解
第一:字面量对象的方法,支持缩写形式 //es6之前,这么写 var User = { name : 'ghostwu', showName : function(){ return this.nam ...
- 页面循环绑定(变量污染问题),js面向对象编程(对象属性增删改查),js字符串操作,js数组操作
页面循环绑定(变量污染问题) var lis = document.querySelectorAll(".ul li") for ( var i = 0 ; i < lis. ...
- JS面向对象编程:对象
一般面向过程的写法都是写很多function,坏处:1.代码复用不好 2.函数名称容易重复冲突 下面介绍面向对象的写法: 在JS中每个函数function都是一个对象. 比如,下面这个就是一个对象,我 ...
- JS面向对象编程,对象,属性,方法。
document.write('<script type="text/javascript" src="http://api.map.baidu.com/api?v ...
- js面向对象知识点之对象属性 创建对象 总结中
昨天面试出了一道面试题 本人我做错了 于是痛定思痛 再过一遍面向对象 var name="一体机"; var value="infolist"; //构造函数 ...
- Vue.js入门系列教程(二)
过滤器:filter 全局过滤器 <!DOCTYPE html> <html lang="en"> <head> <meta charse ...
- Vue.js入门系列教程(一)
基本的Vue代码结构 <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> ...
- JS面向对象设计-理解对象
不同于其他面向对象语言(OO,Object-Oriented),JS的ECMAScript没有类的概念, 它把对象定义为"无序属性(基本值.对象.函数)的集合",类似于散列表. 每 ...
- Vue.js入门系列教程(三)
序言
随机推荐
- js实现简易打点计时器
很简单的实现一个打点计时器,规定从start至end,每次加1,每次打印间隔100ms,并且返回取消方法. 代码如下: //打点计时器,每间隔100毫秒+1 function count(start, ...
- 洛谷3871 [TJOI2010]中位数 维护队列的中位数
题目描述 给定一个由N个元素组成的整数序列,现在有两种操作: 1 add a 在该序列的最后添加一个整数a,组成长度为N + 1的整数序列 2 mid 输出当前序列的中位数 中位数是指将一个序列按照从 ...
- java源码学习
Collection List ArrayList LinkedList Vector Stack Set HashSet TreeSet Map HashMap TreeMap LinkedHash ...
- Spring配置方式
Spring配置方式 第一阶段:xml配置 在spring 1.x时代,使用spring开发满眼都是xml配置的bean,随着项目的扩大, 我们需要把xml配置文件分放到不同的配置文件中,那时 ...
- Spring-statemachine给end状态设置action
Spring-statemachine版本:当前最新的1.2.3.RELEASE版本 builder.configureStates() .withStates() .initial(generate ...
- VC:当前不会命中断点,还没有为该文档载入不论什么符号
VS2013中设置的断点无效:"当前不会命中断点,还没有为该文档载入不论什么符号".问题主要出在没有生成调试信息.解决方法例如以下: (1)项目-〉属性-〉配置属性-〉C/C++- ...
- Mesh BRep Shapes
Mesh BRep Shapes eryar@163.com Abstract. 当对OpenCASCADE的BRep表示法的数据结构有了一定的理解后,建议可以自己实现一个显示数据生成的功能,即网格剖 ...
- UE4的JSON读写方式<一>
声明:全部权利保留. 转载必须说明出处:http://blog.csdn.net/cartzhang/article/details/41009343 UE4的Json的解析博客地址: http:// ...
- 流水线技术原理和Verilog HDL实现
所谓流水线处理,如同生产装配线一样,将操作执行工作量分成若干个时间上均衡的操作段,从流水线的起点连续地输入,流水线的各操作段以重叠方式执行.这使得操作执行速度只与流水线输入的速度有关,而与处理所需的时 ...
- Jesse's Code
题目描述 Jesse是个数学迷,他最喜欢研究“哥德巴赫猜想”,因此他的计算机密码也都采用素数. 但一直用同一个密码是不安全的,所以他要经常更换他的密码.但他只允许自己的密码中出现某些数字,且密码的每一 ...