js权威指南-第六章

本文深入探讨JavaScript中的对象概念,包括创建对象的各种方法、属性的操作、继承机制、属性的特性及对象的锁定等高级主题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

第六章–对象

6.1 创建对象
三种方法

6.1.1 对象直接量
    对象直接量就相当于使用键值对进行对象的属性配置,类似与 json。
var empty={};//没有任何属性的对象
var point={x:2,y=0};//两个属性
......
6.1.2 通过new 创建对象

6.1.3 原型
    所有对象直列量创建的对象都具有同一个原型对象,并且通过 js代码 Object.prototype 获得对原型对象的引用。通过关键字 new 创建出来的对象的原型就是构造函数的 prototype 属性的值。
    没有原型的对象并不多, Object.prototype 就是其中之一。

6.1.4 Object.create()
    另有一个 Object.create()的方法。他创建一个对象,其中第一个对象是这个对象的原型。他提供了第二个可选参数,用以对这个对象的属性进行进一步描述。
    这是一个静态方法。
var o1=Object.create({s:1,j:6});//o1继承了属性s和j
var o2=Object.create(null); //o2 不继承任何属性和方法,甚至不含toString ,所以不可以和 ’+‘ 运算符一起工作

例6-1:通过原型继承创建一个新对象

function inherit(p){
    if(p==null)
        throw TypeError();//p 是一个对象,但不能为空
    if(Object.create)
        return Object.create(p);//直接使用它
    var t=typeof p;//否则进行进一步检测
    if(t!=="Object"&&t!=="funcrtion")
        throw TypeError();
    function f(){};//定义一个空的构造函数
    f.prototype=p;//讲其原型设定为p
    return new f(); //使用f创建p的继承对象
}

inherit函数的其中一个用途就是防止库函数无意间修改那些不受你控制的对象。不是讲对象作为参数传递给函数,而是将他的继承对象传入。当函数读取继承对象的属性进行修改时,实际上修改的只是这个继承对象本身,而不是原始对象。

6.2 属性的查询和设置
之前说过通过点(.) 或者 方括号([ ]) 可以获取属性的值。
和查询属性一样,也可以通过相同方式为对象设置属性赋值。

book.edition=6;//未book创建一个名为 edition的属性。
boook["main title"]="ECMAScript";//"main title"属性赋值
6.2.1 作为关联数组的对象
    上文说到,下面有个js表达式的值相同
object.property;
object["property"]
第二种语法更像是数组,只是这个数组元素是通过字符串索引而不是通过数字索引。这种数组就是我们说的关联数组。js对象都是关联数组。
当通过点操作符来操作属性时,属性名必须是一个标示符。标示符必须直接出现在 js 程序中。他们不是数据类型,程序无法修改他们。
当通过[] 来访问对象属性时,属性名字通过字符串表示。字符串是js数据类型,可以再运行时修改他们,因此可以使用如下代码
var addr="";
for(i=0;i<5;i++){
    addr+=consumer["address"+i];
}
6.2.2 继承

6.2.3 属性访问错误
    属性访问并不总是返回或设置一个值。
    查询一个不存在的属性并不会报错,如果在对象o之中的自身属性或者继承属性都没有找到指定属性,则讲返回 undefined 
    但是如果查询一个不存在对象的属性就会报错。
    另外有一些属性是只读的,不能别重新赋值。但是这些操作都不会报错。比如对 object.prototype 赋值不会成功而且不会报错。

6.3 删除属性
delete 操作符可以删除对象的属性。
注意 delete 只是断开对象与属性之间的关系。而不会去操作属性中的属性。
而且delete只能删除自身的属性,不能删除继承来的属性。
当删除成功或者没有任何副作用(删除不存在的属性)会返回 true。

o={x:1};
delete o.x; //删除x 返回true
delete o.x; //x已经不存在了,返回true
delete o.toString; // toSting 是继承而来的,什么也没有做,返回 true
delete 1; //无意义
delete 不能删除那些可配置性为 false 的属性。比如通过变量声明的或者函数声明的全局变量。这些情况下 delete 会返回 false
delete object.prototype;//不能删除,该属性不可配置
var x=1;//声明一个全局变量
delete this.x;//不能删除这个属性
function f(){};//声明一个全局函数
delete this.f;//也不能删除全局函数

6.4 检测属性
js可以视为属性的集。我们可以使用 in操作符,hasOwnProperty,propertyIsEnumerable 方法检测。
in 操作符左边是属性名,右边是一个对象。如果这个对象的自有属性或者继承属性包含这个属性,就返回 true。

var o={x:1};
"x" in o;//true
"y" in o;//false
"toString" in o;//true
对象的 hasOwnProperty 方法用来检测给定的名字是否是对象的自有属性。对于继承而来的属性会返回 false
var o={x:1};
o.hasOwnProperty("x");//true
o.hasOwnProperty("y");//false
o.hasOwnProperty("toString");//false
propertyIsEnumerable() 只有在检测到是自有属性而且是可枚举的才能返回 true
var o=inherit({y:2});
o.x=1;
o.propertyIsEnumerable("x");//true
o.propertyIsEnumerable("y");//false
o.propertyIsEnumerable("toString");//false .可以枚举

除了in操作符之外,还有一种更加简洁的方法来判断属性是否是 undefined。

var o={x:2};
o.x!==undefined;//true
o.y!==undefined;//false,没有这个属性
0.toString!==undefined;//true

值得注意的是 in可以区分属性存在但是值为 undefined的属性。!==操作符可能检测存在但是其值为 undefined的属性

6.5 枚举属性

6.6 属性 setter 和 gettter
定义储存器属性最简单的是使用对象直接量语法的一种扩展。

举个栗子:

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/oldvaluxe;
        this.x*=ratio;
        this.y*=ratio;
    },
    get theta(){
        return Math.atan2(this.y,this.x);
    }
};
这里函数定义没有使用 function 的关键字,而是使用 get set。而且函数自检没有使用分好分开,而是使用逗号分隔。属性也是如此。

6.7 属性的特性
可以认为一个属性包括四个特性,读取,写入,可枚举,可配置。
通过调用 Object.getOwnPropertyDescriptor() 获取某个对象特定属性的属性描述符。

//返回 {value:2,writable:true,enumerable:true,configrable:true}
Object.getOwnPropertyDescriptor({x:2,"x"});
//返回 {get:/*fun*/,set:undfined,enumerable:true,configurable:true}
Object.getOwnPropertyDescriptor(random,"octet");
//对于不存在或是继承而来的属性,将返回 undefined
Object.getOwnPropertyDescriptor({},"x");
Object.getOwnPropertyDescriptor({},"toString");
想要设置属性的特性,或者想让新建舒心具有某种特性,则需要调用 Object.defineproperty(),传入想要修改的对象、要创建或者修改的属性的名称以及属性描述符对象
var o={};
//添加不可枚举的数据属性,并赋值为1
Object.defineProperty(o,"x",{value:1,writable:true,enumerable:false,configurable:true});
//修改为只读
Object.defineProperty(o,"x",{writable:false});
//操作失败但是不会报错
o.x=2;
  • 如果对象是不可扩展的,那么可以编辑已有的自由属性,但是不能给他添加新属性
  • 如果属性时不可配置的,那么不能修改它的可配置性和可枚举性。
  • 如果存储器属性是不可配置的,则不能修改其 getter setter 方法,也不能将其转换成数据属性
  • 如果数据属性是不可配置的,则不能将它转化为存储器属性
  • 如果数据属性是不可配置的,则不能将他的可写性从false修改为true,但是可以从 true修改为 false
  • 如果数据属性是不可配置的且不可写的,则不能修改他的值。然而可配置的但是不可写的值可以修改。
//给Object.propertype 添加一个不可枚举的extend方法
//这个方法继承自调用他的对象,将作为参数传入的对象的属性一一复制
//除了值之外,也复制属性的所有特性,除非在目标对象中存在同名的属性,
//参数对象的所有自有对象(包括不可枚举的属性),也会一一复制
 Object.defineProperty(Object.property,"extend",{
    writable:true,//定义 Object.prototype.extend
    enumerable:false,//定义不可枚举
    configuration:true,
    value: function(o){
        //得到所有的自有属性,包括不可枚举属性
        var names=Object.getOwnPropertyNames(o);
        for(var i=0;i<names.length;i++){
            //如果属性已经存在 跳过
            if(names[i] in this) continue;
            //得到o中的属性的描述符
            var desc=Object.getOwnPropertyDescriptor(o,names[i]);
            //用他给this创建一个属性
            Object.defineProperty(this,names[i],desc);
        }

    }
});

6.8 对象的三个属性
6.8.1 原型属性
6.8.2 类属性
对象的类属性是一个字符串,用以表示对象的类型信息。
默认的 toString 方法返回如下格式字符串:
[object class]
所以想要获得对象的类,可以调用对象的 toString 方法。然后提取仪返回字符串的第8个字符到倒数第二个位置之间的字符。
classof() 函数可以返回传递给他的任意对象的类

function classof(o){
    if(o=null) return "Null";
    if(o=undefined) return "Undefined";
    return Object.prototype.toString.call(o).slice(8,-1);
}
6.8.3 可扩展性
    对象的可扩展性用以表示是否可以对对象添加新属性。
    可扩展性的目的是将对象锁定,以避免外界的干扰。
    Object.seal() 和 Object.preventExtensions() 类似。除了给对象位置为不可扩展之外,还可以将对象的所有自身属性都设置为不可配置的。也就是说不能给这个对象添加新对象,而且他已有的属性也不可以删除或配置,不过可写属性依然可以设置。注意对于那些已经封闭起来的对象是不能解封的,可以使用 Object.isSealed()来检测对象是否封闭。
    Object.freeze() 将更严格地锁定对象,除了将对象设置为不可扩展和将其属性设置为不可配置之外,还可以将它自由属性设置为只读的。使用 Object.isFrozen() 查询对象是否冻结。
var o=Object.seal(Object.create(Object.freeze({x:1}),{}));
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值