一、什么是js 对象?
对象是“键值对”的集合,是一种无序的数据的集合
二、如何声明 (创建对象)?方式有哪几种? 有什么区别?
1.对象字面量 字面量的方式创建对象
2.关键字 new 内置构造函数
//字面量的方式创建对象
var obj0 = {}
console.log(obj0)
var obj = {
name: "du",
age:100,
location: "南昌"
}
console.log(obj)
//{name: "du", age: 100, location: "南昌"}
//内置构造函数
var obj2 = new Object()
console.log(obj2)
obj2.name = "xiaoming"
obj2.age = 18
console.log(obj2)
//{name: "xiaoming", age: 18}
三、Object.create()函数
静态方法以一个现有对象作为原型,创建一个新对象
四、对象的继承和原型、原型链?(重难点)
对于使用过基于类的语言(如 Java 或 C++)的开发者来说,JavaScript 实在是有些令人困惑——JavaScript 是动态的且没有静态类型。
当谈到继承时,JavaScript 只有一种结构:对象。每个对象(object)都有一个私有属性指向另一个名为原型(prototype)的对象。原型对象也有一个自己的原型,层层向上直到一个对象的原型为 null
。根据定义,null
没有原型,并作为这个原型链(prototype chain)中的最后一个环节。可以改变原型链中的任何成员,甚至可以在运行时换出原型,因此 JavaScript 中不存在静态分派的概念。
尽管这种混杂通常被认为是 JavaScript 的弱点之一,但是原型继承模型本身实际上比类式模型更强大。例如,在原型模型的基础上构建类式模型(即类的实现方式)相当简单。
尽管类现在被广泛采用并成为 JavaScript 中新的范式,但类并没有带来新的继承模式。虽然类为大部分原型的机制提供了抽象,但了解原型在底层是如何工作的仍然十分有用。
在像 { a: 1, b: 2, __proto__: c }
这样的对象字面量中,c
值(必须为 null
或另一个对象)将变成字面量所表示的对象的 [[Prototype]]
,而其他键(如 a
和 b
)将变成对象的自有属性。这种语法读起来非常自然,因为 [[Prototype]]
只是对象的“内部属性”。
下面演示当尝试访问属性时会发生什么:
const o = { a: 1, b: 2, // __proto__ 设置了 [[Prototype]]。它在这里被指定为另一个对象字面量。 __proto__: { b: 3, c: 4, }, }; // o.[[Prototype]] 具有属性 b 和 c。 // o.[[Prototype]].[[Prototype]] 是 Object.prototype(我们会在下文解释其含义)。 // 最后,o.[[Prototype]].[[Prototype]].[[Prototype]] 是 null。 // 这是原型链的末尾,值为 null, // 根据定义,其没有 [[Prototype]]。 // 因此,完整的原型链看起来像这样: // { a: 1, b: 2 } ---> { b: 3, c: 4 } ---> Object.prototype ---> null console.log(o.a); // 1 // o 上有自有属性“a”吗?有,且其值为 1。 console.log(o.b); // 2 // o 上有自有属性“b”吗?有,且其值为 2。 // 原型也有“b”属性,但其没有被访问。 // 这被称为属性遮蔽(Property Shadowing) console.log(o.c); // 4 // o 上有自有属性“c”吗?没有,检查其原型。 // o.[[Prototype]] 上有自有属性“c”吗?有,其值为 4。 console.log(o.d); // undefined // o 上有自有属性“d”吗?没有,检查其原型。 // o.[[Prototype]] 上有自有属性“d”吗?没有,检查其原型。 // o.[[Prototype]].[[Prototype]] 是 Object.prototype 且 // 其默认没有“d”属性,检查其原型。 // o.[[Prototype]].[[Prototype]].[[Prototype]] 为 null,停止搜索, // 未找到该属性,返回 undefined。
给对象设置属性会创建自有属性。获取和设置行为规则的唯一例外是当它被 getter 或 setter 拦截时。
同理,你可以创建更长的原型链,并在原型链上查找一个属性。
const o = {
a: 1,
b: 2,
// __proto__ 设置了 [[Prototype]]。它在这里被指定为另一个对象字面量。
__proto__: {
b: 3,
c: 4,
__proto__: {
d: 5,
},
},
};
// { a: 1, b: 2 } ---> { b: 3, c: 4 } ---> { d: 5 } ---> Object.prototype ---> null
console.log(o.d); // 5
继承方法
JavaScript 并没有其他基于类的语言所定义的“方法”。在 JavaScript 中,任何函数都被可以添加到对象上作为其属性。函数的继承与其他属性的继承没有差别,包括上面的“属性遮蔽”(这种情况相当于其他语言的方法重写)。
当继承的函数被调用时,this
值指向的是当前继承的对象,而不是拥有该函数属性的原型对象。
const parent = {
value: 2,
method() {
return this.value + 1;
},
};
console.log(parent.method()); // 3
// 当调用 parent.method 时,“this”指向了 parent
// child 是一个继承了 parent 的对象
const child = {
__proto__: parent,
};
console.log(child.method()); // 3
// 调用 child.method 时,“this”指向了 child。
// 又因为 child 继承的是 parent 的方法,
// 首先在 child 上寻找“value”属性。但由于 child 本身
// 没有名为“value”的自有属性,该属性会在
// [[Prototype]] 上被找到,即 parent.value。
child.value = 4; // 在 child,将“value”属性赋值为 4。
// 这会遮蔽 parent 上的“value”属性。
// child 对象现在看起来是这样的:
// { value: 4, __proto__: { value: 2, method: [Function] } }
console.log(child.method()); // 5
// 因为 child 现在拥有“value”属性,“this.value”现在表示
// child.value
对象属性访问
const person1 = {};
person1['firstname'] = 'Mario';
person1['lastname'] = 'Rossi';
console.log(person1.firstname);
// "Mario"
const person2 = {
firstname: 'John',
lastname: 'Doe',
};
console.log(person2['lastname']);
// "Doe"
删除属性
const Employee = {
firstname: 'Maria',
lastname: 'Sanchez',
};
console.log(Employee.firstname);
// Expected output: "Maria"
delete Employee.firstname;
console.log(Employee.firstname);
// Expected output: undefined
遍历
for...in
for...in对于新手来说有些陌生,比如以下代码,我在想这个pron这个变量值为什么就可以输出a嘞,后面查了资料,他是把obj里面每一个的值赋给了pron
var obj = { a: 1, b: 2, c: 3 };
for (var prop in obj) {
console.log("obj." + prop + " = " + obj[prop]);
}
// Output:
// "obj.a = 1"
// "obj.b = 2"
// "obj.c = 3"
Object.keys()
这个好理解,key值就是如上面代码对象里面的a、b、c、d等
Object.values()
这个也好理解,value值就是key值后面的值,如上面代码a后面1,1就是value值
Object.entries()
他是静态方法返回一个数组,包含给定对象自有的可枚举字符串键属性的键值对
const object1 = {
a: 'somestring',
b: 42,
};
for (const [key, value] of Object.entries(object1)) {
console.log(`${key}: ${value}`);
}
// Expected output:
// "a: somestring"
// "b: 42"
Object.fromEntries()
他是静态方法将键值对列表转换为一个对象,他是这样理解的?先把entries遍历一遍,然后自己从entries里面的key和值转换成表?
const entries = new Map([
['foo', 'bar'],
['baz', 42],
]);
const obj = Object.fromEntries(entries);
console.log(obj);
// Expected output: Object { foo: "bar", baz: 42 }
Object.getOwnPropertyNames()
const object1 = {
a: 1,
b: 2,
c: 3,
};
console.log(Object.getOwnPropertyNames(object1));
// Expected output: Array ["a", "b", "c"]
这个也好理解,就是获取全部属性值为什么的并且在后台输出出来,记住他是静态方法返回一个数组
Object.defineProperty()
静态方法会直接在一个对象上定义一个新属性,或修改其现有属性,并返回此对象。
const object1 = {};
Object.defineProperty(object1, 'property1', {
value: 42,
writable: false,
});
object1.property1 = 77;
// Throws an error in strict mode
console.log(object1.property1);
// Expected output: 42
Object.defineProperties()
静态方法直接在一个对象上定义新的属性或修改现有属性,并返回该对象
const object1 = {};
Object.defineProperties(object1, {
property1: {
value: 42,
writable: true,
},
property2: {},
});
console.log(object1.property1);
// Expected output: 42
JSON.stringify()
将一个 JavaScript 对象或值转换为 JSON 字符串,如果指定了一个 replacer 函数,则可以选择性地替换值,或者指定的 replacer 是数组,则可选择性地仅包含数组指定的属性
console.log(JSON.stringify({ x: 5, y: 6 }));
// Expected output: '{"x":5,"y":6}'
console.log(
JSON.stringify([new Number(3), new String('false'), new Boolean(false)]),
);
// Expected output: '[3,"false",false]'
console.log(JSON.stringify({ x: [10, undefined, function () {}, Symbol('')] }));
// Expected output: '{"x":[10,null,null,null]}'
console.log(JSON.stringify(new Date(2006, 0, 2, 15, 4, 5)));
// Expected output: '"2006-01-02T15:04:05.000Z"'
常用方法
Object.freeze() 这个也好理解些,把东西冻结了就不能加、放、删东西了
Object.freeze()
静态方法可以使一个对象被冻结。冻结对象可以防止扩展,并使现有的属性不可写入和不可配置。被冻结的对象不能再被更改:不能添加新的属性,不能移除现有的属性,不能更改它们的可枚举性、可配置性、可写性或值,对象的原型也不能被重新指定。freeze()
返回与传入的对象相同的对象
const obj = {
prop: 42,
};
Object.freeze(obj);
obj.prop = 33;
// Throws an error in strict mode
console.log(obj.prop);
// Expected output: 42
Object.isFrozen()
判断一个对象是否被冻结,和是一个函数配套使用,返回布尔类型值
const object1 = {
property1: 42,
};
console.log(Object.isFrozen(object1));
// Expected output: false
Object.freeze(object1);
console.log(Object.isFrozen(object1));
// Expected output: true
Object.seal()
这个就和object.freez有些相似了,不同于他的是,通过 Object.seal()
密封的对象可以更改其现有属性,只要它们是可写的。
密封一个对象会阻止其扩展并且使得现有属性不可配置。密封对象有一组固定的属性:不能添加新属性、不能删除现有属性或更改其可枚举性和可配置性、不能重新分配其原型。只要现有属性的值是可写的,它们仍然可以更改。seal()
返回传入的同一对象。
const object1 = {
property1: 42,
};
Object.seal(object1);
object1.property1 = 33;
console.log(object1.property1);
// Expected output: 33
delete object1.property1; // Cannot delete when sealed
console.log(object1.property1);
// Expected output: 33
Object.is()
console.log(Object.is('1', 1));
// Expected output: false
console.log(Object.is(NaN, NaN));
// Expected output: true
console.log(Object.is(-0, 0));
// Expected output: false
const obj = {};
console.log(Object.is(obj, {}));
// Expected output: false
hasOwnPreperty()
返回一个布尔值,表示对象自有属性(而不是继承来的属性)中是否具有指定的属性。
const object1 = {};
object1.property1 = 42;
console.log(object1.hasOwnProperty('property1'));
// Expected output: true
console.log(object1.hasOwnProperty('toString'));
// Expected output: false
console.log(object1.hasOwnProperty('hasOwnProperty'));
// Expected output: false
propertyIsEnumerable()
返回一个布尔值,表示指定的属性是否是对象的可枚举自有属性。
const object1 = {};
const array1 = [];
object1.property1 = 42;
array1[0] = 42;
console.log(object1.propertyIsEnumerable('property1'));
// Expected output: true
console.log(array1.propertyIsEnumerable(0));
// Expected output: true
console.log(array1.propertyIsEnumerable('length'));
// Expected output: false
getOwnPropertyNames()
静态方法返回一个数组,其包含给定对象中所有自有属性(包括不可枚举属性,但不包括使用 symbol 值作为名称的属性)。
const object1 = {
a: 1,
b: 2,
c: 3,
};
console.log(Object.getOwnPropertyNames(object1));
// Expected output: Array ["a", "b", "c"]
getOwnPropertyDescriptor()
静态方法返回一个对象,该对象描述给定对象上特定属性(即直接存在于对象上而不在对象的原型链中的属性)的配置。返回的对象是可变的,但对其进行更改不会影响原始属性的配置。
const object1 = {
property1: 42,
};
const descriptor1 = Object.getOwnPropertyDescriptor(object1, 'property1');
console.log(descriptor1.configurable);
// Expected output: true
console.log(descriptor1.value);
// Expected output: 42
isPrototypeOf()
isPrototypeOf()
方法用于检查一个对象是否存在于另一个对象的原型链中。
function Foo() {}
function Bar() {}
Bar.prototype = Object.create(Foo.prototype);
const bar = new Bar();
console.log(Foo.prototype.isPrototypeOf(bar));
// Expected output: true
console.log(Bar.prototype.isPrototypeOf(bar));
// Expected output: true