JavaScript其实支持多种编程范式的,包括函数式编程
和面向对象编程
:
- JavaScript中的对象被设计成一组属性的无序集合,像是一个哈希表,有key和value组成;
- key是一个标识符名称,value可以是任意类型,也可以是其他对象或者函数类型;
- 如果值是一个函数,那么我们可以称之为是对象的方法;
如何创建一个对象呢?
早期使用创建对象的方式最多的是使用Object类
,并且使用new关键字
来创建一个对象:
- 这是因为早期很多JavaScript开发者是从Java过来的,它们也更习惯于Java中通过new的方式创建一个对象;
后来很多开发者为了方便起见,都是直接通过字面量
的形式来创建对象:
- 这种形式看起来更加的简洁,并且对象和属性之间的内聚性也更强,所以这种方式后来就流行了起来;
创建对象的两种方式
/**
* 对象的创建方式一
*/
var person = new Object();
person.name = "coderwhy";
person.age = 18;
/**
* 对象的创建方式二:字面量方式
*/
var obj = {
name: "kobe",
age: 40,
};
对对象的属性进行操作
var obj = {
name: "kobe",
age: 40,
};
//访问对象的属性
console.log(obj.name)
//给对象添加属性
obj.height = 1.88;
//修改对象属性
obj.name = "curry"
//删除对象的属性
delete obj.name
对属性操作的控制
在前面我们的属性都是直接定义在对象内部,或者直接添加到对象内部的:
- 但是这样来做的时候我们就不能对这个属性进行一些限制:比如这个属性是否是可以通过delete删除的?这个属性是否在for-in遍历的时候被遍历出来呢?
如果我们想要对一个属性进行比较精准的操作控制,那么我们就可以使用属性描述符。
- 通过属性描述符可以
精准的添加或修改
对象的属性; - 属性描述符需要使用
Object.defineProperty
来对属性进行添加
或者修改
;
Object.defineProperty
Object.defineProperty() 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此
对象。
image.png
可接收三个参数:
- obj要定义属性的对象;
- prop要定义或修改的属性的名称或 Symbol;
- descriptor要定义或修改的属性描述符;
返回值:
- 被传递给函数的对象。
var obj = {
name: "kobe",
age: 40,
};
/**
* Object.defineProperty(obj, property, descritor)
* obj为操作的目标对象
* property为操作的目标对象的属性
* descritor为属性描述符
*/
//使用下面方式给obj添加的height属性是不可枚举的,
//即console.log的时候,不会显示这个属性,
//for in的时候,不会遍历这个属性,
//Object.keys时也没用这个属性,
//但是可以通过obj.height获取到
Object.defineProperty(obj, "height", {
value: 1.88,
});
console.log(obj); //{name: "kobe", age: 40}
console.log(obj.height); //1.88
属性描述符分类
属性描述符的类型有两种:
- 数据属性(Data Properties)描述符(Descriptor);
- 存取属性(Accessor访问器 Properties)描述符(Descriptor);
数据属性描述符
数据数据描述符有如下四个特性:
[[Configurable]]:表示属性是否可以通过delete删除属性,是否可以修改它的特性,或者是否可以将它修改为存取属性描述符;
- 当我们直接在一个对象上定义某个属性时,这个属性的[[Configurable]]为true;
- 当我们通过属性描述符定义一个属性时,这个属性的[[Configurable]]默认为false;
[[Enumerable]]:表示属性是否可以通过for-in或者Object.keys()返回该属性;
- 当我们直接在一个对象上定义某个属性时,这个属性的[[Enumerable]]为true;
- 当我们通过属性描述符定义一个属性时,这个属性的[[Enumerable]]默认为false;
[[Writable]]:表示是否可以修改属性的值;
- 当我们直接在一个对象上定义某个属性时,这个属性的[[Writable]]为true;
- 当我们通过属性描述符定义一个属性时,这个属性的[[Writable]]默认为false;
[[value]]:属性的value值,读取属性时会返回该值,修改属性时,会对其进行修改;
- 默认情况下这个值是undefined;
数据属性描述符-configurable
var obj = {
name: "kobe",
age: 40,
};
Object.defineProperty(obj, "address", {
value: "北京",
//该特性为false,则对象的此属性不能被delete删除,不能被修改,不能被重新定义为存取属性描述符
configurable: false,
})
//测试configurable
delete obj.address
console.log(obj.address) //北京 address属性没有被从obj对象上删除
obj.address = "上海"
console.log(obj.address) //北京 address属性值没有被修改
Object.defineProperty(obj, "address", {
value: "上海",
configurable: true
}) //报错,Cannot redefine property: address address不能被重新定义
数据属性描述符-enumerable
var obj = {
name: "kobe",
age: 40,
};
Object.defineProperty(obj, "address", {
value: "北京",
//该特性为false,则对象的此属性不能被delete删除,不能被修改,不能被重新定义为存取属性描述符
configurable: false,
//该特性为false,则对象的此属性不能被for in遍历,不能被Object.keys(obj)获取到,使用console.log(obj)输出是不能被输出
enumerable: false,
})
//测试enumerable
for(var key in obj) {
console.log(key)
}
//name age address没有被遍历出来
console.log(Object.keys(obj)) //[name, age] 不包含address
console.log(obj) //{name: "kobe", age: 40} 不包含address
image.png
数据属性描述符-writable
var obj = {
name: "kobe",
age: 40,
};
Object.defineProperty(obj, "address", {
value: "北京",
//该特性为false,则对象的此属性不能被delete删除,不能被修改,不能被重新定义为存取属性描述符
configurable: false,
//该特性为false,则对象的此属性不能被for in遍历,不能被Object.keys(obj)获取到,使用console.log(obj)输出是不能被输出
enumerable: false,
//该特性为false,则对象的此属性的值不可以被修改
writable: false,
})
//测试writable
obj.address = "上海"
console.log(obj.address) //北京
image.png
定义对象属性的不同方法,数据属性描述符配置的默认值
var obj = {
name: "kobe",
age: 40,
};
obj.address = "北京";
//上面定义对象属性的方法相当于下面的写法
Object.defineProperty(obj, "address", {
value: "北京",
configurable: true,
enumerable: true,
writable: true,
});
Object.defineProperty(obj, "height", {
value: 1.88,
});
//上面定义对象属性的方法相当于下面写法
Object.defineProperty(obj, "height", {
value: 1.88,
configurable: false,
enumerable: false,
writable: false,
});
存取属性描述符
数据数据描述符有如下四个特性:
[[Configurable]]:表示属性是否可以通过delete删除属性,是否可以修改它的特性,或者是否可以将它修改为存取属性描述符;
- 和数据属性描述符是一致的;
- 当我们直接在一个对象上定义某个属性时,这个属性的[[Configurable]]为true;
- 当我们通过属性描述符定义一个属性时,这个属性的[[Configurable]]默认为false;
[[Enumerable]]:表示属性是否可以通过for-in或者Object.keys()返回该属性;
- 和数据属性描述符是一致的;
- 当我们直接在一个对象上定义某个属性时,这个属性的[[Enumerable]]为true;
- 当我们通过属性描述符定义一个属性时,这个属性的[[Enumerable]]默认为false;
[[get]]:获取属性时会执行的函数。默认为undefined
[[set]]:设置属性时会执行的函数。默认为undefined
var obj = {
name: "kobe",
age: 40,
};
Object.defineProperty(obj, "_address", {
value: "北京",
configurable: true,
enumerable: false,
writable: true,
})
//存取属性描述符的用法一:隐藏一个私有属性,不希望被外界直接使用和赋值
Object.defineProperty(obj, "address", {
configurable: true,
enumerable: true,
get: function() {
return this._address
},
set: function(val) {
this._address = val
}
})
console.log(obj) //{ name: 'kobe', age: 40, address: [Getter/Setter] }
console.log(obj.address) //北京
obj.address = "上海"
console.log(obj.address) //上海
//存取属性描述符的用法二:截获某一个属性的访问和设置值的过程,
Object.defineProperty(obj, "address", {
configurable: true,
enumerable: true,
get: function() {
console.log("获取了address的值")
return this._address
},
set: function(val) {
console.log("设置了address的值")
this._address = val
}
})
console.log(obj.address)
obj.address = 50
image.png
在字面量对象中直接设置存取属性描述符,configurable,enumerable默认值为true
var obj = {
name: "why",
_address: "北京市",
//在字面量对象中直接设置存取属性描述符,configurable,enumerable默认值为true
get address() {
return this._address;
},
set address(val) {
this._address = val;
},
};
console.log(obj);
相当于下面写法
var obj = {
name: "why",
_address: "北京市",
};
Object.defineProperty(obj, "address", {
configurable: true,
enumerable: true,
get: function () {
return this._address;
},
set: function (val) {
this._address = val;
},
});
属性描述符相关api
1. Object.defineProperties()
直接在一个对象上一次性定义多个
新的属性或修改多个
现有属性,并返回该对象。
语法:
Object.defineProperties(obj, props)
用法:
var obj = {
name: "why",
_age: 18,
eatting: function () {},
};
//一次性给目标对象定义多个属性描述符
Object.defineProperties(obj, {
address: {
configurable: false,
enumerable: false,
writable: false,
value: "北京市",
},
height: {
configurable: true,
enumerable: true,
writable: true,
value: 1.88
},
age: {
configurable: true,
enumerable: true,
get: function () {
return this._age;
},
set: function (val) {
this._age = val;
},
},
});
console.log(obj);
//因为address是不可枚举的,所有没有输出address属性,但是可以通过obj.address获取值
console.log(obj.address)
image.png
2. Object.defineProperty()
在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。
语法:
Object.defineProperty(obj, prop, descriptor)
用法:
var obj = {
name: "why",
_address: "北京市",
running: function () {},
};
Object.defineProperty(obj, "age", {
value: 18,
configurable: true,
enumerable: true,
writable: true,
});
Object.defineProperty(obj, "address", {
configurable: true,
enumerable: true,
get: function () {
return this._address;
},
set: function (val) {
this._address = val;
},
});
console.log(obj);
console.log(obj.address);
image.png
3. Object.getOwnPropertyDescriptor()
返回指定对象上一个
自有属性对应的属性描述符。(自有属性指的是直接赋予该对象的属性,不需要从原型链上进行查找的属性)
语法:
Object.getOwnPropertyDescriptor(obj, prop)
用法:
var obj = {
name: "why",
_address: "北京市",
get address() {
return this._address;
},
set address(val) {
this._address = val;
},
running: function () {},
};
const descriptor1 = Object.getOwnPropertyDescriptor(obj, "name");
const descriptor2 = Object.getOwnPropertyDescriptor(obj, "address");
const descriptor3 = Object.getOwnPropertyDescriptor(obj, "running");
console.log(descriptor1);
console.log( descriptor2);
console.log(descriptor3);
image.png
4. Object.getOwnPropertyDescriptors()
获取所指定对象的所有
自身属性的描述符,如果没有任何自身属性,则返回空对象。
用法:
var obj = {
name: "why",
_address: "北京市",
get address() {
return this._address;
},
set address(val) {
this._address = val;
},
running: function () {},
};
const descriptors = Object.getOwnPropertyDescriptors(obj);
console.log(descriptors);
image.png
5. Object.preventExtensions()
让一个对象变的不可扩展,也就是永远不能再添加新的属性
语法:
Object.preventExtensions(obj)
用法:
var obj = {
name: "why",
running: function () {},
};
//让obj变得不可扩展,也就是永远不能给obj添加新的属性
Object.preventExtensions(obj);
obj.age = 18;
console.log(obj)
//{ name: 'why', running: [Function: running] } age属性并没有被添加到obj上
image.png
6. Object.seal()
封闭一个对象,阻止添加新属性并将所有现有属性标记为不可配置
- 1.即所有的属性都不能被delete删除,所有的属性描述符不能被修改
- 2.不能给对象添加新属性
用法:1.让对象的所有现有属性变为不可配置
var obj = {
name: "why",
_age: 18,
get age() {
return this._age;
},
set age(val) {
this._age = val;
},
running: function () {},
};
console.log(Object.getOwnPropertyDescriptors(obj))
//让对象所有属性变得不可配置,即所有的属性都不能被delete删除,所有的属性描述符不能被修改
Object.seal(obj);
console.log(Object.getOwnPropertyDescriptors(obj))
image.png
相当于对对象做了如下操作:
for (var key in obj) {
Object.defineProperty(obj, key, {
...Object.getOwnPropertyDescriptor(obj, key),
configurable: false,
});
}
用法二:让对象不能添加新属性
/**
* Object.seal(obj)
* 封闭一个对象,阻止添加新属性并将所有现有属性标记为不可配置
* 1.即所有的属性都不能被delete删除,所有的属性描述符不能被修改
* 2.不能给对象添加新属性
*/
var obj = {
name: "why",
_age: 18,
get age() {
return this._age;
},
set age(val) {
this._age = val;
},
running: function () {},
};
//让对象所有属性变得不可配置,即所有的属性都不能被delete删除,所有的属性描述符不能被修改
Object.seal(obj);
//height属性不会被添加到obj上
obj.height = 18;
console.log(Object.getOwnPropertyDescriptors(obj));
image.png
7. Object.freeze()
冻结一个对象,阻止添加新属性并将所有现有属性标记为不可配置,属性值不可以被修改
- 1.一个被冻结的对象再也不能被修改;
- 2.冻结了一个对象则不能向这个对象添加新的属性,
- 3.不能删除已有属性,不能修改该对象已有属性的可枚举性、可配置性、可写性,
- 4.不能修改已有属性的值。
- 5.冻结一个对象后该对象的原型也不能被修改。
+6. freeze() 返回和传入的参数相同的对象。
也就是,如果一个对象被冻结,这个对象现有的所有属性的的属性描述符的configurable
, writable
被设置为false
用法:1.把对象所有属性的属性描述符的configurable,writable设置为false,则对象所有的属性不能被删除,属性描述符不能被修改,属性的值不能改变
/**
* Object.freeze(obj)
* 冻结一个对象,阻止添加新属性并将所有现有属性标记为不可配置,属性值不可以被修改
* 1.即所有的属性都不能被delete删除,所有的属性描述符不能被修改
* 2.对象所有的属性的值不可以被修改
* 3.不能给对象添加新属性
* 也就是说,对象的所有属性的属性描述符的configurable,writable被设置为false
*/
var obj = {
name: "why",
_age: 18,
get age() {
return this._age;
},
set age(val) {
this._age = val;
},
running: function () {},
};
console.log(Object.getOwnPropertyDescriptors(obj));
Object.freeze(obj);
console.log(Object.getOwnPropertyDescriptors(obj));
//对象所有属性的属性描述符的configurable,writable被设置为false
image.png
用法:2.对冻结的对象,不能添加新属性
var obj = {
name: "why",
_age: 18,
get age() {
return this._age;
},
set age(val) {
this._age = val;
},
running: function () {},
};
Object.freeze(obj);
//height属性不会被添加到obj上
obj.height = 18;
console.log(Object.getOwnPropertyDescriptors(obj));
image.png
8. Object.isExtensible()
判断一个对象是否是可扩展的(是否可以在它上面添加新的属性)。
语法:
Object.isExtensible(obj)
返回值:Boolean,true表示检测的对象是可扩展的
用法:
/**
* Object.isExtensible(obj)
* 检测目标对象是否可以扩展
* 返回一个布尔值,表示其是否可扩展
*/
var obj = {
name: "why",
running: function () {},
};
//让obj变得不可扩展,也就是永远不能给obj添加新的属性
Object.preventExtensions(obj);
console.log(Object.isExtensible(obj)) //false
8. Object.isFrozen()
判断一个对象是否被[冻结]
语法:
Object.isFrozen(obj)
返回值:布尔值,true代表被检测的对象时冻结的
用法:
/**
* Object.isFrozen(obj)
* 判断一个对象是否被冻结
* 1.对象不可以扩展,即不添加新属性
* 2. 对象的所有属性都是不可配置的,即所有属性描述符的configurable为false
* 3.对象的所有属性值都是不可以修改的,即所有属性描述符的writable为false
*/
//一个空对象被Object.preventExtensions()处理后,就变成是冻结的
var emptyObj = {};
Object.preventExtensions(emptyObj);
console.log(Object.isFrozen(emptyObj)); //true
//非空空对象被Object.seal()处理后,不是被冻结状态
var obj1 = { name: true };
Object.seal(obj1);
console.log(Object.isFrozen(obj1)); //false
var obj2 = {
name: "why",
_age: 18,
get age() {
return this._age;
},
set age(val) {
this._age = val;
},
running: function () {},
};
Object.preventExtensions(obj2);
for (var key in obj2) {
//in操作符可以用来判断一个属性是否属于一个对象
if ("writable" in Object.getOwnPropertyDescriptor(obj2, key)) {
Object.defineProperty(obj2, key, {
...Object.getOwnPropertyDescriptors(obj2),
configurable: false,
writable: false,
});
} else {
Object.defineProperty(obj2, key, {
...Object.getOwnPropertyDescriptors(obj2),
configurable: false,
});
}
}
console.log(Object.isFrozen(obj2)); //true
//被Object.freeze()处理的对象时冻结的
var obj3 = { name: "why" };
Object.freeze(obj3);
console.log(Object.isFrozen(obj3));
image.png
9. Object.isSealed()
判断一个对象是否被密封。
- 1.对象不可以添加新属性
- 对象的所有属性都是不可配置的,即所有属性描述符的configurable为false
语法:
Object.isSealed(obj)
用法:
/**
* Object.isSealed(obj)
* 判断一个对象是否被密封
* 1.对象不可以添加新属性
* 2. 对象的所有属性都是不可配置的,即所有属性描述符的configurable为false
*/
//一个空对象被Object.preventExtensions()处理后,就变成是密封的
var emptyObj = {};
Object.preventExtensions(emptyObj);
console.log(Object.isSealed(emptyObj)); //true
//非空空对象被Object.seal()处理后变成密封的
var obj1 = { name: true };
Object.seal(obj1);
console.log(Object.isSealed(obj1)); //true
var obj2 = {name: true}
Object.preventExtensions(obj2);
for (var key in obj2) {
Object.defineProperty(obj2, key, {
...Object.getOwnPropertyDescriptors(obj2),
configurable: false,
});
}
console.log(Object.isSealed(obj2)); //true
//一个密封对象同时也是不可扩展的
console.log(Object.isExtensible(obj2)); //false
//一个冻结的对象同时也是密封的
var obj3 = { name: "kobe", age: 40 };
Object.freeze(obj3);
console.log(Object.isSealed(obj3)); //true
image.png
11. Object.keys()
会返回一个由一个给定对象的自身可枚举属性组成的数组,数组中属性名的排列顺序和正常循环遍历该对象时返回的顺序一致 。
语法:
Object.keys(obj)
用法:
/**
* Object.keys 返回一个所有元素为字符串的数组,]
* 其元素来自于从给定的object上面可直接枚举的属性。
* 这些属性的顺序与手动遍历该对象属性时的一致。
*/
var obj = {
name: "why",
_age: 18,
eatting: function () {},
};
//一次性给目标对象定义多个属性描述符
Object.defineProperties(obj, {
address: {
configurable: false,
enumerable: false,
writable: false,
value: "北京市",
},
height: {
configurable: true,
enumerable: true,
writable: true,
value: 1.88
},
age: {
configurable: true,
enumerable: true,
get: function () {
return this._age;
},
set: function (val) {
this._age = val;
},
},
});
console.log(obj)
console.log(Object.keys(obj));
//obj不可以枚举的属性是不会出现在Object.keys(obj)返回的对象中的
image.png
非常感谢王红元老师的深入JavaScript高级语法让我学习到很多 JavaScript
的知识
网友评论