面向对象概述

面向对象(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面向对象系列教程 — 对象的基本操作的更多相关文章

  1. [js高手之路] es6系列教程 - 对象功能扩展详解

    第一:字面量对象的方法,支持缩写形式 //es6之前,这么写 var User = { name : 'ghostwu', showName : function(){ return this.nam ...

  2. 页面循环绑定(变量污染问题),js面向对象编程(对象属性增删改查),js字符串操作,js数组操作

    页面循环绑定(变量污染问题) var lis = document.querySelectorAll(".ul li") for ( var i = 0 ; i < lis. ...

  3. JS面向对象编程:对象

    一般面向过程的写法都是写很多function,坏处:1.代码复用不好 2.函数名称容易重复冲突 下面介绍面向对象的写法: 在JS中每个函数function都是一个对象. 比如,下面这个就是一个对象,我 ...

  4. JS面向对象编程,对象,属性,方法。

    document.write('<script type="text/javascript" src="http://api.map.baidu.com/api?v ...

  5. js面向对象知识点之对象属性 创建对象 总结中

    昨天面试出了一道面试题 本人我做错了 于是痛定思痛 再过一遍面向对象 var name="一体机"; var value="infolist"; //构造函数 ...

  6. Vue.js入门系列教程(二)

    过滤器:filter 全局过滤器 <!DOCTYPE html> <html lang="en"> <head> <meta charse ...

  7. Vue.js入门系列教程(一)

    基本的Vue代码结构 <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> ...

  8. JS面向对象设计-理解对象

    不同于其他面向对象语言(OO,Object-Oriented),JS的ECMAScript没有类的概念, 它把对象定义为"无序属性(基本值.对象.函数)的集合",类似于散列表. 每 ...

  9. Vue.js入门系列教程(三)

    序言

随机推荐

  1. ReactiveCocoa简单使用20例

    ReactiveCocoa简单使用20例 1. 观察值变化 你别动,你一动我就知道. //当self.value的值变化时调用Block,这是用KVO的机制,RAC封装了KVO @weakify(se ...

  2. Java 调用对象方法的执行过程

    弄清调用对象方法的执行过程十分重要.下面是调用过程的详细描述: 1) 编译器查看对象的声明类型和方法名.假设调用x.f(param),且隐式参数x声明为C类的对象.需要注意的是:有可能存在多个名为f, ...

  3. 关联Anaconda和最新Pycharm2018.3.2

    在Anaconda和Pycharm 2018.3.2 x64都安装好之后,进行Anaconda 与Pycharm的关联操作 首先File -->New Project 打开以后切记要把Proje ...

  4. 题解 P3372 【【模板】线段树 1】(珂朵莉树解法)

    这道题可以用珂朵莉树做,但是由于数据比较不随机,而我也没有手写一颗平衡树,所以就被卡掉了,只拿了70分. 珂朵莉树是一种基于平衡树的(伪)高效数据结构. 它的核心操作是推平一段区间. 简而言之,就是把 ...

  5. poj 2533 Longest Ordered Subsequence 最长递增子序列(LIS)

    两种算法 1.  O(n^2) #include<iostream> #include<cstdio> #include<cstring> using namesp ...

  6. Win8.1应用开发之文件操作

    在操作文件之前,先相应用的应用功能声明进行设定.用户通过C#(非UI)对win8.1上的文件进行訪问,仅仅能局限于图片,音乐,视频和文档四个目录. 而通过文件选取器则能訪问到整个系统的文件. (一)应 ...

  7. linux中的硬连接和软连接

    linux中的硬连接和软连接 linux中的硬连接和软连接 背景 连接 硬连接 软连接 example reference 背景 linux中的文件主要分3块, - 真正的数据 - 索引节点号(ino ...

  8. legend---五、如何优雅的实现多继承

    legend---五.如何优雅的实现多继承 一.总结 一句话总结:多继承可以通过把别人对象作为属性来调用属性的方法执行, 继承的本质也是为了调用方法和属性,而上述的方式可以满足 1.php中前端可以共 ...

  9. 分贝(dB)的理解

    分贝(dB,decibels)表达的是功率比(power ratio,P2/P1),而不是一个amount,P2>P1,分贝为正值,否则为负值.分贝是对数形式的,而不是线性形式的,也即 20 d ...

  10. mysql日期函数及批量循环返回主键ID

    实际项目中总是会遇到各种时间计算查询等等许多时候是特别麻烦前阵子公司有个需求大致是要查询当前日期与数据库存储日期之差,本来写了个工具类调用的但是最后觉得这样不好就想着能不能用函数解决,没想到还真有这里 ...