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 — 对象的基本操作的更多相关文章

  1. JS对象继承篇

    JS对象继承篇 ECMAScript只支持实现继承,而且其实现继承主要是依靠原型链来实现的 原型链 其基本思路是利用原型让一个引用类型继承另一个引用类型的属性和方法 function Person() ...

  2. JS 对象封装的常用方式

    JS是一门面向对象语言,其对象是用prototype属性来模拟的,下面,来看看如何封装JS对象. 常规封装 function Person (name,age,sex){ this.name = na ...

  3. JSON字符串和JS对象之间的转换

    JSON字符串和JS对象之间的转换 1 json字符串转换为js对象 1.1 标准json格式字符串转换为Js对象  JSON字符串 str JSON.parse(str) eval(str) eva ...

  4. js 对象的_proto_

    js 对象呢,有个属性叫_proto_,以前没听说过,也没关注,最近看这个原型,就被迫知道了这个东西,js 这里面的东西,真是规定的很奇怪,具体为啥也不知道,就测试发现的,对象的_proto_属性,和 ...

  5. js对象/数组深度复制

    今天碰到个问题,js对象.数组深度复制:之前有见过类似的,不过没有实现函数复制,今晚想了一下,实现代码如下: function clone(obj) { var a; if(obj instanceo ...

  6. js对象的深度克隆

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  7. js对象详解

    js自定义对象 一,概述 在Java语言中,我们可以定义自己的类,并根据这些类创建对象来使用,在Javascript中,我们也可以定义自己的类,例如定义User类.Hashtable类等等. 目前在J ...

  8. js对象常用2中构造方法

    //js 对象的构造方法通常有2中情况: //第一种是通过json对象构造 var persion={ name:"孙悟空", age:40, eat:function () { ...

  9. JS对象复制

    在JavaScript很多人复制一个对象的时候都是直接用"=",因为大家都觉得脚本语言是没有指针.引用.地址之类的,所以直接用"="就可以把一个对象复制给另外一 ...

随机推荐

  1. idea 包的显示方式

    idea 可以通过点击Project的导航栏里的小齿轮里面有一个 Flatten packages 选项,将其勾上.就可以得到跟eclipse一样的包的显示方式. 没有设置默认是这样的 2018-06 ...

  2. Qt之滚动字幕

    简述 滚动字幕,也就是传说中的跑马灯效果. ​简单地理解就是:每隔一段时间(一般几百毫秒效果较佳)显示的文字进行变化(即滚动效果). 简述 实现 效果 源码 实现 利用定时器QTimer,在固定的时间 ...

  3. deque迭代器失效的困惑?

    在实现LRU算法的时候lru_list 開始用的是deque 可是由于害怕其在插入删除上的迭代器失效情况的诡异情况.遂用list取代之. 在数据量比較大的时候性能不是非常好.性能优化分析的时候决定用d ...

  4. Java学习书目

    Java学习书目 拜读了:http://www.importnew.com/26932.html#comment-636554

  5. 第十六周项目3:max带来的冲突

    问题及代码: /* *Copyright (c)2015,烟台大学计算机与控制工程学院 *All rights reserved. *文件名:project.cpp *作 者:陈文青 *完毕日期:20 ...

  6. Unity 内置Shader变量、辅助函数等

    一:标准库里的常用.cginc文件 HLSLSupport.cginc - (automatically included) Helper macros and definitions for cro ...

  7. 使用MyEclipse编写Java程序

    MyEclipse是非常实用的一款Java程序开发工具,主要用于Java.Java EE以及移动应用的开发.MyEclipse的功能非常强大,支持也十分广泛,尤其是对各种开源产品的支持相当不错. My ...

  8. php中命名空间和use

    php中命名空间和use 总结 php中的namespace就有点像java中package包的概念 php中的use的概念就是用别人的命名空间中的类 php中的include enquire是引入文 ...

  9. Optional arguments

    We have seen built-in functions that take a variable number of arguments. For example range can take ...

  10. 关键字super

    1.super,相较于关键字this,可以修饰属性.方法.构造器 2.super修饰属性.方法:在子类的方法.构造器中,通过super.属性或者super.方法的形式,显式的调用父类的指定 属性或方法 ...