JavaScript中的对象
关键词: JavaScript 对象
创建对象的方式:
1. new运算符
var o = new Object();//创建一个空对象(即没有任何属性的对象);
var now = new Date(); //创建当前的日期和时间。
var new_years_eve = new Date(2000,12,31); //创建2000年12月31日
2. 对象直接量
大括号里 属性:属性值构成。
var empty = {} //创建一个没有属性的对象。
var point = {x:0,y:0};
var circle = {x:point.x, y:point.y, radius:2};
var homer = {
name:”Homer Simpson”,
age:34,
married:true,
occupation:”plant operator”,
email:”homer@example.com”
}
构造函数:
由new运算符调用,new 操作符先创建一个空对象,然后将该对象作为构造函数的this值,并调用构造函数来初始化这个对象。(具体见原型节)
实例:
// 定义一个构造函数,注意怎样通过”this”引用来初始化对象的。
function Rectangle(w, h) {
this.width = w;
this.height = h;
}
// 调用构造函数创建两个对象。
var rect1 = new Rectangle(2, 4); // rect1 = { width:2, height:4 };
var rect2 = new Rectangle(8.5, 11); // rect2 = { width:8.5, height:11 };
对象的属性:
属性的访问:用“引用对象.属性”方式。例如o.p(访问引用对象o的属性p)。例子:
var book = {}; //用对象直接量的方式声明一个对象。
book.title = “javascript: The Definitive Guide"; //设置一个属性。
book.chapter1 = new Object(); //设置一个属性,该属性引用了另一个对象。
book.chapter1.title = “Introduction to JavaScript”; //设置一个属性(嵌套的对象)的属性
book.chapter1.pages = 11;
book.chapter2 = {title: "Lexical Structure", pages: 6} //对象直接量的方式,声明一个属性
alert("Outline: " + book.title + "/n/t" + //读取属性值
"Chapter 1 " + book.chapter1.title + "/n/t" +
"Chapter 2 " + book.chapter2.title);
注意:可以通过把一个值赋给对象的新属性来创建一个新的属性,绝不能像声明变量一样用var来创建属性。一旦创建了新属性,就可以随时随地修改它。
枚举一个对象的属性:在调试时很有用,因为该对象可能拥有我们无法事先获知的属性
function DisplayPropertyNames(obj) {
var names = "";
for(var name in obj) names += name + "/n";
alert(names);
}
注意:for/in循环列出的属性并无特定顺序,虽然它能枚举出所有的用户定义的属性,却不能枚举出某些预定义的属性和方法。
检查属性是否存在:可用“in”操作符检查一个对象是否有某个属性:eg:if(“x” in o) o.x = 1;①
如果访问一个并不存在的属性,将返回“undefined”。因此上述代码常写成:if(o.x != “undefined”) o.x = 1;②
注意:存在这种情况,某个属性存在但该属性仍然返回“undefined”。比如你写了如下代码:o.x = undefined;。在这种情况下,代码①将设置x为1,代码②将不做任何操作。
删除属性:delete o.x;(不是简单的将属性设为undefined,而是真正的从对象中删除该属性。)
对象的方法:
方法无非就是一个存储在对象的某个属性并且需要通过对象来调用的JavaScript函数。记住JavaScript中函数是一种数据,它们的名字只不过是一个用来保存函数对象的变量的名称而已,所以你可以把这个函数对象赋给任何变量甚至一个对象的任何属性。比如已经有了函数f(),就可以用o.m = f;给对象o定义一个方法m(),以后可以用o.m()来调用这个方法了。
方法有一个重要的属性:在方法体内”this”关键字的值是调用该方法的对象。例如:
var calculator = { //定义一个对象。
operand1: 1, //定义属性operand1,值为1。
operand2: 1, //定义属性operand2,值为1。
compute: function() { //定义方法computer。
this.result = this.operand1 + this.operand2; //方法体。另:calculator对象多了一个result属性。
}
};
calculator.compute(); // What is 1+1?
print(calculator.result); // Display the result
虽然,我们应该区分“函数”与“方法”,但实际上它们的差别并不像原来那么大了。调用一个函数时,实际是调用全局对象的一个方法,this引用的是全局对象。
对象通用的属性和方法:
因为javascript所有的对象都从Object继承,所以了解Object固有的属性和方法很重要。
1. constructor属性
该属性引用构造函数(初始化对象的函数)。eg:var d = new Date(); //d.constructor引用的是Date;
该属性可以用来确定一个对象的类型。eg:if( (typeof o == “object”)&&(o.constructor == Date) )或采用instanceof操作符if ( (typeof o == "object") && (o instanceof Date) )
2. toString()方法
用来显示对象信息。(见E9)
3. toLocaleString()方法
用来显示一段本地化的信息,常与toString()相同。一般子类可以重定义自己的toLocaleString()方法。如Array、Date、Number类的toLocaleString()。
4. valueOf()方法
当一个对象转化为它的父类时,自动调用。(见E9)
5. hasOwnProperty()方法
如果一个对象的属性是自己定义的,那么该方法返回true。eg:
var o = {};
o.hasOwnProperty("undef"); // false: 该属性未定义
o.hasOwnProperty("toString"); // false: toString 是继承来的属性
Math.hasOwnProperty("cos"); // true: Math 对象有自己定义的cos属性。
6. propertyIsEnumerable()方法
如果一个对象的属性是自己定义的,并且该属性可以用一个“for/in”循环列举,那么该方法返回true。eg:
var o = { x: 1 };
o.propertyIsEnumerable("x"); // true: x属性存在并且是可列举的。
o.propertyIsEnumerable("y"); // false: y属性不存在。
o.propertyIsEnumerable("valueOf"); // false: valueof属性是继承来的。
注意:一个对象中所有用户自定义的属性都是可列举的。不可列举的属性有代表性的是继承来的属性(详见E9),所以这个属性的返回值基本与hasOwnProperty()方法相同。
7. isPrototypeOf()方法
如果调用这个方法的对象是实参的原型对象,那么该方法返回true。eg:
var o = {}
Object.prototype.isPrototypeOf(o); // true: o.constructor == Object
Object.isPrototypeOf(o); // false
o.isPrototypeOf(Object.prototype); // false
Function.prototype.isPrototypeOf(Object); // true: Object.constructor==Function
原型
为了效率,javascript采用了一种方案:每个对象都包含一个“内反射”到另一个对象,即它的原型对象。每个javascript对象都从它的原型继承属性。
创建一个对象的详细过程:
new 操作符先创建一个空对象,然后new操作符设置这个对象的原型。一个对象的原型是它的构造函数的”prototype”属性的值。任何函数都有”prototype”属性,它是函数定义时自动创建和初始化的。”prototype”属性的初始值是一个只有唯一属性”constructor”的对象。”constructor”属性回头引用到原型关联的构造函数。原型对象的所有属性都将成为对象的属性。
注意:属性并不是从原型copy到新的对象,它们仅仅是看起来像是对象的属性而已。这有两点重要的含义,一可以减少每个对象要求的内存量,因为它们可以从原型中继承很多。二对象可以继承原型中的所有属性,即使是在对象创建好后才向原型加入的新属性。
实例:
// 构造函数初始化那些每个实例都不同的属性
function Rectangle(w, h) {
this.width = w;
this.height = h;
}
// 原型对象保存那些每个实例都共享的属性/方法
Rectangle.prototype.area = function( ) { return this.width * this.height; }
//建立一个对象
var r = new Rectangle(2, 3);
r.hasOwnProperty("width"); // true: width 是r的直接属性。
r.hasOwnProperty("area"); // false: area 是r继承来的属性。
"area" in r; // true: "area" 是r的属性。
读对象o的属性p时,JavaScript首先查询o是否具有属性p,如果o没有,就进一步查询o的原型对象是否有属性p。这就是以原型为基础的继承机制如何工作的。但是当写对象o的属性p时,JavaScript是用不到原型对象的。尽管属性p可能是从原型继承来的,但是当你写属性p的值时,JavaScript为对象o创建了一个新属性p。这样o的属性p就“隐藏”了原型对象的属性p了。当你再次读属性p时,因为JavaScript发现了o自己的属性p,它就不必再查询原型对象了。
常把方法(对每个对象来说都是相同的)或常量(比如数学常量等)定义在原型属性里。也可以把那些想在对象创建时就能被初始化值的属性放在原型里定义,这样对象创建后就会有统一的默认值了。
对象是关联数组
所以访问对象的属性也可以用[]操作符,例如object.property可以写成object["property"]。此时的属性名称是一个字符串,这就使我们可以动态的构建该字符串来访问对象相应的属性。eg:
var c = new Circle(1,2,3);
var tmp = c[“radius”]; //访问c. radius
c[“addedProperty”] = “this is a addedProperty”; //c从此有了一个c.addedProperty属性
c[0] = "this is an array element of an object!" //给c创建了一个名为0的属性。(该属性有点特殊,只能用c[0]/c[“0”]访问,不能用c.0访问,有待研究。)
数组
JavaScript的数组元素可以是任意类型,一个数组中的元素也可以是不同类型。应该说,数组在JavaScript内置的一种提供了额外功能的对象。一些数组实例:
var empty = []; // 一个空数组
var primes = [2, 3, 5, 7, 11]; // 一个有五个数字元素的数组
var misc = [ 1.1, true, "a", ]; // 三个元素是不同类型
var base = 1024;
var table = [base, base+1, base+2, base+3]; //数组元素可以是表达式
var b = [[1,{x:1, y:2}], [2, {x:3, y:4}]]; //数组元素可以是数组或对象
var count = [1,,3]; // 第二个元素未定义
var undefs = [,,]; // 两个元素都未定义的数组
也可以通过Array()构造函数来创建数组。eg:
var a = new Array(); //空数组,相当于var a = [];
var a = new Array(5, 4, 3, 2, 1, "testing, testing"); //参数可以是任意类型,length属性自动设置为参数数目。
var a = new Array(10); //参数是一个单独的数字,将创建指定长度的数组。10个元素,每个元素都置为undefined。
按索引来访问数组元素,索引是从0开始的。eg:a[0] = 3;
如果用一个无效的索引(比如字符串,布尔值等等),只会使数组创建一个新属性,而不是一个新元素。eg:a[-1.23] = true;
JavaScript中的数组索引是可以不连续的,eg:a[0] = 1; a[10000] = "this is element 10,000"; //解析器只会给索引为0、10000的元素分配内存,其他9999个元素是不占内存的。
如果用delete删除一个元素,只会将该元素置为undefined,元素本身还是存在的。若想真正从数组中删除一个元素,必须用array类提供的方法:Array.shift()删除第一个元素,Array.pop()删除最后一个元素,Array.splice()删除数组中的元素。
任何数组都有一个特殊的属性length,该属性是可读写的,如果为length赋了一个小的值,那么数组会自动截断,如果赋了一个大的值,数组会自动在末尾追加“undefined”元素。
尽管JavaScript不支持多维数组,但可以用元素为数组的数组来模拟。访问时用matrix[x][y]即可。
数组的方法
join()
将所有的元素连接成一个字符串。参数为分割符号。eg:
var a = [1, 2, 3]; var s = a.join(); // s == "1,2,3" 默认分割符为”,”
reverse()
将数组倒序排列,eg:
var a = new Array(1,2,3); a.reverse(); // now a[0] = 3, a[1] = 2, a[2] = 1
sort()
将数组进行排序。默认的是按字符排序并” undefined “元素放在最后。eg:
var a = new Array("banana", "cherry", "apple"); a.sort(); // a[0]="apple” a[1]=”banana” a[2]=”cherry"
如果想用自己的规则排序,必须传入一个比较函数。该比较函数应能确定它自己的两个参数谁前谁后,如果第一个参数在前,比较函数应返回<0;如果第二个参数在前,比较函数应返回>0;eg:
var a = [33, 4, 1111, 222];
a.sort(); // 默认按字符顺序:1111, 222, 33, 4
a.sort(function(a,b) { //自定义的按数字顺序: 4, 33, 222, 1111 这里使用了函数直接量,因为该函数只在这一个地方有用。
return a-b;
});
concat()
连接数组,返回新创建的连接后的新数组。eg:
var a = [1,2,3];
var b = a.concat(4,5); //b = [1,2,3,4,5];
var c = a.concat([4,5]); //c = [1,2,3,4,5]
var d = a.concat([4,5],[6,7]); //d = [1,2,3,4,5,6,7]
var e = a.concat(4,[5,[6,7]]); //e = [1,2,3,4,5,[6,7]]
slice()
返回子数组。参数为起始索引(闭区间),结束索引(开区间)。如果只有一个参数,则认为是起始索引至末尾。如果参数为负数,则是相对最后一个元素而言的,如-1为最后一元素。eg:
var a = [1,2,3,4,5];
a.slice(0,3); //Returns [1,2,3] a.slice(1,3); //Returns [2,3] a.slice(1,5); //Returns [2,3,4,5] a.slice(1,4); //Returns [2,3,4]
a.slice(3); // Returns [4,5]
a.slice(1,-1); // Returns [2,3,4]
a.slice(-3,-2); // Returns [3]
splice()
在数组中插入/删除元素(真实删除而不是置undefined)。返回值为被删除元素组成的数组。
删除:需要指定两个参数,即开始索引、要删除的数目。如果只有一个参数,则认为是开始索引至末尾。eg:
var a = [1,2,3,4,5,6,7,8];
a.splice(4); // Returns [5,6,7,8]; a = [1,2,3,4]
a.splice(1,2); // Returns [2,3]; a = [1,4]
a.splice(1,1); // Returns [4]; a = [1]
插入:需要指定三个(以上)的参数,即开始索引、要删除的数目、要插入的元素。eg:
var a = [1,2,3,4,5];
a.splice(2,0,'a','b'); // Returns []; a = [1,2,'a','b',3,4,5]
a.splice(2,2,[1,2],3); // Returns ['a','b']; a = [1,2,[1,2],3,3,4,5]
push() / pop()
像栈一样来操作数组。
push()将元素附加到数组尾部,返回值为数组的新长度。
pop()删除数组的最后一元素。返回值为被删除的元素。eg:
var stack = []; // stack: []
stack.push(1,2); // stack: [1,2] Returns 2
stack.pop(); // stack: [1] Returns 2
stack.push(3); // stack: [1,3] Returns 2
stack.pop(); // stack: [1] Returns 3
stack.push([4,5]); // stack: [1,[4,5]] Returns 2
stack.pop() // stack: [1] Returns [4,5]
stack.pop(); // stack: [] Returns 1
unshift() / shift()
在数组的头部进行栈操作。
unshift()将元素添加到数组头部,返回值为数组的新长度。
shift()删除数组的第一个元素。返回值为被删除的元素。eg:
var a = []; // a:[]
a.unshift(1); // a:[1] Returns: 1
a.unshift(22); // a:[22,1] Returns: 2
a.shift(); // a:[1] Returns: 22
a.unshift(3,[4,5]); // a:[3,[4,5],1] Returns: 3 注意一次插入多个元素的情形。
a.shift(); // a:[[4,5],1] Returns: 3
a.shift(); // a:[1] Returns: [4,5]
a.shift(); // a:[] Returns: 1
toString() / toLocaleString()
与所有的JavaScript对象一样,数组也有toString()。该方法与无参数调用join()是返回的字符串相同。eg:
[1,2,3].toString() // 生成 '1,2,3'
["a", "b", "c"].toString() // 生成'a,b,c'
[1, [2,'c']].toString() // 生成 '1,2,c'
toLocaleString() 是 toString().的本地化版本。
类数组对象(类似数组的对象)
JavaScript可以让一些对象具有length属性,从而使之看起来像数组,虽然不能让它能调用数组的方法,但是可以像数组一样用length属性来遍历。比如Arguments对象就是一个类数组对象。在客户端JavaScript中,一些DOM方法比如document.getElementsByTagName()返回值也是一个类数组对象。
本文深入讲解JavaScript中的对象概念,包括创建对象的各种方式、对象属性与方法的定义及使用、原型链的工作原理,以及数组这种特殊对象的特点和常用操作。
401

被折叠的 条评论
为什么被折叠?



