JavaScript中,除了五种原始类型(即数字,字符串,布尔值,null,undefined)之外的都是对象了,所以,不把对象学明白怎么继续往下学习呢?
一.概述
对象是一种复合值,它将很多值(原始值或其他对象)聚合在一起,可通过属性名访问这些值。而属性名可以是包含空字符串在内的任意字符串。JavaScript对象也可以称作一种数据结构,正如我们经常听说的“散列(hash)”、“散列表(hashtable)”、“字典(dictionary)”、“关联数组(associative array)”。
JavaScript中对象可以分为三类:
①内置对象,例如数组、函数、日期等;
②宿主对象,即JavaScript解释器所嵌入的宿主环境(比如浏览器)定义的,例如HTMLElement等;
③自定义对象,即程序员用代码定义的;
对象的属性可以分为两类:
①自有属性(own property):直接在对象中定义的属性;
②继承属性(inherited property):在对象的原型对象中定义的属性(关于原型对象下面会详谈);
二.对象的创建
既然学习对象,又怎能不懂如何创建对象呢?面试前端岗位的同学,可能都被问过这个基础问题吧:
创建JavaScript对象的两种方法是什么?(或者:说说创建JavaScript对象的方法?)
这个问题我就被问过两次。“创建对象的两种方法”这种说法网上有很多,但是据我所看书籍来说是有三种方法的!下面我们就来具体谈谈这三种方法:
1.对象直接量
对象直接量由若干名/值对组成的映射表,名/值对中间用冒号分隔,名/值对之间用逗号分隔,整个映射表用花括号括起来。属性名可以是JavaScript标识符也可以是字符串直接量,也就是说下面两种创建对象obj的写法是完全一样的:
1 2 |
var obj = {x: 1, y: 2}; var obj = {'x': 1, 'y':2}; |
2.通过new创建对象
new运算符后跟随一个函数调用,即构造函数,创建并初始化一个新对象。例如:
1 2 3 |
var o = new Object(); //创建一个空对象,和{}一样 var a = new Array(); //创建一个空数组,和[]一样 var d = new Date(); //创建一个表示当前时间的Date对象 |
关于构造函数相关的内容以后再说。
3.Object.create()
ECMAScript5定义了一个名为Object.create()的方法,它创建一个新对象,其中第一个参数是这个对象的原型对象(好像还没解释原型对象…下面马上就说),第二个可选参数用以对对象的属性进行进一步的描述,第二个参数下面再说(因为这第三种方法是ECMAScript5中定义的,所以以前大家才经常说创建对象的两种方法的吧?个人觉得应该是这个原因)。这个方法使用很简单:
1 2 |
var o1 = Object.create({x: 1, y: 2}); //对象o1继承了属性x和y var o2 = Object.create(null); //对象o2没有原型 |
下面三种的完全一样的:
1 2 3 |
var obj1 = {}; var obj2 = new Object(); var obj3 = Object.create(Object.prototype); |
为了解释为啥这三种方式是完全一样的,我们先来解释下JavaScript中的原型对象(哎,让客官久等了!),记得一位大神说过:
Javascript是一种基于对象(object-based)的语言,你遇到的所有东西几乎都是对象。但是,它又不是一种真正的面向对象编程(OOP)语言,因为它的语法中没有class(类)。
面向对象的编程语言JavaScript,没有类!!!那么,它是怎么实现继承的呢?没错,就是通过原型对象。基本上每一个JavaScript对象(null除外)都和另一个对象相关联,“另一个”对象就是所谓的原型对象(原型对象也可以简称为原型,并没有想象的那么复杂,它也只是一个对象而已)。每一个对象都从原型对象继承属性,并且一个对象的prototype属性的值(这个属性在对象创建时默认自动生成,并不需要显示的自定义)就是这个对象的原型对象,即obj.prototype就是对象obj的原型对象。
原型对象先说到这,回到上面的问题,有了对原型对象的认识,下面就是不需要过多解释的JavaScript语言规定了:
①所有通过对象直接量创建的对象的原型对象就是Object.prototype对象;
②通过关键字new和构造函数创建的对象的原型对象就是构造函数prototype属性的值,所以通过构造函数Object创建的对象的原型就是Object.prototype了;
现在也补充了第三种创建对象的方法Object.create()第一个参数的含义。
三.属性的查询和设置
学会了如何创建对象还不够啊,因为对象只有拥有一些属性才能真正起到作用滴!那么,就继续往下学习对象的属性吧!
可以通过点(.)或方括号([])运算符来获取和设置属性的值。对于点(.)来说,右侧必须是一个以属性名命名的标识符(注意:JavaScript语言的标识符有自己的合法规则,并不同于带引号的字符串);对于方括号([])来说,方括号内必须是一个字符串表达式(字符串变量当然也可以喽,其他可以转换成字符串的值比如数字什么的也是都可以滴),这个字符串就是属性的名字。正如下面例子:
1 2 3 |
var obj = {x: 1, y: 2}; obj.x = 5; obj['y'] = 6 |
概述中说过,JavaScript对象具有”自有属性“,也有“继承属性”。当查询对象obj的属性x时,首先会查找对象obj自有属性中是否有x,如果没有,就会查找对象obj的原型对象obj.prototype是否有属性x,如果没有,就会进而查找对象obj.prototype的原型对象obj.prototype.prototype是否有属性x,就这样直到找到x或者查找到的原型对象是undefined的对象为止。可以看到,一个对象上面继承了很多原型对象,这些原型对象就构成了一个”链“,这也就是我们平时所说的“原型链”,这种继承也就是JavaScript中“原型式继承”(prototypal inheritance)。
对象o查询某一属性时正如上面所说会沿着原型链一步步查找,但是其设置某一属性的值时,只会修改自有属性(如果对象没有这个属性,那就会添加这个属性并赋值),并不会修改原型链上其他对象的属性。
四.存取器属性getter和setter
上面我们所说的都是很普通的对象属性,这种属性称做“数据属性”(data property),数据属性只有一个简单的值。然而在ECMAScript 5中,属性值可以用一个或两个方法替代,这两个方法就是getter和setter,有getter和setter定义的属性称做“存取器属性”(accessor property)。
当程序查询存取器属性的值时,JavaScript调用getter方法(无参数)。这个方法的返回值就是属性存取表达式的值。当程序设置一个存取器属性的值时,JavaScript调用setter方法,将赋值表达式右侧的值当做参数传入setter。如果属性同时具有getter和setter方法,那么它就是一个读/写属性;如果它只有getter方法,那么它就是一个只读属性,给只读属性赋值不会报错,但是并不能成功;如果它只有setter方法,那么它是一个只写属性,读取只写属性总是返回undefined。看个实际的例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
var p = { x: 1.0, y: 2.0, get r(){ return Math.sqrt(this.x*this.x + this.y*this.y); }; set r(newvalue){ var oldvalue = Math.sqrt(this.x*this.x + this.y*this.y); var ratio = newvalue/oldvalue; this.x *= ratio; this.y *= ratio; }, get theta(){ return Math.atan2(this.y, this.xyon-h"> Math.atan2(this.y, this.x字符串在内的任意字符串。JavaScript对象也可以称作一种数据结构,正如我们经常听说的“散列(hash)”、“散列表(hashtable)”、“字典(dictionary)”、“关联数组(associative array)”。
JavaScript中对象可以分为三类: ①内置对象,例如数组、函数、日期等; ②宿主对象,即JavaScript解释器所嵌入的宿主环境(比如浏览器)定义的,例如HTMLElement等; ③自定义对象,即程序员用代码定义的; 对象的属性可以分为两类: ①自有属性(own property):直接在对象中定义的属性; ②继承属性(inherited property):在对象的原型对象中定义的属性(关于原型对象下面会详谈); 二.对象的创建 既然学习对象,又怎能不懂如何创建对象呢?面试前端岗位的同学,可能都被问过这个基础问题吧:
这个问题我就被问过两次。“创建对象的两种方法”这种说法网上有很多,但是据我所看书籍来说是有三种方法的!下面我们就来具体谈谈这三种方法: 1.对象直接量 对象直接量由若干名/值对组成的映射表,名/值对中间用冒号分隔,名/值对之间用逗号分隔,整个映射表用花括号括起来。属性名可以是JavaScript标识符也可以是字符串直接量,也就是说下面两种创建对象obj的写法是完全一样的:
2.通过new创建对象 new运算符后跟随一个函数调用,即构造函数,创建并初始化一个新对象。例如:
关于构造函数相关的内容以后再说。 3.Object.create() ECMAScript5定义了一个名为Object.create()的方法,它创建一个新对象,其中第一个参数是这个对象的原型对象(好像还没解释原型对象…下面马上就说),第二个可选参数用以对对象的属性进行进一步的描述,第二个参数下面再说(因为这第三种方法是ECMAScript5中定义的,所以以前大家才经常说创建对象的两种方法的吧?个人觉得应该是这个原因)。这个方法使用很简单:
下面三种的完全一样的:
为了解释为啥这三种方式是完全一样的,我们先来解释下JavaScript中的原型对象(哎,让客官久等了!),记得一位大神说过:
面向对象的编程语言JavaScript,没有类!!!那么,它是怎么实现继承的呢?没错,就是通过原型对象。基本上每一个JavaScript对象(null除外)都和另一个对象相关联,“另一个”对象就是所谓的原型对象(原型对象也可以简称为原型,并没有想象的那么复杂,它也只是一个对象而已)。每一个对象都从原型对象继承属性,并且一个对象的prototype属性的值(这个属性在对象创建时默认自动生成,并不需要显示的自定义)就是这个对象的原型对象,即obj.prototype就是对象obj的原型对象。 原型对象先说到这,回到上面的问题,有了对原型对象的认识,下面就是不需要过多解释的JavaScript语言规定了: ①所有通过对象直接量创建的对象的原型对象就是Object.prototype对象; ②通过关键字new和构造函数创建的对象的原型对象就是构造函数prototype属性的值,所以通过构造函数Object创建的对象的原型就是Object.prototype了; 现在也补充了第三种创建对象的方法Object.create()第一个参数的含义。 三.属性的查询和设置 学会了如何创建对象还不够啊,因为对象只有拥有一些属性才能真正起到作用滴!那么,就继续往下学习对象的属性吧! 可以通过点(.)或方括号([])运算符来获取和设置属性的值。对于点(.)来说,右侧必须是一个以属性名命名的标识符(注意:JavaScript语言的标识符有自己的合法规则,并不同于带引号的字符串);对于方括号([])来说,方括号内必须是一个字符串表达式(字符串变量当然也可以喽,其他可以转换成字符串的值比如数字什么的也是都可以滴),这个字符串就是属性的名字。正如下面例子:
概述中说过,JavaScript对象具有”自有属性“,也有“继承属性”。当查询对象obj的属性x时,首先会查找对象obj自有属性中是否有x,如果没有,就会查找对象obj的原型对象obj.prototype是否有属性x,如果没有,就会进而查找对象obj.prototype的原型对象obj.prototype.prototype是否有属性x,就这样直到找到x或者查找到的原型对象是undefined的对象为止。可以看到,一个对象上面继承了很多原型对象,这些原型对象就构成了一个”链“,这也就是我们平时所说的“原型链”,这种继承也就是JavaScript中“原型式继承”(prototypal inheritance)。 对象o查询某一属性时正如上面所说会沿着原型链一步步查找,但是其设置某一属性的值时,只会修改自有属性(如果对象没有这个属性,那就会添加这个属性并赋值),并不会修改原型链上其他对象的属性。 四.存取器属性getter和setter 上面我们所说的都是很普通的对象属性,这种属性称做“数据属性”(data property),数据属性只有一个简单的值。然而在ECMAScript 5中,属性值可以用一个或两个方法替代,这两个方法就是getter和setter,有getter和setter定义的属性称做“存取器属性”(accessor property)。 当程序查询存取器属性的值时,JavaScript调用getter方法(无参数)。这个方法的返回值就是属性存取表达式的值。当程序设置一个存取器属性的值时,JavaScript调用setter方法,将赋值表达式右侧的值当做参数传入setter。如果属性同时具有getter和setter方法,那么它就是一个读/写属性;如果它只有getter方法,那么它就是一个只读属性,给只读属性赋值不会报错,但是并不能成功;如果它只有setter方法,那么它是一个只写属性,读取只写属性总是返回undefined。看个实际的例子:
|