javascript进阶之基础篇二:对象

JavaScript对象:

1、术语
<1>、对象的描述:
ECMA-262 把对象(object)定义为“属性的无序集合,每个属性存放一个原始值、对象或函数”,对象是无特定顺序的值的数组。
对象是JavaScript的基础数据类型。除了字符串、数字、true,false,null,undefined之外,JavaScript中的所有事物都是对象。
对象不仅是字符到值的映射,除了保持自身的属性,还可以从原型的对象继承属性,对象的方法常是继承的属性,这种“原型继承”
是JavaScript的核心特征。
<2>、类的描述:
每个对象都由类定义,可以把类看做对象的配方。类不仅要定义对象的接口(interface)(开发者访问的属性和方
法),还要定义对象的内部工作(使属性和方法发挥作用的代码)。
编译器和解释程序都根据类的说明构建对象。
<3>、实例的描述:
程序使用类创建对象时,生成的对象叫作类的实例(instance)。对类生成的对象的个数的唯一限制来自于运行
代码的机器的物理内存。每个实例的行为相同,但实例处理一组独立的数据。由类创建对象实例的过程叫做实例化(instantiation)
ECMAScript 并没有正式的类。相反,ECMA-262 把对象定义描述为对象的配方,因为对象定义实际上是对象自身。即使类并不真正存
在,我们也把对象定义叫做类
2、对象的创建:
可以通过对象直接量、关键字new和(ECMAScript)Object.create()函数来创建对象
<1>、对象直接量创建对象:
对象直接量是一个表达式,每次运算都会创建并初始化一个新的对象,是由若干名/值对组成的映射表,名/值对中间冒号分隔,
名/值对之间用逗号分隔,整个映射表用花括号包含起来。
-> 属性名是可以说JavaScript标识符或者字符直接量(包括空字符串)。
-> 属性值可以为任意类型的JavaScript的表达式,表达式的值,可以说原始值也可以是对象值。
var o = {}; //没有任何属性的对象
var object = {x: 0, y: 0}; //有两个属性的对象
var a = {x: object.x, y: object + 1}; //复杂的对象
var people = {
   man: { //这个属性值是一个对象
   "make money": " yes", //属性名有空格,必须用字符串表示
   eat: "ye so"//注意这里的属性名没有用引号
   },
   "for": "buy things" //for是保留字,因此必须用引号
}
注:在IE旧的版本是ECMAScript 3标准,保留字作为属性名,必须用引号,新的浏览器版本采用的都是ECMAScript 5的标准,可以用
不带引号的保留字作为属性名,而且对象的最后一个属性名会自动忽略最后的逗号。
<2>、通过new创建对象:
new运算符创建新对象时,关键字new后面会跟着一个构造函数来初始化一个新创建的对象。
注:如果创建的对象的构造函数无参数,可以省略后面的括号。即var o=new Object和var o=new Object()。都是创建了一个对象,
尽管括号不是必需的,但是为了避免混乱,最好使用括号。
var o = new Object(); //创建一个空对象,代码创建了Object类的一个实例,并把它存储到变量o中,和{}一样
var a = new Array(); //创建一个空数组,代码创建了Array类的一个实例,并把它存储到变量a中,和[]一样
var d = new Date(); //创建一个date对象,代码创建了Date类的一个实例,并把它存储到变量d中,表示当前时间
var r = new RegExp("js");//创建一个模式匹配的RegExp对象
<3>、原型创建对象:
每一个对象(null除外)都从另外一个对象相关联,每一个对象都是从原型继承属性。
所有通过对象直接量创建的对象都具有同一个原型对象,通过Object.prototype获取原型对象的引用、通过关键字new和构造函数创
建的对象的原型就就是该对象构造函数的prototype属性的值。
故:new Object()的原型是Object.prototype等所有内置构造函数都具有一个Object.prototype的原型。
故:new Date()创建的对象的属性继承自Date.prototype和Object.prototype,这就叫原型链接。
<4>、Object.create()创建对象:(ECMAScript 5标准)
Object.create(prototype,attr)是一个静态函数,有两个参数,第一个参数是这个要创建对象的原型,第二个可选参数是用来描述
对象的属性。所以,只需要传入对象的原型即可,可以通过任意原型创建对象:
var object = Object.create({x: 1, y: 2}); //object继承了第一个参数原型的属性x和y
var object = Object.create(null); //object不继承任何属性和方法。
var o = Object.create(Object.prototype);//创建一个普通的空对象,和{}和new Object()创建对象一样
注:在ECMAScript 3标准中可以通过下面的代码模拟原型继承,可以防止函数无意间修改哪些不受你控制的对象;
不是向上面那样直接将对象作为参数传入函数demo(),而是将他继承的对象p传入函数,当函数读取继承对象p的属性时,实际读取的
是继承对象f的值,如果给继承对象的属性赋值时只会影响继承的对象f本身,而不会影响原始的对象p;
function demo(p) {
    if (p == null) {//p是一个对象,但是不能为null,
        throw TypeError();
    }
    if (object.create) {//如果object.create()对象存在,则直接使用它创建对象
        return Object.create(p);
    }
    var t = typeof p;//如果p不是对象,也不是function,则抛出异常;
    if (t !== "object" && t !== "function") {
        throw TypeError();
    }
    function f() {
    };//定义一个空构造函数
    f.prototype = p;//将其原型属性设为p
    return new f();//使用new f()创建p的继承对象。
}
var pro = {"id": "1001", "name": "zhangsan"};
var obj = demo(pro);//demo返回的demo内部新创建的对象f切f继承传入的pro的原型属性,可以防止对原本对象pro意外修改
3、对象属性的操作:
<1>、设置或获取属性:
通过(.)或者([])运算符来获取或者设置属性的值:
--在ECMAScript 3中,点运算符后的标识符保留字是非法的,比如o.for或者o.class是非法的;因为for是关键字,.class是保留字。
--在ECMAScript 5中,可以直接使用无影响。
//可以认为JavaScript对象都是关联的数组,通过字符串索引来获取属性。
var person = {"id": "1001", "name": "zhangsan"};
var id = person.id;//id=1001, 获取person的id属性
var name = person["name"];//name=zhangsan, 获取person的name属性
person.id = "1000";//设置person的id的属性为1000
person["name"] = "lisi";//设置person的name的属性为lisi
<2>、原型链:
如果查询o的x属性,o的x属性不存在,会继续找o继承的原型对象中找到属性x,如果找不到会继续在原型对象的原型查询,一直到返回原
型是null的对象为止。可以看到对象的属性构成了一个“链”,通过这个“链”实现属性的继承。在JavaScript中只会在查询属性时,
才能体会到原型链的存在,而设置属性与继承无关,让程序员有选择覆盖继承的属性,这是JavaScript的重要特性。
--假设给o的属性x赋值,属性赋值先会检查原型链,是否允许赋值操作。
--(1)、如果o继承自一个只读属性x,那么赋值不允许。
--(2)、如果o继承的属性不是只读的,允许赋值,也会只在原始对象的基础上创建属性x或者对已有的属性x赋值,而不会改变原型链。
--(3)、如果o已有属性x(这个属性不是继承来的),那么赋值操作只会改变已有属性x的值。
--(4)、如果o中不存在属性x,则赋值会给o新添加一个属性x,如果o继承原型的属性x,则继承的属性被新属性x所覆盖
var o = {};//o继承的是Object.prototype的属性
o.x = 1;//给o定义一个属性x
var p = demo(o);//p继承o和Object.prototype的属性x
p.y = 2;//给p定义一个属性y
var q = demo(p);//q继承p、o、Object。prototype的属性x和y;
q.z = 3;//给q定义一个属性z
var s = q.toString();//toString方法继承自Object.prototype
var r = q.x + q.y;//r=3,q的属性x和y分别继承自o和p;
q.x = 3;//q的x的属性值会覆盖继承的属性值。
var ox = o.x;//ox=1;q.x=3,没有修改继承自o的属性x的值。
<3>、属性访问:
属性访问并不总是返回或设置一个值。如果查询对象中并存在的属性不会报错,如果在o自身的属性中和继承的原型属性中没有找到属性
x,则返回undefined。如果对象不存在,去访问对象的属性,就会报错。只读属性,不能赋值。
注:undefined和null不存在任何属性,访问undefined和null的属性,会抛出异常,设置或者查询都会抛出异常。
var name = book.name;//name=undefined,表示属性name在对象o和继承的属性中不存在。
//在ECMAScript 5标准中,任何失败的属性操作都会抛出一个类型错误异常。
var name = book.name.length;//抛出一个错误异常,undefined没有length属性。因为o.name=undefined,undefined不存在任何属性。
//一种冗余,但是易懂的方法,
var len = undefined;
if (book) {
    if (book.name) {
        len = book.name.length;
    }
}
//更加简练的方法,用来获取获取book对象的name属性的length属性或者undefined,利用运算符&&短路的来取出值。
var len = book && book.name && book.name.length;
<4>、删除属性:
delete运算符可以删除对象的属性,只是断开属性和对象之间的关联,而不会操作属性中的属性。
var book={"id":"191","name":"平凡的世界"};
//--delete运算符只能删除自身属性,不能删除继承属性。delete删除成功后会返回true。
delete book.name;//删除属性name,返回true
delete book.name;//属性name在上面已经删除,在book对象中不存在,此时delete什么都没做,返回true;
delete book.toString;//属性toString是继承来的,不能删除继承属性,此时delete什么都没做,返回true;
delete 1;//无意思,返回true;
//--delete不能删除那些可配置性为false的属性,在非严格情况下会返回false,在ECMAScript 5标准中,严格下会抛出类型错误。
delete Object.prototype;//不能删除。属性是不可配置的。
//--通过变量声明或者函数声明床架的全局对象的属性实不可删除的
var x = 1;//声明一个全局变量
delete this.x;//不能删除全局变量。
function fun() {};//声明一个全局函数
delete this.fun;//不能删除全局函数
//--创建一个可配置的全局属性。没有用var声明
this.y=1;
delete this.y;//删除成功,严格删除。
delete y;//非严格删除,在严格模式下,会报语法错误。
<5>、判断属性是否存在:
对象可以看做属性的集合,可以通过in运算符、hashOwnProperty()和propertyIsEnumerable()方法,判断属性是否存在对象中,或者通
过属性查询判断属性是否在对象中。
//(1).in运算符:左侧是属性名,右侧是对象,如果对象自身属性或者继承属性中存在,则返回true;
var book = {"name": "诛仙", id: undefined};
name in book;//返回true, name不是book的属性
code in book;//返回false,code不是book的属性
"toString" in book;//返回true;toString继承自Object.prototype属性
//(2).hashOwnProperty()方法,检测对象自身是否有属性,如果是继承的属性将返回false;
book.hashOwnProperty("name");//返回true。name是本身属性
book.hashOwnProperty("toString");//返回false,toString是继承属性
//(3).propertyIsEnumerable()方法是hashOwnProperty()的增强版,只有检测到自身属性且这个属性可枚举性为true时他才会返回true
var p = demo(book);
p.x = 1;
p.propertyIsEnumerable("name");//返回false,name是继承来的。
p.propertyIsEnumerable("x");//返回true,x是可枚举的自有属性
Object.prototype.propertyIsEnumerable("toString");//返回false,不可枚举。
//(4).用"!=="判断一个属性是否为undefined
book.code !== undefined;//返回false,属性中没有code
book.id !== undefined;//返回false,属性存在,但是值为undefined,这种情况下只能用in
/**
 * 注:"!=="、"!="、"=="、"===" 的区别:
 * == 和 != 比较若类型不同,先偿试转换类型,再作值比较,最后返回值比较结果。而 === 和 !== 只有在相同类型下,才会比较其值。
 */
var num = 1;
var str = "1";
var test = 1;
test == num   //true 相同类型 相同值
test === num  //true 相同类型 相同值
test !== num  //false test与num类型相同,其值也相同, 非运算肯定是false
num == str   //true  把str转换为数字,检查其是否相等。
num != str   //false  == 的非运算
num === str  //false  类型不同,直接返回false
num !== str  //true   num 与 str类型不同意味着其两者不等、非运算自然是true
<6>、枚举属性:
for/in循环可以在循环体中遍历对象中所有可以枚举的属性。对象继承的内置方法是不可枚举的,代码中添加的属性是可以枚举的
var book = {"name": "诛仙", "code": "1001"};
for (b in book) {
    if (!book.hashOwnProperty(b)) continue;//跳过继承的属性
    if (typeof book[p] === "function") continue;//跳过方法
}
/**
 * 把obj中可以枚举的属性复制到book中,并返回book, 如果book中含有同名属性,则覆盖book中的属性,
 * 这个函数并不处理getter和setter以及复制属性。
 * @param book 被赋值属性的对象
 * @param obj  复制属性的对象
 * @returns {*} book对象
 */
function extend(book, obj) {
    for (o in obj) {//遍历obj的所有属性
        book[o] = obj[o];//把obj的属性复制到book中。如果不存在同名属性则添加,如果存在同名属性,则覆盖
    }
    return book;
}
/**
 * 将obj中可以枚举的属性赋复制到book中,并返回book, 如果obj和book中有同名的属性,book的属性将不受影响
 * 这个函数并不处理getter和setter以及复制属性。
 * @param book 被赋值属性的对象
 * @param obj  复制属性的对象
 * @returns {*} book对象
 */
function merge(book, obj) {
    for (o in obj) {//遍历obj的所有属性
        if (book.hashOwnProperty(o)) continue;//如果book中含有属性o,不是继承来的,则跳过。
        book[o] = obj[o];//把obj的属性复制到book中。如果不存在同名属性则添加,如果存在同名属性,则覆盖
    }
    return book;
}
/**
 * 删除同名属性
 * 如果book中含有和obj一样的属性,删除book中的属性
 * @param book 被赋值属性的对象
 * @param obj  复制属性的对象
 * @returns {*} book对象
 */
function restict(book, obj) {
    for (o in obj) {//遍历obj的所有属性
        delete book(o);//删除同名属性
    }
    return book;
}
<7>、属性getter和setter:
在ECMAScript 5标准中,属性值可以用方法代替,getter和setter,由getter和setter定义的属性称为“存取器属性”。
--setter方法:将赋值表达式右侧的值当做参数传入setter,设置属性值;
--getter方法:查询属性的值时,调用getter方法(无参数),返回的值就是属性存取表达式的值。
--读写属性:属性同时具有getter和setter方法,
--只读属性:属性只有getter方法
定义存取器属性:
/**
 * 创建一个对象book
 * 注:函数体内的this指向表示这个点的对象,JavaScript把this.name当做book对象的方法来使用了。
 * @type {{name: string, article: string, r, r, t}}
 */
var book = {
    name: "诛仙",
    article: "第一章",
    //r为可读写存取器属性,它有getter和setter
    get r() {
        return this.name + this.article;
    },
    set r(newvalue) {
        this.article = newvalue;
    },
    //t是只读存取器属性,只有getter方法
    get t() {
        return this.name + this.article;
    }
};
var bname = book.r;//诛仙第一章
book.r("第二章").t;//诛仙第二章
/**
 * 对象random可以有返回随机数的属性
 * 方法1:Math.floor()向下取整,
 * 方法2:Math.random()生成一个大于0小于等于1.0的随机数
 * @type {{octet, uint16, int16}}
 */
var random = {
    get octet() {
        return Math.floor(Math.random() * 256);
    },
    get uint16() {
        return Math.floor(Math.random() * 65536);
    },
    get int16() {
        return Math.floor(Math.random() * 65536) - 32768;
    }
};
<8>、属性特性:
一个属性包含一个属性名字和四个特性:值(value)、可写性(writable)、可枚举性(enumerable)和可配置性(configurable), 存取器属
性不具有value和writable,因为他有get和set方法,所以只有enumerable和configurable;
//设置属性的特性:Object.definePropertyOf(),不允许操作的属性会报类型错误异常
Object.definePropertyOf(o, x, {value: "张三", writable: true, enumerable: true, configurable: true});
<9>、属性描述符:
通过调用Object.getOwnPropertyDescriptor(),可以获得某个对象特定属性描述符。
//返回{value:"张三",writable:true,enumerable:true,configurable:true}
Object.getOwnPropertyDescriptor({name: "张三"}, "name");
//返回{get:/*func*/,set:undefined,enumerable:true,configurable:true}
Object.getOwnPropertyDescriptor(random, "octet");
//对于自身和不存在的属性则返回undefined
Object.getOwnPropertyDescriptor({}, "toString");//undefined,继承属性
Object.getOwnPropertyDescriptor({}, "x");//undefined,自身不存在
<10>、对象三个属性:
//--(1).原型属性:是用来继承属性,通常把对象的原型属性称为对象的原型。
//通过Object.getPrototypeOf()查询对象的原型,通过isPrototypeOf()查询是否原型;
var book = {name: "张三"};//创建一个对象book
var obj = Object.create(book);//根据book创建对象obj,obj继承自book的属性
book.isPrototypeOf(obj);//返回true,判断book是否为obj的原型。
Object.prototype.isPrototypeOf(book);//返回true,book继承自原型Object.prototype
//--(2).类属性:class attribute是一个字符串,表示对象的类型信息,默认是toString()方法返回格式字符串"[object class]"
/**
 * 获取对象的类属性
 * call([thisObj[,arg1[, arg2[, [,.argN]]]]])方法:
 * 参数:thisObj可选项。将被用作当前对象的对象。arg1, arg2, , argN可选项。将被传递方法参数序列。
 * call方法可以用来代替另一个对象调用一个方法。call方法可将一个函数的对象上下文从初始的上下文改为由thisObj指定的新对象。
 * 如果没有提供 thisObj 参数,那么 Global 对象被用作 thisObj。
 * slice(start,end)方法,从尾部开始截取,start是从字符串尾部开始算起的位置,end如果为负数,则直接从截取到尾部。
 * @param o 对象
 * @returns {*} 对象的类属性
 */
function classof(o) {
    if (o === null) return "Null";
    if (o === undefined) return "Undefined";
    //如果用传入对象o代替Object.prototype执行toString();返回值是"[object class]"
    return Object.prototype.toString().call(o).slice(8, -1);
}
//使用
classof(null);//Null;
classof(1);//Number;
classof("string");//String
//--(3).可扩展性属性:可以给对象添加新属性,所有内置对象都是显示可扩展的,宿主的可扩展性由JavaScript引擎定义的。
Object.isExtensibel();//判断对象是否可扩展
Object.preventExtensibel();//设置对象不可扩展。
Object.seal();//设置对象不可扩展,对象自身的属性不可设置,不能添加删除配置,只能可写可赋值可读。
Object.isSealed();//判断对象是否封闭。
Object.freeze();//冻结对象,对象不可扩展,所有属性设为只读的(setter方法除外)
Object.isForzen();//判断对象是否冻结。
//创建一个封闭对象,包括一个原型,和一个不可枚举的属性。
Object.seal(Object.create(Object.freeze({x: 1}), {y: {value: 2, writable: true}}));
4、序列化对象:
对象序列化是指将对象转换为字符串,也可以将字符串还原为对象。对象、数组、字符串、无穷大数字、true、false和null、都可以序
列化和还原。函数、RegExp、Error对象和undefined值不能序列化和还原。
JSON对象:JSON全称"JavaScript Object Notation"-即JavaScript对象表示法
ECMAScript5提供了内置的JSON.Stringify()和JSON.parse()用来序列化和还原JavaScript的JSON对象或JSON字符串。
可以引入http://json.org/json2.js模块在ECMAScript 3环境中使用ECMAScript 5的JSON的函数。
5、对象方法:
(1).toString()方法:没有参数,返回调用对象的字符串。很多类都带有自定义的toString()方法。
(2).toLocalString()方法:返回对象本地化的字符串。
(3).toJSON()方法:Object.prototype没有定义toJSON()方法,是JSON.stringify()内部调用的toJSON()方法,返回序列化的结果。
(4).valueOf()方法:将对象转换为原始值会调用。

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值