5.1 JavaScript的面向对象
JavaScript其实支持多种编程范式的,包括函数式编程和面向对象编程:
- JavaScript中的对象被设计成一组属性的无序集合,像是一个哈希表,有key和value组成;
- key是一个标识符名称,value可以是任意类型,也可以是其他对象或者函数类型;
- 如果值是一个函数,那么我们可以称之为是对象的方法;
如何创建一个对象呢?
- 早期使用创建对象的方式最多的是使用Object类,并且使用new关键字来创建一个对象:
- 这是因为早期很多JavaScript开发者是从Java过来的,它们也更习惯于Java中通过new的方式创建一个对象;
- 后来很多开发者为了方便起见,都是直接通过字面量的形式来创建对象: 这种形式看起来更加的简洁,并且对象和属性之间的内聚性也更强,所以这种方式后来就流行了起来;
5.2 创建对象的两种方式
41.png5.3 对对象属性进行操作
43.PNGvar obj = {
name: "why",
age: 18
}
// 获取属性
console.log(obj.name)
// 给属性赋值
obj.name = "kobe"
console.log(obj.name)
// 删除属性
// delete obj.name
// console.log(obj)
// 需求: 对属性进行操作时, 进行一些限制
// 限制: 不允许某一个属性被赋值/不允许某个属性被删除/不允许某些属性在遍历时被遍历出来
// 遍历属性
for (var key in obj) {
console.log(key)
}
5.4 Object.defineProperty
42.png
var obj = {
name: "why",
age: 18
}
// 属性描述符是一个对象
Object.defineProperty(obj, "height", {
// 很多的配置
value: 1.88
})
console.log(obj)
console.log(obj.height)
1.属性描述符
属性描述符的类型有两种:
- 数据属性(Data Properties)描述符(Descriptor);
- 存取属性(Accessor访问器 Properties)描述符(Descriptor);
2.数据属性描述符
45.PNG- configurable
const obj = {
name:"why",
age:18,
friends:{
name:"kobe"
},
hobbies:["篮球","足球"]
}
//Object.defineProperty()//
/* 直接在对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象 */
let res = Object.defineProperty(obj, "name", {
value:"new setting value",
//第一种:当我们直接在一个对象上定义某个属性的时候,这个属性的configurable为true
//第二种:当我们通过属性表舒服定义一个属性的时候,这个属性的configurable默认为false
//configurable:false
})
// delete obj.name
console.log(obj)
//{age: 18, friends: {…}, hobbies: Array(2)}
//不写/configurable:false的话,name能删除是因为这个obj是属于第一种,configurable的默认值是true
//如果在里面设置configurable为flase之后,就不能删除了
////设置了configuratble为false之后,就不能删除address和改变它的definProperty里面的configurable属性。
console.log(res === obj)//true
Object.defineProperty(obj, "name", {
value:"new setting value2",
//第一种:当我们直接在一个对象上定义某个属性的时候,这个属性的configurable为true
//第二种:当我们通过属性表舒服定义一个属性的时候,这个属性的configurable默认为false
configurable:true//如果上一个definProerty的时候设置了configurableweifalse,第二次就不能再次把他它变成了false
})
2.enumrable
第一种:当我们直接在一个对象上定义某个属性时,这个属性的[[Enumerable]]为true;
第二种:当我们通过属性描述符定义一个属性时,这个属性的[[Enumerable]]默认为false;
const obj = {
name:"why",
age:18,
friends:{
name:"kobe"
},
hobbies:["篮球","足球"]
}
console.log(Object.keys(obj));//返回一个数组,里面是对象里面的所有可以遍历的属性的key名字
//(3) ['age', 'friends', 'hobbies']
Object.keys(obj).map((currentValue,index, arr) => {
console.log(obj[currentValue])
})
//Enumerable:表示属性是否可以通过for-in或者Object.keys()返回该属性
for(let key in obj) {
console.log(key, obj[key])
}
/*
name why
test.html:31 age 18
test.html:31 friends {name: 'kobe'}
test.html:31 hobbies (2) ['篮球', '足球']
*/
var obj = {
name: "why",
age: 18
}
//数据属性描述符
Object.defineProperty(obj, "address", {
value:"北京市",// 默认值undefined
configuratble:false,// 默认值false
//该特殊是配置对应的属性(address)是否是可以枚举
enumerable:false,//默认值false
})
console.log(obj)//{name: 'why', age: 18, address: '北京市'}
for (var key in obj) {
console.log(key)//name //age//address
}
console.log(Object.keys(obj))//) ['name', 'age', 'address']
//设置enumerable为false的时候,是不可被枚举,输出为下
//{name: 'why', age: 18, address: '北京市'}
//name age
//['name', 'age']
3.writable
[[Writable]]:表示是否可以修改属性的值;
p 当我们直接在一个对象上定义某个属性时,这个属性的[[Writable]]为true;
p 当我们通过属性描述符定义一个属性时,这个属性的[[Writable]]默认为false;
const obj = {
name:"my",
age:18,
address:"none"
}
//数据属性描述符
Object.defineProperty(obj, "address", {
value:"北京市",// 默认值undefined
configuratble:false,// 默认值false
//该特殊是配置对应的属性(address)是否是可以枚举
enumerable:true,//默认值false
//该特性是属性是否是可以赋值(写入值)
writable: true// 默认值false
})
//当设置为writable为false的时候
obj.address = "上海市"
console.log(obj.address)//"北京市"
//当设置为ture的时候
//上海市
4.value
n [[value]]:属性的value值,读取属性时会返回该值,修改属性时,会对其进行修改;
p 默认情况下这个值是undefined;
3.存取属性描述符
46.PNG var obj = {
name: "why",
_address: "北京市"
}
/*,1.,第一个场景的话就是我们隐藏某一个私有属性,不希望直接被外界使用和赋值
我不希望address这个属性随随便便被暴露出去,我们比如说给他来了一个下划线,
因为一般下划线开头的话,我们会表示他是一个私有的,然后呢使用了address这个属性名字,
来获取或者设置_address, 这个样子的化我们就不知道这个对象还有_address这个属性名
2.如果我们希望截获某一个属性它访问和设置值的过程时, 也会使用存储属性描述符
*/
Object.defineProperty(obj, "address", {
enumerable: true,
configurable: true,
get: function() {
foo()
return this._address //这个this值得是obj,因为是obj.address调用
},
set: function(value) {
bar()
this._address = value
}
})
console.log(obj.address)
obj.address = "上海市"
console.log(obj.address)
function foo() {
console.log("获取了一次address的值")
}
function bar() {
console.log("设置了addres的值")
}
console.log(obj)
/*
获取了一次address的值
北京市
设置了addres的值
获取了一次address的值
上海市
{name: 'why', _address: '上海市'}
address
:
(...)
name
:
"why"
_address
:
"上海市"
*/
5.5 同时定义多个属性
image.pngvar obj = {
// 私有属性(js里面是没有严格意义的私有属性) 就是别人不知道这个属性的名字,不能访问这个属性
/* 在整个JS社区里面,一般情况下,我们以下划线开头的某一个属性,
我们就认为我们就认为他是一个私有属性 */
_age: 18,
_eating: function() {},
}
Object.defineProperties(obj, {
name: {
configurable: true,
enumerable: true,
writable: true,
value: "why"
},
age: {
configurable: true,
enumerable: false,
get: function() {
return this._age
},
set: function(value) {
this._age = value
}
}
})
obj.age = 19
console.log(obj.age)
console.log(obj)
如果设置age的enumerable为false,打印obj的话
image.png
如果设置address的enumerable为true,打印obj的话
image.png
可以发现age一个是虚的一个是实的。代表能不能列举。
另外,在js中还有另一种写法
/* var obj = {
_age: 18,
_eating: function() {},
}
*/
var obj = {
_age: 18,
_eating: function() {},
set age(value) {
this._age = value
},
get age() {
return this._age
}
}
/* ,在我们开发里面,如果我们想要给我们的某一个某一个对象的某一个属性,给它定义对应的get和set,
而且另外它的这个值和这个值,我们想要使用默认的时候,其实我们这里可以这样来做
如果age的configurable为true,enumerable为true,那我们可以把definproperties里面的age这个代码给注释掉,
可以在obj里面直接定义set和get
例如obj.age = 19, console.log(obj.age)
*/
obj.age = 19
console.log(obj.age)
console.log(obj)
/*
在obj里面直接写set和get何用definProperty有一些差异,就是直接在obj中写就是直接设置了enumerable的值为true和configurable为true。
,这个时候和definProperty中的enumerble为true和configurable为true的结果一样。只不过如果我们用definProperty来写的话,你可以更加精准的去控制我们这个属性。
*/
Object.defineProperties(obj, {
name: {
configurable: true,
enumerable: true,
writable: true,
value: "why"
},
/* age: {
configurable: true,
enumerable: true,
get: function() {
return this._age
},
set: function(value) {
this._age = value
}
} */
})
5.6 获取属性描述符Object.getOwnPropertyDescriptor
image.pngvar obj = {
_age: 18,
_eating: function() {}
}
Object.defineProperties(obj, {
name: {
configurable: true,
enumerable: true,
writable: true,
value: "why"
},
age: {
configurable: true,
enumerable: true,
get: function() {
return this._age
},
set: function(value) {
this._age = value
}
}
})
// 获取某一个特性属性的属性描述符
console.log(Object.getOwnPropertyDescriptor(obj, "name"))
//{value: 'why', writable: true, enumerable: true, configurable: true}
console.log(Object.getOwnPropertyDescriptor(obj, "age"))
//{enumerable: true, configurable: true, get: ƒ, set: ƒ}
// 获取对象的所有属性描述符
console.log(Object.getOwnPropertyDescriptors(obj))
image.png
var obj = {
name: "why",
age: 18,
};
// 1.禁止对象继续添加新的属性
Object.preventExtensions(obj);
obj.height = 1.88;
obj.address = "广州市";
console.log(obj); //{name: 'why', age: 18}
// 2.禁止对象配置/删除里面的属性
// for (var key in obj) {
// Object.defineProperty(obj, key, {
// configurable: false,
// enumerable: true,
// writable: true,
// value: obj[key]
// })
// }
/*
可以不用像上面那么写,因为js给我们提供了方法
密封对象,不允许配置,不可配置就是不可以删除属性:seal
实际是调用preventExtensions
并且将现有属性的configurable:false
*/
Object.seal(obj);
delete obj.name;
console.log(obj.name);//why
// 3.让属性不可以修改(writable: false)
Object.freeze(obj);
obj.name = "kobe";
console.log(obj.name);//why
网友评论