继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

JavaScript中的对象

为爱心太软
关注TA
已关注
手记 170
粉丝 1.4万
获赞 860

基本概念

对象是无序属性的集合,其属性值可以是基本数据类型(Boolean、Number、String等),也可以是引用类型(Object、Array、Function等)。对象的每个属性都有一个key(可以理解为属性名),而每个key都映射一个value(值)。

例子:

var obj = {
    name: "new obj",
    action: function() {
        return this.name
    }
}

Key 键

key拥有4个数据属性和4个访问器属性:

1、 数据属性

[[configurable]]:表示能否通过delete删除属性从而重新定义属性,默认值为true。
[[enumerable]]:表示能否通过for-in循环返回属性,默认值为true。
[[writable]]:表示能否修改属性的值,默认值为true。
[[value]]:该属性的值,默认值为undefined。

要创建或修改key的4个数据属性值,需要使用Object.defineProperty()方法。这个方法接收三个参数:属性所在的对象,属性名和描述符对象。

例子:

var obj = {
    name: "new obj",
    action: function() {
        return this.name
    }
}

//使用Object.defineProperty()方法为对象obj创建新属性:age
Object.defineProperty(obj, "age", {
    configurable: true,
    enumerable: true,
    writable: true,
    value: 20
})

测试代码:

//测试1:configurable: false
var obj = {
    name: "new obj",
    action: function() {
        return this.name
    }
}

Object.defineProperty(obj, "age", {
    configurable: false,
    enumerable: true,
    writable: true,
    value: 20
})
delete obj.age;
console.log(obj.age);
//输出:20
//说明删除age属性失败
//测试2:enumerable: false
var obj = {
    name: "new obj",
    action: function() {
        return this.name
    }
}
Object.defineProperty(obj, "age", {
    configurable: true,
    enumerable: false,
    writable: true,
    value: 20
})
for (k in obj) {
    console.log(k);
}
//输出:name、action
//说明遍历age属性失败
//测试3: writable: false
var obj = {
    name: "new obj",
    action: function() {
        return this.name
    }
}
Object.defineProperty(obj, "age", {
    configurable: true,
    enumerable: true,
    writable: false,
    value: 20
})
obj.age = 18;
console.log(obj.age);
//输出:20
//说明修改age属性失败

注意:

1、使用Object.defineProperty()方法创建的属性,如果不指定configurable、enumerable和writable的值,默认值为false,而用其他方式创建的属性,configurable、enumerable和writable的默认值为true。

测试代码:

*可以使用Object.getOwnPropertyDescriptor()方法读取属性的数据属性和访问器属性。

var obj = {
    name: "new obj",
    action: function() {
        return this.name
    }
}
Object.defineProperty(obj, "age", {
    value: 20
})

console.log(Object.getOwnPropertyDescriptor(obj, "name"));
//输出:{value: "new obj", writable: true, enumerable: true, configurable: true}
console.log(Object.getOwnPropertyDescriptor(obj, "age"));
//输出:{value: 20, writable: false, enumerable: false, configurable: false}

2、可以多次调用Object.defineProperty()方法修改同一个属性,但在把configurable设置为false之后,再调用Object.defineProperty()方法修改configurable和enumerable,就会导致错误。

测试代码:

//测试1:第二次修改 writable和value
var obj = {
    name: "Tom",
    action: function() {
        return this.name
    }
}
Object.defineProperty(obj, "name", {
    configurable: false,
    enumerable: true,
    writable: true,
    value: "Amy"
})

Object.defineProperty(obj, "name", {
    writable: false,
    value: "Lili"
})
console.log(obj.name);
//输出:Lili
//第二次调用Object.defineProperty()方法:writable和value可以正常修改
//测试2:第二次修改 configurable
var obj = {
    name: "new obj",
    action: function() {
        return this.name
    }
}
Object.defineProperty(obj, "name", {
    configurable: false,
    enumerable: true,
    writable: true,
    value: 20
})
Object.defineProperty(obj, "name", {
    configurable: true
})
console.log(obj.name);
//输出:error
//测试3:第二次修改 enumerable
var obj = {
    name: "new obj",
    action: function() {
        return this.name
    }
}
Object.defineProperty(obj, "name", {
    configurable: false,
    enumerable: true,
    writable: true,
    value: 20
})
Object.defineProperty(obj, "name", {
    enumerable: false
})
console.log(obj.name);
//输出:error

2、 访问器属性

[[configurable]]:表示能否通过delete删除属性从而重新定义属性,默认值为false。
[[enumerable]]:表示能否通过for-in循环返回属性,默认值为false。
[[getter]]:在读取属性时调用的函数,默认值为undefined。
[[setter]]: 在写入属性时调用的函数,默认值为undefined。

测试代码:

var obj = {
    name: "new obj",
    _age: 18,
    action: function() {
        return this.name
    }
}
Object.defineProperty(obj, "age", {
    configurable: true,
    enumerable: true,
    get: function() {
        return this._age;
    },
    set: function(newAge) {
        return this._age = newAge;
    }
})
console.log(obj.age);
obj.age = 20;
console.log(obj.age);
//输出:18、20

注意:

访问器属性只能通过Object.defineProperty()方法定义。

定义多个属性以及数据属性和访问器属性的混合应用

创建或修改多个属性可以使用Object.defineProperties()方法:

测试代码:

var obj = {
    name: "Tom",
    _year: 2017,
    action: function() {
        return this.name
    }
}
Object.defineProperties(obj, {
    name: {
        enumerable: false,
        value: "Amy"
    },
    age: {
        enumerable: true,
        value: 18
    },
    this_year: {
        enumerable: true,
        get: function() {
            return this._year
        },
        set: function(num) {
            return this._year = num
        }
    }
})
console.log(obj.name)
//输出:Amy
console.log(obj.age)
//输出:18
console.log(obj._year)
//输出:2017
console.log(obj.this_year)
//输出:2017

for (k in obj) {
    console.log(k)
}
//输出:_year、action、age、this_year

obj.this_year = 2018
console.log(obj._year)
//输出:2018
console.log(obj.this_year)
//输出:2018
obj._year = 2018
console.log(obj._year)
//输出:2018
console.log(obj.this_year)
//输出:2018
//修改this_year和_year中任意一个属性的value,可以同时更新this_year和_year的value。

ES5、ES6和ES7常用的对象方法

Object.is()

ES5 比较两个值是否相等,只有两个运算符:相等运算符(==)和全等运算符(===)。它们都有缺点,前者会自动转换数据类型,后者的NaN不等于自身,以及+0等于-0。ES6引入了Object.is()方法来弥补全等运算符的不准确运算。这个方法接受两个参数,如果这两个参数类型相同且具有相同的值,则返回true。

例子:

let a = [1, 2, 3],
    b = a,
    c = a;
console.log(Object.is(1, "1")); //输出:false
console.log(Object.is(-0, +0)); //输出:false
console.log(Object.is(NaN, NaN)); //输出:true
console.log(Object.is(b, c)); //输出:true

Object.assign()

Object.assign()方法用于对象的合并,这个方法的第一个参数是目标对象,后面的参数都是源对象,最终结果是返回目标对象。其中源对象的数量是任意的,如果多个源对象具有同名属性,则排位靠后的源对象会覆盖排位靠前的。另外需要注意,Object.assign()方法只拷贝对象自身的可枚举的属性,不可枚举或继承的属性不会拷贝。

例子:

let o1 = {
        name: "Tom",
        age: 20
    },
    o2 = Object.create({
        //继承的属性不能拷贝
        job: "IT"
    }, {
        //可枚举的属性可以拷贝
        "family": {
            enumerable: true,
            value: "mama"
        },
        //不可枚举的属性不可拷贝
        "school": {
            value: "school"
        },
        //覆盖对象o1的name属性
        "name": {
            enumerable: true,
            value: "Amy"
        }
    });
let obj = Object.assign({}, o1, o2);
console.log(obj); //输出:{name: "Amy", age: 20, family: "mama"}

利用Object.assign()为对象一次性添加多个方法。

例子:

let obj = {
    name: "Tom",
    age: 19
}
let objFn = {
    fn1() {
        console.log(this.name);
    },
    fn2() {
        console.log(this.age);
    }
}
Object.assign(obj, objFn);
obj.fn1(); //输出:Tom
obj.fn2(); //输出:19

Object.keys()、Object.values()、Object.entries()

Object.keys() 方法返回一个数组,成员是参数对象自身的(不含继承的)所有可枚举(enumerable)属性的属性名。
Object.values() 方法返回一个数组,成员是参数对象自身的(不含继承的)所有可枚举(enumerable)属性的属性值。
Object.entries() 方法返回一个数组,成员是参数对象自身的(不含继承的)所有可枚举(enumerable)属性的键值对数组。

例子:

let obj = Object.create({
    //继承的属性不能取到
    job: "IT"
});
Object.defineProperty(obj, "school", {
    //不可枚举的属性不能取到
    value: "school"
})
Object.assign(obj, {
    //自身属性可以取到
    name: "Tom",
    age: 19,
    //访问器属性可以取到
    get family() {
        return "mama";
    }
})
let objKeys = Object.keys(obj);
let objVals = Object.values(obj);
let objKVls = Object.entries(obj);
console.log(objKeys); //输出:["name", "age", "family"]
console.log(objVals); //输出:["Tom", 19, "mama"]
console.log(objKVls); //输出:[["name", "Tom"], ["age", 19],["family", "mama"]]

上面三个方法涉及到对象属性枚举顺序的问题,ES6的基本规则是:

1、所有数值键按照数值升序排列。
2、所有字符串键按照加入对象的时间顺序排列。
3、所有Symbol键按照加入对象的时间顺序排列(ES6中的新数据类型)。

例子:

let obj = {
    a: "a",
    0: 0,
    c: "c",
    2: 2,
}
Object.assign(obj, {
    b: "b",
    1: 1
});
console.log(Object.keys(obj)); //输出:["0", "1", "2", "a", "c", "b"]
console.log(Object.values(obj)); //输出:[0, 1, 2, "a", "c", "b"]
console.log(Object.entries(obj)); //输出:[ ["0", 0], ["1", 1], ["2", 2], ["a", "a"],  ["c", "c"], ["b", "b"]]
for (let k in obj) {
    console.log(k); //输出:0, 1, 2, a, c, b
}

文中的代码部分,带有“例子”和“测试代码”字样的,只是用来学习或测试某一功能用的代码,不可以直接用于项目的开发中。带有“代码如下”字样的,都是经过本人测试,简单修改即可用于项目开发中的代码,如有错误,欢迎指出。

打开App,阅读手记
0人推荐
发表评论
随时随地看视频慕课网APP