面向对象编程
过程型编程
在编写代码时,使用一系列的变量声明、条件、while语句和函数调用。
这是一种过程型思维:先这样做,再那样做…
这好比于手工烤面包:先制作加热线圈,将线圈通电,手持面包放在离线圈很近的地方烤,然后耐心等待,等烤熟后再将线圈断电;
面向对象编程
从对象的状态和行为的角度思考问题,这是更加自然的方式;
同时,对象隐藏了状态和行为的复杂性,从而让我们能在更高层次考虑问题
这好比于使用烤箱烤面包:只需将面包放入烤箱再按下按钮即可
第一种方式是过程型的,而第二种方式是面向对象的:你有一个烤箱对象,让你能够轻松地放入并烤好面包
对象(Object)
JavaScript中,类型分为两种:基本类型和对象
- 基本类型:数字
number
、字符串string
、布尔值boolean
、null
和undefined
- 特殊的类型:对象
object
类型(用于表示问题空间中的事物)
不属于基本类型的值都是对象
如“数组
Array
”,其本质上就是对象(即object
),有push
等方法
其他一些常见的对象:
JavaScript提供的对象:
Math
Date
用于操作日期和时间
RegExp
用于在字符串中查找模式
JSON
用于与其他应用程序交换JavaScript对象
浏览器提供的对象:
Document
用于写入内容到网页
Console
用于控制台调试
Window
表示浏览器中的一个窗口
ps.Window.alert()
,可以写成alert()
,这里省略了全局对象Window
在一些情况下,基本类型也如同对象被暂时转换为对象进行处理:
使用基本类型
string
的属性或方法时(如split
、substring
、contact
等),JavaScript将把它暂时转换为对象,使用指定的属性或方法,再将其转换为基本类型字符串。这个过程是自动进行的,程序员无需关注。
ps.number
、boolean
类型(有toString
等方法)也有类似的转化;
对象的特点
- 对象有一系列属性(property),并且有方法(也可看作属性,是一个函数)
- 方式也是一种属性,只是将函数赋给了这种属性
- 对象包含状态和行为,状态可以影响行为,行为也可以影响状态
(对象的属性记录了状态,对象的方法产生行为) - 优点:对象封装(隐藏)了其状态和行为的复杂性(便于专注高层次设计)
对象怎样被存储下来?——对象变量
对象有可变数量的属性,对象可能很大也可能很小
因此,变量装不下整个对象,只存储[指向这个对象的引用]
- 基本类型的变量(数字、字符串等)存储的是实际值
- 对象变量存储的是指向对象的引用,而非对象本身
- 因此,对象变量也被称为引用变量
对于
car.color
严格来说,car
不是对象,而是指向对象的引用(如同指针,是对象的存储地址)
使用car.color
,就像在对JavaScript解释器说:
请使用句点.
前的引用来获取相应的对象,再访问句点.
后指定的属性
由于此原因,向函数传递实参时:
- 实参为基本类型变量,则传入[变量]的副本,函数中的操作不改变原始变量;
- 实参为对象变量,传入[指向该对象的引用]的副本,函数直接修改原始对象;
(此时,实参是[指向该对象的引用],形参是[指向该对象的引用]的副本,
实参和形参指向同一个对象)
对象的属性
- 对象的属性可以是一般的变量,也可以是函数(也称方法)
car.color = "red";//属性为一般的变量
window.onload = init;//属性为函数
注意,属性名可以看作一个字符串
- 一般情况下,可以直接写字符串的内容,如
car.color
- 当属性名中包含空格时,必须写成
car."on sale"
,而不能写成car.on sale
*注:在WIN10的Microsoft Edge中,car."on=sale"=false;
写法报错
Uncaught SyntaxError: Unexpected string
,故还是不要用带空格的属性名
访问一个不存在的属性,如car
对象中没有needWashing
属性
那么表达式car.needWashing
的结果为undefined
对象的方法
-
对象的属性也可以是函数,称为方法
(方式也是一种属性,只是将函数赋给了这种属性) -
方法和属性的区分,可以从有没有带括号
()
直观地看出来 -
方法和普通的函数没什么两样,方法是位于对象内的函数,仅此而已
(如同向常规函数传递参数一样,可以向方法传递实参)
ps. 可以将[方法]视为[属性],将[函数]视为属性的[值]
自定义一个car.drive()
方法
var car = {
started:true,
drive:function(){
if(this.started==true)
alert("Zoom zoom!");
else
alert("Start the engine first!");
}
};
car.drive();//调用car对象的drive方法
- 注意,这里的
function()
是一个匿名函数,即没有显式地命名,因为可以直接用属性名drive
调用这个函数 - 注意
this.started
:要在方法中访问该对象的属性/方法,使用句点表示法
(使用关键字this
而不是对象名car
)
在方法体内使用关键字this
指向本对象
在上面的代码中:
var car = {
...
drive:function(){
if(this.started==true)...//不是if(car.started==true)或(started==true)
else...
}
};
car.drive();//调用car对象的drive方法
如果直接写if(started==true)
,JavaScript误以为start只是一个普通变量
正确写法是if(this.started==true)
,用关键字this告诉JavaScript,你说的是当前所处的对象
关键字this
的工作原理
每当方法被调用时,在该方法体内都可使用关键字this
来引用其方法被调用的对象
换句话说,每当调用对象car的方法drive时,JavaScript负责将对象car赋给this(当然前提是:在创建对象时,在方法体内的代码中使用了this)
例如,调用car对象的方法drive
car.drive();
则在方法体内的this,都将指向对象car
if(this.started==true) 而this的值为指向car对象的引用,相当于执行了if(car.started==true)
如果调用的是
taxi.drive();
,则在该对象的drive方法中,this指向对象taxi;
如果调用的是chevy.drive();
,则在该对象的drive方法中,this指向对象chevy;
…
可见,this具有普遍性和一般性,它不特指某个具体的对象,this指向什么对象完全取决于当前被调用的方法属于哪个对象
总结:this
出现在哪个对象的方法中,它就指向[该方法所属的那个对象]
调用方法时,解释器将执行 this
=[当前所处的对象]的引用
创建对象
下面创建一个没有属性的对象
var car = {};
下面创建一个名为car的对象
对象字面量表示法
var car = {
make:"Chevy",//各属性用逗号分隔
"on sale":false
};
构造函数法
使用Object
构造函数
var car = new Object();//该构造函数为新对象定义了默认的属性和方法
car.make="Chevy";//要为对象添加属性时,直接为其赋值即可
car."on sale"=false;
访问对象的属性
句点表示法
car.color = "red";
方括号表示法
对象[属性名(字符串)]
使用方括号表示法,括号内必须填入属性名对应的字符串
应该写car["color"]
,而不是car[color]
var colorOfCar=car["color"];
方括号表示法,在表达式为(表示属性名的)字符串的场景中,更灵活:
例如
car["co"+"lor"];
又如下面的例子
↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓
迭代对象的所有属性
使用for in
迭代器,以随机的方式遍历对象的所有属性
for (var prop in car){
console.log(prop+": "+car[prop]);
}
- 注意
car[prop]
:此时prop
是一个字符串,使用方括号表示法更方便
为对象添加属性/修改属性
直接为属性赋值时:
- 如果属性不存在将被自动添加
- 否则将修改其值
var car = {
make:"Chevy",
"on sale":false
};
car.mileage=1021;//添加属性
car.make="Fiat";//修改属性
删除对象的属性
使用delete
关键字
delete car.mileage;//删除属性mileage
注意,删除成功后delete
表达式返回true
(即使要删除的属性本就不存在)
对象可能属于浏览器而受到保护,无法删除属性,delete
表达式返回false