美文网首页
Day38:对象(二)

Day38:对象(二)

作者: 钱塘风华 | 来源:发表于2019-05-01 23:58 被阅读0次

【书名】:你不知道的JavaScript(上卷)

【作者】:Kyle Simpson

【本书总页码】:213

【已读页码】:136

1. [[Get]]

var myObject = {a: 2};

myObject.a; // 2

myObject.a 是一次属性访问,但这条语句并不仅仅是在 myObjet 中查找名字为 a 的属性。

在语言规范中,myObject.a 在 myObject 上实际上是实现了 [[Get]] 操作(有点像函数调用:[[Get]]())。对象默认的内置 [[Get]] 操作首先在对象中查找是否有名称相同的属性,如果找到就会返回这个属性的值。

如果没有找到名称相同的属性,按照 [[Get]] 算法的定义会遍历可能存在的 [[Prototype]] 链(原型链)。

如果无论如何都没有找到名称相同的属性,那 [[Get]] 操作会返回值 undefined。

注意,这种方法和访问变量时是不一样的。如果引用了一个当前词法作用域中不存在的变量,并不会像对象属性一样返回undefined,而是会抛出一个 ReferenceError 异常。

2. [[Put]]

[[Put]] 被触发时,实际的行为取决于许多因素,包括对象中是否已经存在这个属性(这是最重要的因素)。

如果已经存在这个属性,[[Put]] 算法大致会检查下面这些内容。

    属性是否是访问描述符?如果是并且存在setter就调用setter。

    属性的数据描述符中writable是否是false?如果是,在非严格模式下静默失败,在严格模式下抛出 TypeError 异常。

    如果都不是,将该值设置为属性的值。

3. Getter和Setter

对象默认的 [[Put]] 和 [[Get]] 操作分别可以控制属性值的设置和获取。

在 ES5 中可以使用 getter 和 setter 部分改写默认操作,但是只能应用在单个属性上,无法应用在整个对象上。getter 是一个隐藏函数,会在获取属性值时调用。setter 也是一个隐藏函数,会在设置属性值时调用。

当给一个属性定义 getter、setter 或者两者都有时,这个属性会被定义为“访问描述符”(和“数据描述符”相对)。对于访问描述符来说,JavaScript 会忽略它们的 value 和writable 特性,取而代之的是关心 set 和 get(还有 configurable 和 enumerable)特性。

var myObject = {

    //给 a 定义一个 getter

    get a() {return 2;}

};

Object.defineProperty(

    myObject, // 目标对象

    "b", // 属性名

    {

        // 描述符

        // 给 b 设置一个 getter

        get: function(){ return this.a * 2 },

        // 确保 b 会出现在对象的属性列表中

        enumerable: true

     }

);

myObject.a; // 2

myObject.b; // 4

var myObject = {

    //给 a 定义一个 getter

    get a() {return 2;}

};

myObject.a = 3;

myObject.a; // 2

由于只定义了 a 的 getter,所以对 a 的值进行设置时 set 操作会忽略赋值操作,不会抛出错误。而且即便有合法的 setter,由于我们自定义的 getter 只会返回 2,所以 set 操作是没有意义的。

为了让属性更合理,还应当定义 setter,和期望的一样,setter 会覆盖单个属性默认的[[Put]](也被称为赋值)操作。通常来说 getter 和 setter 是成对出现的(只定义一个的话通常会产生意料之外的行为):

var myObject = {

    //给 a 定义一个 getter

    get a() {return this._a_;},

    // 给 a 定义一个 setter

    set a(val) {this._a_ = val * 2;}

    };

    myObject.a = 2;

    myObject.a; // 4

4. 存在性

myObject.a 的属性访问返回值可能是 undefined,但是这个值有可能是属性中存储的 undefined,也可能是因为属性不存在所以返回 undefined。那么如何区分这两种情况呢?

可以在不访问属性值的情况下判断对象中是否存在这个属性:

var myObject = {a:2};

("a" in myObject); // true

("b" in myObject); // false

myObject.hasOwnProperty( "a" ); // true

myObject.hasOwnProperty( "b" ); // false

in 操作符会检查属性是否在对象及其 [[Prototype]] 原型链中。相比之下,hasOwnProperty(..) 只会检查属性是否在 myObject 对象中,不会检查 [[Prototype]] 链。

所有的普通对象都可以通过对于 Object.prototype 的委托来访问hasOwnProperty(..), 但 是 有 的 对 象 可 能 没 有 连 接 到Object.prototype( 通 过 Object.create(null) 来创建。在这种情况下,形如 myObejct.hasOwnProperty(..)就会失败。

这时可以使用一种更加强硬的方法来进行判断:Object.prototype.hasOwnProperty.call(myObject,"a"),它借用基础的 hasOwnProperty(..) 方法并把它显式绑定到 myObject 上。

关于枚举

var myObject = { };

    Object.defineProperty(myObject,"a",

    //让 a 像普通属性一样可以枚举

    { enumerable: true, value: 2 }

);

Object.defineProperty(myObject,"b",

    //让b不可枚举

    { enumerable: false, value: 3 }

);

myObject.b; // 3

("b" in myObject); // true

myObject.hasOwnProperty( "b" ); // true

// .......

for (var k in myObject) {console.log( k, myObject[k] );}

// "a" 2

可以看到,myObject.b 确实存在并且有访问值,但是却不会出现在 for..in 循环中(尽管可以通过 in 操作符来判断是否存在)。原因是“可枚举”就相当于“可以出现在对象属性的遍历中”。

也可以通过另一种方式来区分属性是否可枚举:

var myObject = { };

Object.defineProperty(myObject,"a",

    //让 a 像普通属性一样可以枚举

    { enumerable: true, value: 2 }

);

Object.defineProperty(myObject,"b",

    //让 b 不可枚举

    { enumerable: false, value: 3 }

);

myObject.propertyIsEnumerable( "a" ); // true

myObject.propertyIsEnumerable( "b" ); // false

Object.keys( myObject ); // ["a"]

Object.getOwnPropertyNames( myObject ); // ["a", "b"]

propertyIsEnumerable(..) 会检查给定的属性名是否直接存在于对象中(而不是在原型链上)并且满足 enumerable:true。

Object.keys(..) 会返回一个数组,包含所有可枚举属性,Object.getOwnPropertyNames(..)会返回一个数组,包含所有属性,无论它们是否可枚举。

in 和 hasOwnProperty(..) 的区别在于是否查找 [[Prototype]] 链,然而,Object.keys(..)和 Object.getOwnPropertyNames(..) 都只会查找对象直接包含的属性。

(目前)并没有内置的方法可以获取 in 操作符使用的属性列表(对象本身的属性以及 [[Prototype]] 链中的所有属性)。不过可以递归遍历某个对象的整条[[Prototype]] 链并保存每一层中使用 Object.keys(..) 得到的属性列表——只包含可枚举属性。

相关文章

网友评论

      本文标题:Day38:对象(二)

      本文链接:https://www.haomeiwen.com/subject/jodgnqtx.html