目录
八. Object.defineProperty Object.defineProperty() | MDN
Object - JavaScript | MDN
一. 对象的使用
- key: 字符串类型, 但是在定义对象的属性名时, 大部分情况下引号都是可以省略的
- value : 可以是任意值
const person = {
name: 'why',
age: 18,
height: 1.88,
// 这种的就要加上''号
'my friend': {
name: 'kobe',
age: 30
},
run: function () {
console.log('running');
},
eat: function () {
console.log('eat foods');
},
};
二. 对象的创建方式
1 - 对象字面量
// 直接花括号赋值即可,用的最多
const obj1 = {
name: "why"
}
2 - 构造函数
// 当函数被new关键词调用时,该函数就被称为构造函数
const obj = new Object()
obj.name = "star"
obj2.runing = function(){}
3 - 类创建
class Person {
constructor(name) {
this.name = name;
}
}
const stu = new Person('star');
三. 对象的操作
1 - 定义
const info = {
name: "star",
age: 18,
friend: {
name: "coder",
age: 30
},
running: function() {
console.log("running~")
}
}
2 - 访问对象属性
console.log(info.name)
console.log(info.friend.name)
info.running()
3 - 修改对象属性
info.age = 25
info.running = function() {
alert("I am running~")
}
console.log(info.age)
info.running()
4 - 增加对象属性
info.height = 1.88
info.studying = function() {
console.log("I am studying~")
}
5 - 删除对象属性
delete info.age
delete info.height
四. 对象的方括号 [] 使用法
const obj = {
name: "why",
"my friend": "kobe",
"eating something": function() {
console.log("eating~")
}
}
// 这里 . 语法不能用
console.log(obj["my friend"])
console.log(obj.name)
// 这和 . 语法一个意思
console.log(obj["name"])
// 用变量的值充当对象的key
var eatKey = "eating something"
obj[eatKey]()
// 可连在一起使用
obj["eating something"]()
五. 对象的遍历
1 - 普通for循环
// Object.keys() => 拿到对象的所有key
const infoKeys = Object.keys(info)
for (let i = 0; i < infoKeys.length; i++) {
// 拿到key的值
let key = infoKeys[i]
// 拿到value的值
let value = info[key]
console.log(`key: ${key}, value: ${value}`)
}
2 - for ... in ...
// 可直接拿到对象的key
for (let key in info) {
let value = info[key]
console.log(`key: ${key}, value: ${value}`)
}
3 - Object.keys( )
const obj = {
name: 'star',
age: 18,
height: 1.88
};
// 获取所有的key
const keys = Object.keys(obj);
console.log(keys); // ['name', 'age', 'height']
4 - Object.values( )
const obj = {
name: 'star',
age: 18,
height: 1.88
};
// 获取所有的value
const values = Object.values(obj);
console.log(values); // ['star', 18, 1.88]
5 - Object.entries( )
const obj = {
name: 'star',
age: 18,
height: 1.88
};
const entries = Object.entries(obj);
console.log(entries); // [[key,value], ...] => [['name', 'star'], ['age', 18], ['height', 1.88]]
for (const entry of entries) {
// 解构一下
const [key, value] = entry;
console.log(key, value);
}
6 - Object.fromEntries( )
const obj = {
name: 'star',
age: 18,
height: 1.88,
friends: [1, 2, 3]
};
const entries = Object.entries(obj);
console.log(entries); // [ ['name', 'star'], ['age', 18], ['height', 1.88] ]
// 可以装换回对象
const info = Object.fromEntries(entries);
console.log(info); // {name: 'star', age: 18, height: 1.88}
// 是一个浅拷贝
console.log(info === obj, info.friends === obj.friends); // false , true
六. 对象的内存分配
js代码可以运行在浏览器,也可运行在node环境,无论是什么环境,最终都是运行在内存中
内存会映射在真实的电脑物理内存中,所以内存越大,跑的速度越快~~~
- 基本类型 : 存储在内存中的栈内存
- 引用类型 : 存储在内存中的堆内存
1 - 面试题一
const obj1 = {}
const obj2 = {}
console.log(obj1 === obj2) // false
2 - 面试题二
const info = {
name: "why",
friend: {
name: "kobe"
}
}
const friend = info.friend
friend.name = "james"
console.log(info.friend.name) // james
3 - 面试题三
function foo(a) {
a = 200
}
const num = 100
foo(num)
console.log(num) // 100
4 - 面试题四
function foo(a) {
a = {
name: "star"
}
}
const obj = {
name: "obj"
}
foo(obj)
console.log(obj) //{ name:obj }
5 - 面试题五
function foo(a) {
a.name = "star"
}
const obj = {
name: "obj"
}
foo(obj)
console.log(obj) // {name : star}
七. 创建一系列对象的方式
1 - 一个一个写
有点小蠢~
const stu1 = {
name: 'star',
age: 16,
height: 1.66,
running: function () {
console.log('running~');
}
};
const stu2 = {
name: 'coder',
age: 17,
height: 1.77,
running: function () {
console.log('running~');
}
};
const stu3 = {
name: 'liuli',
age: 18,
height: 1.88,
running: function () {
console.log('running~');
}
};
2 - 通过for循环写
还是有点蠢~
const nameArr = ['star', 'coder', 'liuli'];
const ageArr = [16, 17, 18];
const heightArr = [1.66, 1.77, 1.88];
const funcs = {
running: function () {
console.log('running~');
}
};
for (let i = 0; i < nameArr.length; i++) {
let stu = {
name: nameArr[i],
age: ageArr[i],
height: heightArr[i],
running: funcs.running
};
console.log(stu); //{name: 'star', age: 16, height: 1.66, running: ƒ} ...
}
3 - 通过工厂函数
// 工厂函数(工厂生产student对象) -> 一种设计模式
// 通过工厂设计模式, 自己来定义了一个这样的函数
function createStudent(name, age, height) {
const stu = {};
stu.name = name;
stu.age = age;
stu.height = height;
stu.running = function () {
console.log('running~');
};
return stu;
}
const stu1 = createStudent('stare', 16, 1.66);
const stu2 = createStudent('coder', 17, 1.77);
const stu3 = createStudent('liuli', 18, 1.88);
console.log(stu1);
console.log(stu2);
console.log(stu3);
弊端 : 拿到的数据的类型都是Object类型
4 - 通过new操作符来创建
简单理解下构造函数
// JavaScript已经默认提供给了我们可以更加符合JavaScript思维方式(面向对象的思维方式)的一种创建对象的规则
// 在函数中的this一般指向某一个对象
/*
如果一个函数被new操作符调用
1.创建出来一个新的空对象
2.这个对象的 __proto__ 指向构造函数的 prototype
3.让this指向这个空对象
4.执行函数体的代码块
5.如果没有明确的返回一个非空对象, 那么this指向的对象会自动返回
*/
function Coder(name, age, height) {
// 相当于new操作符做了
// let obj = {}
// this = obj
this.name = name
this.age = age
this.height = height
this.running = function() {
console.log("running~")
}
// return this
}
// 在函数调用的前面加 new 关键字(操作符)
const stu1 = new coder("why", 18, 1.88)
const stu2 = new coder("kobe", 30, 1.98)
console.log(stu1, stu2)
八. Object.defineProperty Object.defineProperty() | MDN
- 通过属性描述符可以精准的添加或修改对象的属性
- 属性描述符需要使用 Object.defineProperty 来对属性进行添加或者修改
Object.defineProperty() 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象
Object.defineProperty(obj, prop, descriptor) 可接收三个参数: obj要定义属性的对象 prop要定义或修改的属性的名称或 Symbol descriptor要定义或修改的属性描述符 返回值: 被传递给函数的对象。
属性描述符的类型有两种 :
- 数据属性(Data Properties)描述符(Descriptor)
- 存取属性(Accessor访问器 Properties)描述符(Descriptor)
数据属性描述符
Configurable
- [[Configurable]] : 表示属性是否可以通过delete删除属性,是否可以修改它的特性,或者是否可以将它修改为存取属性描述符
- 当直接在一个对象上定义某个属性时,这个属性的[[Configurable]]为true
- 当通过属性描述符定义一个属性时,这个属性的[[Configurable]]默认为false
const obj = {
name: 'star',
age: 18
};
// 修改configurable
Object.defineProperty(obj, 'name', {
configurable: false // 定义不可删除
});
// 不能删除
delete obj.name;
console.log(obj); // {name: 'star', age: 18}
// 不能再次配置,这里报错
Object.defineProperty(obj, 'name', {
configurable: true
});
Enumerable
- [[Enumerable]] : 表示属性是否可以通过for-in或者Object.keys()返回该属性
- 当直接在一个对象上定义某个属性时,这个属性的[[Enumerable]]为true
- 当通过属性描述符定义一个属性时,这个属性的[[Enumerable]]默认为false
const obj = {
name: 'star',
age: 18
};
// 修改configurable
Object.defineProperty(obj, 'name', {
enumerable: false // 不可枚举
});
for (const key in obj) {
console.log('key:', key, ' === value:', obj[key]); // key: age === value: 18
}
Writable
- [[Writable]] : 表示是否可以修改属性的值
- 当直接在一个对象上定义某个属性时,这个属性的[[Writable]]为true
- 当通过属性描述符定义一个属性时,这个属性的[[Writable]]默认为false
const obj = {
name: 'star',
age: 18
};
// 修改configurable
Object.defineProperty(obj, 'name', {
writable: false // 不可修改
});
// 修改失败
obj.name = 'coder';
console.log(obj); // {name: 'star', age: 18}
value
- [[value]] : 属性的value值,读取属性时会返回该值,修改属性时,会对其进行修改
- 默认情况下这个值是undefined
const obj = {
name: 'star',
age: 18
};
// 修改configurable
Object.defineProperty(obj, 'name', {
value: 'coder' // 优先读取和修改这里的值
});
console.log(obj); // {name: 'coder', age: 18}
obj.name = 'coderstar';
console.log(obj); // {name: 'coderstar', age: 18}
存取属性描述符
Configurable
- [[Configurable]] : 表示属性是否可以通过delete删除属性,是否可以修改它的特性,或者是否可以将它修改为存取属性描述符
- 和数据属性描述符是一致的
- 当直接在一个对象上定义某个属性时,这个属性的[[Configurable]]为true
- 当通过属性描述符定义一个属性时,这个属性的[[Configurable]]默认为false
Enumerable
- [[Enumerable]] : 表示属性是否可以通过for-in或者Object.keys()返回该属性
- 和数据属性描述符是一致的
- 当直接在一个对象上定义某个属性时,这个属性的[[Enumerable]]为true
- 当通过属性描述符定义一个属性时,这个属性的[[Enumerable]]默认为false
get
- [[get]]:获取属性时会执行的函数。默认为undefined
set
- [[set]]:设置属性时会执行的函数。默认为undefined
const obj = {
name: 'star',
age: 18
};
// 这里通过一个闭包来实现获取值
let _name = '';
// 修改configurable
Object.defineProperty(obj, 'name', {
configurable: true,
enumerable: false,
// 获取属性的值时会促发的函数
get() {
// return obj.name 千万不要这么写,会形成死循环
console.log('get函数触发');
return _name;
},
// 设置属性的值时会促发的函数
set(value) {
_name = value;
console.log('set函数触发', value);
}
});
obj.name = 'coder'; // set函数触发 coder
obj.name = 'coderstar'; // set函数触发 coderstar
console.log(obj.name); // get函数触发 coderstar
Object.defineProperties
直接在一个对象上定义 多个 新的属性或修改现有属性,并且返回该对象,其他和上面辣个一样
const obj = {
name: 'star',
age: 18
};
Object.defineProperties(obj, {
name: {
configurable: true,
enumerable: false,
writable: false,
value: 'star'
},
age: {
configurable: true,
enumerable: true,
set(value) {
console.log('set响应', value);
}
}
});
console.log(obj.name); // 'star'
obj.age = '19'; // set响应 19
额外方法补充
01 - 获取对象的属性描述符
getOwnPropertyDescriptor : 获得单个属性的描述符
getOwnPropertyDescriptors : 获得好多个属性的描述符
const obj = {
name: 'star',
age: 18
};
/**
* {
* value: 'star',
* writable: true,
* enumerable: true,
* configurable: true
* }
*/
console.log(Object.getOwnPropertyDescriptor(obj, 'name'));
/**
* {
* age: {value: 18, writable: true, enumerable: true, configurable: true}
* name: {value: 'star', writable: true, enumerable: true, configurable: true
* }
*/
console.log(Object.getOwnPropertyDescriptors(obj));
02 - 禁止对象扩展新属性
const obj = {
name: 'star',
age: 18
};
// 阻止扩展新属性
Object.preventExtensions(obj);
// 添加失败
obj.address = '广州市';
console.log(obj); // {name: 'star', age: 18}
03 - 密封对象,不允许配置和删除属性
-
实际是调用preventExtensions
-
并且将现有属性的configurable:false
const obj = {
name: 'star',
age: 18
};
// 密封对象(不能进行配置)
Object.seal(obj);
delete obj.name;
console.log(obj); // {name: 'star', age: 18}
04 - 冻结对象,不允许修改现有属性
const obj = {
name: 'star',
age: 18
};
// 密封对象(不能进行配置)
Object.freeze(obj);
obj.name = 'coder';
console.log(obj); // {name: 'star', age: 18}
九. 对象的解构
1 - 简单的解构
const obj = { name: "star", age: 18, height: 2.05 }
// 对象的解构,不根据顺序解构,根据key解构
const { age, name, height } = obj
console.log(name, age, height) // star 18 2.05
2 - 解构并重命名
const obj = { name: "star", age: 18, height: 2.05 }
const { height: SHeight, name: SName, age: SAge } = obj
console.log(SName, SAge, SHeight) // star 18 2.05
3 - 解构的默认值
const obj = { name: "star", age: 18, height: 2.05 }
const {
height: SHeight,
name: SName,
// 如果值有值的情况下,不会使用默认值
age: SAge = 29,
// 如果值为undefined的属性值,会使用默认值
address: SAddress = "中国"
} = obj
console.log(SName, SAge, SHeight, SAddress) // star 18 2.05 中国
4 - 解构的剩余内容
const obj = { name: "star", age: 18, height: 2.05 }
const {
name,
// 剩下没解构的数据会全部生成到这里
...newObj
} = obj
console.log(name) // star
console.log(newObj) // { age: 18, height: 1.88 }
十. 判断对象属性
1 - hasOwnProperty
对象是否有某一个属于自己的属性(不是在原型上的属性)
const obj = {
name: 'star',
age: '19'
};
obj.__proto__ = {
address: '北京'
};
console.log(obj, obj.address); // {name: 'star', age: '19'} '北京'
// 判断是否是自己的属性,是为true
console.log(obj.hasOwnProperty('name')); // true
console.log(obj.hasOwnProperty('address')); // false
// 没有的属性也为false
console.log(obj.hasOwnProperty('abc')); // false
2. hasOwn
Object中新增了一个静态方法(类方法): hasOwn(obj, propKey)
该方法用于判断一个对象中是否有某个自己的属性
const obj = {
name: 'star',
age: '19'
};
obj.__proto__ = {
address: '北京'
};
console.log(obj, obj.address); // {name: 'star', age: '19'} '北京'
// 判断是否是自己的属性,是为true
console.log(Object.hasOwn(obj, "name")) // true
console.log(Object.hasOwn(obj, "address")) // false
3. 两者的区别
1. 挂载的地方不同
hasOwnProperty : 挂载的地方为Object.prototype上,也就是显示原型
hasOwn : 挂载的地方为构造函数中,也就是类方法,static上
2. 当创建的对象为顶层对象时
// 创建一个顶层对象
// 因为顶层就时null,也就是说,相当于info.__proto__ === null
const info = Object.create(null);
info.name = 'why';
// 可以使用这个,因为是直接使用类方法的
console.log(Object.hasOwn(info, 'name')); // true
// 这个时候,这个对象都不继承自object类,所以根本没有这个方法
console.log(info.hasOwnProperty('name')); // 报错