JavaScript Object基础(一):对象的属性

目录

理解Object的键

理解Object的属性

属性的类型:

        数据属性:

        访问器属性:


理解Object的键

        Object类型的键只有:①字符串 ②数字 ③符号(Symbol)这三种类型。如果把其它非上述三种类型的实例作为一个键,则会进行强制类型转换,将其转换为string类型。

这里举例一个简单的例子进行说明:

// 这个对象将作为一个键
const objAsKey = {
    toString() {
        return '作为一个键的对象'
    }
}

const obj = {
    // 注意,这里要用中括号属性访问器,补充一点小知识:中括号可以通过访问变量访问属性
    [objAsKey]: 'value',
};

console.log(obj); // { '作为一个键的对象': 'value' }

console.log(obj[objAsKey]); // value

console.log(obj['作为一个键的对象']); // value
// 当把一个对象作为一个对象的键时,会进行类型转换,也就是调用了toString方法

理解Object的属性

属性的类型:

Object的属性分两种:数据属性以及访问器属性

        数据属性:

        数据属性包含一个保存数据值的位置,可以理解为一个存东西的地方。数据属性有四个特性描述它的行为:

        [[Configurable]]:①能否通过delete删除并重新定义该属性 ②能否修改该属性的特性(包括其它特性) ③能否将该属性修改为访问器属性。默认情况下,直接定义在对象上的属性的这个特性是true。

// 当属性直接定义在对象上时
const obj = {
    name: 'javascript',
};

// Object.getOwnPropertyDescriptor 读取属性特性
console.log(Object.getOwnPropertyDescriptor(obj, 'name')); // {configurable: true}

Object.defineProperty(obj, 'name', { configurable: false });

// tips:严格模式会抛出错误,非严格模式会忽略这条语句
delete obj.name;  // Uncaught TypeError: Cannot delete property 'name' of #<Object>

// 一旦将属性的configurable设置为false之后就会收到限制,比如这里再将其设置为true
Object.defineProperty(obj, 'name', { configurable: true });
// 抛出错误:Uncaught TypeError: Cannot redefine property: name

// --------------------------------------------------

// 当属性通过Object.defineProperty定义时,其对应的属性的特性默认为false
Object.defineProperty(obj, 'age', {})

console.log(Object.getOwnPropertyDescriptor(obj, 'age'));  // {configurable: false}

         [[Enumberable]]:表示该属性能否被枚举。默认情况下,直接定义在对象上的属性的这个特性是true。

const obj = {
    name: 'javascript',
    age: '28',
}

// 输出 name  age 
for (let key in obj) {
    console.log(key);
}

// 尝试获得键、值以及键值对的迭代器对象
console.log(Object.keys(obj)); // ['name', 'age']

console.log(Object.values(obj)); // ['javascript', '28']

console.log(Object.entries(obj)); // [['name', 'javascript'], ['age', '28']]

// 将name的enumerable设置为false
Object.defineProperty(obj, 'name', { enumerable: false });

// 输出 age 
for (let key in obj) {
    console.log(key);
}

// 尝试获得键、值以及键值对的迭代器对象
console.log(Object.keys(obj)); // ['age']

console.log(Object.values(obj)); // ['28']

console.log(Object.entries(obj)); // [['age', '28']]

// 还是可以通过Object.getOwnPropertyNames枚举出该属性(不包括Symbol值作为键的属性)
console.log(Object.getOwnPropertyNames(obj)); // ['name', 'age']

        [[Writable]]:表示该属性能否被修改。默认情况下,直接定义在对象上的属性的这个特性是true。

"use strict"
// 直接定义在对象上的属性的该特性默认为true
const obj = {
    name: 'javascript',
};

obj.name = 'C#';

console.log(obj.name); // 'C#'

Object.defineProperty(obj, 'name', {
    writable: false,
})

// 严格模式下会抛出错误,非严格模式会忽略对它的重新赋值
obj.name = 'java'; // Uncaught TypeError: Cannot assign to read only property 'name' of object '#<Object>'

console.log(obj.name); // 'C#'

// 通过Object.defineProperty定义的属性的该特性默认为false
Object.defineProperty(obj, 'age', {});

// 严格模式下会抛出错误,非严格模式会忽略对它的重新赋值
obj.age = 28; // Uncaught TypeError: Cannot assign to read only property 'age' of object '#<Object>'

console.log(obj.age);  // undefined (未赋值,默认为undefined)

        [[Value]]:包含属性的实际值(注意前面说的包含!是读取和写入属性值的位置!)。默认值是undefined。

const obj = {};

Object.defineProperty(obj, 'name', { value: 'javascript' });

console.log(obj.name); // javascript

// 默认为undefined
Object.defineProperty(obj, 'age', {});

console.log(obj.age); // undefined

        访问器属性:

        访问器属性是不包含数据值的,它包含一个对属性的访问器(get)和修改器(set)。

        [[Configurable]]:①能否通过delete删除并重新定义该属性 ②能否修改该属性的特性(包括其它特性) ③能否将该属性修改为数据属性。默认情况下,直接定义在对象上的属性的这个特性是true。

        [[Enumberable]]:表示该属性能否被枚举。默认情况下,直接定义在对象上的属性的这个特性是true。

        [[Get]]:获取函数。读取属性时调用,默认为undefined。

        [[Set]]:设置函数。设置属性时调用,默认为undefined。

        如果只定义了该属性的get函数,那么就意味着这个属性是只读的,如果尝试修改属性的值,在非严格模式下会忽略,而严格模式下会抛出错误。

        类似,如果只定义了该属性的set函数,那么就意味着该属性是只写的,如果尝试读取该属性的值,在非严格模式下返回undefined,严格模式下抛出错误。

        定义属性的访问器和修改器有两种方式:①在对象初始化时 ②通过Object.defineProperty

const obj = {
    age_ : 10,

    get age() {
        return this.age_;
    },
    
    set age(value) {
        this.age_ = value;
    }
}

console.log(obj.age); // 10

obj.age = 20;

console.log(obj.age); // 20

        这里有一个需要注意的地方,就是为什么get函数不直接返回this.age呢?因为这样会导致栈溢出错误。set函数同理。

const obj = {

    get age() {
        return this.age;  // this.age 会调用age的get函数,因此产生栈溢出错误
    },
}

console.log(obj.age); // Uncaught RangeError: Maximum call stack size exceeded

         方式一:在对象初始化时定义get、set函数

"use strict";
// 第一种方式:在对象初始化时定义get、set函数
const obj = {
    // 同时定义了get、set函数
    age_: 28,
    get age() {
        return this.age_;
    },
    set age(value) {
        this.age_ = value;
    },

    // 只定义了get函数
    name_: 'javascript',
    get name() {
        return this.name_;
    },

    // 只定义了set函数
    gender_ :'男',
    set gender(value) {
        this.gender_ = value;
    },
}
// 能够读取、修改同时定义了get、set函数的属性
console.log(obj.age); // 10
obj.age = 20;
console.log(obj.age); // 20

// 只能读取属性值
console.log(obj.name);
// 非严格模式下忽略赋值,严格模式下抛出错误
obj.name = 'typescript'; // Uncaught TypeError: Cannot set property name of #<Object> which has only a getter
console.log(obj.name);

// 只能修改属性值
console.log(obj.gender); // undefined
// 这里理论上存在报错,但是实际并没有,无论是在严格模式或者非严格模式
obj.gender = '女';
console.log(obj.gender); // undefined

         方式二:通过Object.defineProperty定义get、set函数

"use strict";

// 第二种方式:通过Object.defineProperty定义get、set函数
const obj = {
    name_: 'javascript',
};
// 同时定义get、set
Object.defineProperty(obj, 'name', {
    set: function (value) {
        this.name_ = value;
    },
    get: function () {
        return this.name_;
    }
})

console.log(obj.name); // javascript

obj.name = 'java';

console.log(obj.name); // java

        tips:除了以上两种方式外,在ES5之前,还可以通过两个非标准的方法创建访问器属性:__defineGetter__  以及 __defineSetter__,但是这两个方法已经废弃了,不建议使用

const obj = { 
    name_: 'javascript',
};

obj.__defineGetter__("name", function () {
    return this.name_;
});

obj.__defineSetter__("name", function (value) {
    this.name_ = value;
})

console.log(obj.name); // javascript

obj.name = 'java';

console.log(obj.name); // java

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值