Object

179 阅读7分钟

not finished

一、对象Object的属性

参考《JavaScript高级程序设计》(第三版) MDN

Object属性类型分为数据类型和访问器属性

  • 数据属性
    • [[configurable]]:即以下这些属性能否被更改。默认true。(相当于总开关)
    • [[enumerable]]:表示能否通过for-in循环。默认true
    • [[writable]]:表示能否修改属性的值。默认true
    • [[value]]:包含这个属性的数据值。(注意是值)。默认undefined
      注:非严格模式下,赋值会被忽略。严格模式下,赋值会报错
  • 构造器属性
    访问器属性不包含数据值:它们包含一对getter和setter函数,它们决定了如何处理数据。在读取访问器属性时候,会调用getter函数,负责返回有效的值;在写入访问器属性时,会调用setter函数并传入新值,这个函数决定如何处理数据。有如下四个特性
    • [[configurable]]:总开关,默认true
    • [[enumrable]]:表能否通过for-in循环返回属性不是枚举吗,默认true
    • [[get]]:在读取属性时调用的函数。默认undefined
    • [[set]]:在写入属性时调用的函数。默认undefined
      注:访问器不能直接定义,必须使用Object.defineProperty()定义
    //get和set的示例
    var book = {
        _year: 2004,
        //下划线是一种常用记号,用于表示只能通过对象方法访问的属性
        edition: 1
    };
    Object.defineProperty(book,'year',{
        //而访问器year则包含了一个getter函数和setter函数。
        get:function() {
            return this._year;
        },
        set:function(newValue) {
            if (newValue > 2004) {
                this._year = newValue;
                this.edition += newVaule -2004;
            }
        }
    });
    //这是使用访问器属性的常见方式。即设置一个属性的值会导致其他属性发生变化
    set是会遍历全部属性吗?
    

支持ECMAScript5的Object.defineProperty这个方法的浏览器有IE9+(IE8只是部分实现)、Firefox4+、Safari5+、Opera12+和chrome。在这个方法之前,要创建访问器属性,一般都使用两个非标准的方法__defineGetter__()和__defineSetter__方法。最初是由Firefox引入的。使用这两个遗留的方法,可以像下面这样重写前面的例子:

var book = {
    _year : 2004,
    edition: 1
};
//定义访问器的旧有方法
book.__defineGetter__('year',function(){
    return this._year;
});
book.__defineSetter__('year',function(newValue){
    if (newValue > 2004) {
        this._year = newValue;
        this.edition += newVaule -2004;
    }
});
book.year = 2005;
alert(book.edition);//2

注:在不支持Object.defineProperty()方法的浏览器中不能修改[[congigurable]]和[[enmerable]]

  • ESMAscript5又定义了一个Object.definePropertries()方法。可以定义多个属性
var book = {};
Object.defineProerties(book,{
    _year: {
        value:2004
    },
    edition:{
        value:1
    },
    year: {
        get: function() {
            return this._year;
        },
        set: funciton(){
            if(newValue>2004){
                this._year = newValue;
                this.edition += newavalue - 2004;
            }
        }
    }
});

以上代码在book对外定义了两个数据属性(_year和edition)和访问器属性(year)。最终的对象与上面用defineProperty()方法定义的对象相同。唯一的区别是这里的属性都是同一时间定义的。
支持Object.defineProperties()方法有IE9+、Firefox4+、Safari5+、Opera12+和Chrome

读取属性的特性

ESMASCript5的Object.getOwnPropertyDescriptor()方法,可以取得该给定属性的描述符。
参数:属性所在和对象和要读取其扫描符的属性名称。
返回值:该对象
如果是访问器属性,这个对象有congiurable、eunmerable、writable和value

var book = {};
Object.defineProerties(book,{
    _year: {
        value:2004
    },
    edition:{
        value:1
    },
    year: {
        get: function() {
            return this._year;
        },
        set: funciton(){
            if(newValue>2004){
                this._year = newValue;
                this.edition += newavalue - 2004;
            }
        }
    }
});
var descriptor = Object.getOenPropertyDescriptor(book,'_year');
alert(descriptor.value);//2004
alert(descriptor.cinfigurable);//false
alert(typeof descriptor.get);//undefined

var descriptor = Object.getOwnPropertyDescriptor(book,"year");
alert(descriptor.value);//"undefined"
alert(descriptor.enumerable);//false
alert(descriptor.get);//"function"

对于数据属性_year,value等于最初的值。configurable是false,而get等于undefined。对于访问器year,value等于undefined,configurable是false,而get是一个指向getter函数的指针。
在JavaScript中,可以针对任何对象——包括DOM和BOM对象,使用Object.getOwnPropertyDescription()方法,支持这个方法的浏览器有IE9,Firefox4+,Safari5+,Opera12+和Chrome

二、Object.defineProperty()

摘自MDN的Object.property()

  • Object.defineProperty(obj,prop,description)用于定义或修改对象的属性,并返回这个对象
    • obj:要定义的对象
    • prop:要定义或修改的属性
    • description:要定义或修改的属性描述符
    • return:被传递给函数的对象
    • 注:用Symbol定义的对象的key与常规的修改不同,**如何不同?**然后Object.defineProperty是定义key为Symbol的属性的方法之一
  • 通过赋值操作条件的普通属性是可枚举的(for...in或Object.keys),这些属性的值可以被改变,也可删除。默认情况,使用Object.defineProperty()添加的属性值是不可修改的。
  • 属性描述符
    对象里目前存在的属性描述符有主要两种形式 :
    • 数据描述符(default):具有值的属性
    • 存取描述符:由getter-setter函数对描述的属性
    • 描述符必须是这两种形式之一,不能同时是两者
      数据描述符和存取描述符具有以下可选键值:
    • configurable:该属性描述符能否被改变,默认false
    • enumerable:能否枚举,默认false
      数据描述符同时具有以下可选健值
    • value:该属性对应的值。默认undefined
    • writable:value能否被赋值运算符改变。默认false
      存取描述符同时具有以下可选健值
    • get:一个给属性提供getter的方法。默认undefined。当访问该属性实,执行。方法执行时没有参数传入,但是会传入this对象(由于继承关系,这里的this并不一定是定义该属性的对象)
    • set:一个给属性提供setter的方法。默认undefined。当属性值修改时,触发该方法。参数:即该属性新的参数值

注:这些选项不一定是自身属性,如果是继承来的也要考虑。为了却保留这些默认值,可能需要在这之前冻结Object.propertype。明确指定所有的选项,或者通过Object.create(null)将__proto__属性指向null。不理解

//使用__proto__
var obj = {};
var descriptor = Object.create(null);//没有继承属性
//默认没有enumerable,configurable,writable
descriptor.value = 'static';
Object.defineProperty(obj,'key',descriptor);

//显示
Object.defineProperty(obj,"key",{
    enmerable: false,
    configurable: false,
    writable: false,
    value: "static"
});

//循环使用同一对象
//这怎么循环的?
function withValue(value){
    var d = withValue.d||(
        withVAlue.d = {
            enumable: false,
            writable: false,
            configurable: false,
            value: null
        }
    )
    d.value = value;
    return d;
}
//并且
Object.defineProperty(obj,"key",withValue("static"));

//如果freeze可用,防止代码添加或删除对象原型的相互
//(value,get,set,enumerable,writable,configurable)
(Object.freeze||Object)(Object.prototype);
  • 示例
    • 创建属性
var a = {};
//在对象中添加一个顺序与数据描述符的示例
Object.defineProperty(o,"a",{
    value: 37,
    writable: true,
    enumerable: true,
    configurable: true
});
//在对象中添加一个属性与存取描述符的示例

* 修改属性
* 添加多个属性和默认值
* 一般的setters和getters
* 继承属性

三、Object.prototype

  • Object.properto属性表示Object的原型对象
    该属性的属性特性
    • writable:false
    • enumerable:false
    • configurable:false

  • 描述
    几乎所有的JavaScript对象都是Object的实例。(谁不是),一个典型的对象继承了Object.prototype的属性(包括方法),尽管这些属性可能被覆盖。但有时候可能故意创建不具有典型原型链继承的对象。比如通过Object.create(null)创建的对象,或者通过Object.setPrototypeOf方法改变原型链。
    改变Object原型,会通过原型链链改变所有对象;除非在原型链中进一步覆盖受这些变化影响的属性和方法。这提供了一个非常强大、但有潜在危险的机制来覆盖或扩展对象行为。

  • 属性
    • Object.prototype.constructor:
    • Object.prototype.proto:
    • Object.prototype.noSuchMethod:

  • 方法
    • hasOwnProperty()
    • isPrototypeOf()
    • propertyIsEnumerable()
    • toSource()
    • tolocaleString()
    • toString()
    • unwatch()
    • valueOf()

Object构造函数的方法

  • Object.assign(target,...sources)
    把...source复制到target。return target
    只拷贝可枚举的属性

  • Object.create(obj)
    使用现有对象来提供新创建的对象的__proto__

  • Object.entries(obj)
    返回给定对象自身可枚举属性的[key,value]数组

  • Object.freeze(obj)
    冻结对象:这个对象不能被修改 删除

  • Object.is(value1,value2)
    有以下任一项成立,则两值相等

    • 两个值都是undefined|null|true|false
    • 两个值都指向同一个对象
    • 两个值是由相同个数的字符按照相同的顺序组成的字符串
    • 两个值都是数字且:
      • 都是+0|-0|NaN|
      • 都是除0和NaN外的其他同一个数字

    是为了解决NaN===NaN(false)等问题
    ==会进行类型转换,Object.is()不会

  • Object.getPrototypeOf(obj)
    返回其原型的对象,若无返回null

  • Object.setPrototypeOf(obj,prototype)
    给obj设置一个新原型prototype(一个对象或null)