参考
mdn
Javascript高级程序设计(第三版)
数据属性:
包含一下四个特性
[[configurable]]:表示能否通过delete删除属性从而重新定义属性,能否修改属性的特性,或者能否把属性修改为访问器属性。
[[Enumerable]]:表示能否通过for-in循环返回属性。
[[Writable]]:表示能否修改属性的值。
[[Value]]:包含这个属性的数据值。读取属性值的时候,从这个位置读;写入属性值的时候,把新值保存在这个位置。这个特性的默认值为undefined。
访问器属性:
包含以下四个特性
[[configurable]]:表示能否通过delete删除属性从而重新定义属性,能否修改属性的特性,或者能否把属性修改为访问器属性。
[[Enumerable]]:表示能否通过for-in循环返回属性。
[[Get]]:在读取属性时调用的函数。默认值为undefined。
[[Set]]:在写入属性时调用的函数。默认值为undefined。
数据属性与访问器属性区别:
1、访问器属性不能直接定义,必须使用 Object.defineProprerty()来定义
2、对象中定义属性的命名规则,命名中的下划线只是个人习惯或部分约定俗成,以下划线开头的属性不作为公开属性,只可以由对象的方法访问,但其本质上与普通属性没有区别
修改属性默认的特性,使用此方法
Object.defineProperty(obj,prop,descriptor)
// 对象的单个属性
let student = {}
Object.defineProperty(student,'name',{
value: 'zhangsan',
configurable: false,
enumerable: false,
writable: false
})
Object.defineProperties(obj,props)
// 对象的多个属性
let student = {}
Object.defineProperties(student,{
'name': {
value: 'zhangsan',
configurable: false,
enumerable: false,
writable: false
},
'age': {
value: '18',
configurable: false,
enumerable: false,
writable: false
}
})
Object.getOwnPropertyDescriptor(obj,prop)
返回对象上一个自有属性对应的属性描述符(不会去查原型链)
let student = {
age: 18
};
let descriptor1 = Object.getOwnPropertyDescriptor(student, 'age');
console.log(descriptor1.configurable);
console.log(descriptor1.value);
Object.getPrototypeOf(obj)
返回指定对象的原型
内部[[Prototype]]属性的值
let parent = {}
let student = Object.create(parent)
console.log(Object.getPrototypeOf(student) === parent) // true
Object.keys(obj)
返回一个表示给定对象的所有可枚举属性的字符串数组
let student = {}
Object.defineProperty(student,'name',{
value: 'zhangsan',
configurable: true,
enumerable: false,
writable: true
})
Object.keys(student) // []
// 如果enumerable值为true 则返回["name"]
Object.getOwnPropertyNames(obj)
返回自身属性对应的字符串数组。
let student = {}
Object.defineProperty(student,'name',{
value: 'zhangsan',
configurable: true,
enumerable: false,
writable: true
})
Object.getOwnPropertyNames(student) // ["name"]
// 可以拿到自身属性上的不可枚举属性
obj.hasOwnProperty(prop)
返回boolean 用来判断某个对象是否包含某个属性,会忽略从原型链上继承到的属性
let student = {
age: 18
};
student.hasOwnProperty('age') // true
student.hasOwnProperty('toString') // false
prototypeObj.isPrototypeOf(obj)
判断一个对象是否存在于另一个对象的原型链上,返回boolean值,在obj原型链上查找
function Foo() {}
function Bar() {}
function Baz() {}
Bar.prototype = Object.create(Foo.prototype)
Baz.prototype = Object.create(Bar.prototype)
let baz = new Baz()
// Baz.prototype是否存在于baz的原型链上
console.log(Baz.prototype.isPrototypeOf(baz)) // true
console.log(Bar.prototype.isPrototypeOf(baz)) // true
console.log(Foo.prototype.isPrototypeOf(baz)) // true
obj instanceof constructor
检测构造函数的prototype属性是否出现在某个实例对象的原型链上
检测constructor.prototype是否存在于参数obj的原型链上
function Student(name, age) {
this.name = name
this.age = age
}
let student1 = new Student('zhangsan', 18)
console.log(student1 instanceof Student) // true
console.log(student1 instanceof Obejct) // true
2021.07.22更新
[MDN] (https://developer.mozilla.org/zh-CN/docs/orphaned/Web/JavaScript/Reference/Global_Objects/Object)
静态方法
1、Object.assign():将所有可枚举属性的值从一个或多个源对象分配到目标对象。return目标对象
// 语法:Object.assign(target, ...sources)
const target = { a: 1, b: 2 };
const source = { b: 4, c: 5 };
const returnedTarget = Object.assign(target, source);
console.log(target); // { a: 1, b: 4, c: 5 }
console.log(returnedTarget);//{ a: 1, b: 4, c: 5 }
// tips: Object.assign()拷贝的是(可枚举)属性值。假如源值是一个对象的引用,它仅仅会复制其引用值。
2、Object.create(): 创建新对象 指定新对象的proto
// 语法:Object.create(proto,[propertiesObject])
// 返回的新对象的__proto__指向 proto
// Shape - 父类(superclass)
function Shape() {
this.x = 0;
this.y = 0;
}
// 父类的方法
Shape.prototype.move = function(x, y) {
this.x += x;
this.y += y;
console.info('Shape moved.');
};
// Rectangle - 子类(subclass)
function Rectangle() {
Shape.call(this); // call super constructor.
}
// 子类续承父类
Rectangle.prototype = Object.create(Shape.prototype);
Rectangle.prototype.constructor = Rectangle;
var rect = new Rectangle();
console.log('Is rect an instance of Rectangle?',rect instanceof Rectangle); // true
console.log('Is rect an instance of Shape?',rect instanceof Shape); // true
rect.move(1, 1); // Outputs, 'Shape moved.
console.log(Rectangle.prototype.__proto__ === Shape.prototype) // true
3、Object.entries() : 返回一个给定对象自身可枚举属性的键值对数组
(for...in.. 会枚举原型链上的属性)
const object1 = {
a: 'somestring',
b: 42
};
for (const [key, value] of Object.entries(object1)) {
console.log(`${key}: ${value}`);
}
// a: somestring
// b: 42
4、Object.freeze():冻结一个对象。freeze() 返回和传入的参数相同的对象。
一个被冻结的对象再也不能被修改;
- 不能向这个对象添加新的属性,
- 不能删除已有属性,
- 不能修改该对象已有属性的可枚举性、可配置性、可写性,
- 不能修改已有属性的值。
- 该对象的原型也不能被修改。
// 特殊情况
obj1 = {
internal: {}
};
Object.freeze(obj1);
obj1.internal.a = 'aValue';
obj1.internal.a // 'aValue'
5、Object.getOwnPropertySymbols():获取给定对象自身的所有Symbol属性的数组
var obj = {};
var a = Symbol("a");
var b = Symbol.for("b");
obj[a] = "localSymbol";
obj[b] = "globalSymbol";
var objectSymbols = Object.getOwnPropertySymbols(obj);
console.log(objectSymbols.length); // 2
console.log(objectSymbols) // [Symbol(a), Symbol(b)]
console.log(objectSymbols[0]) // Symbol(a)
6、Object.is() : 判断两个值是否为同一个值
- 都是
undefined
- 都是
null
- 都是
true
或false
- 都是相同长度的字符串且相同字符按相同顺序排列
- 都是相同对象(意味着每个对象有同一个引用)
- 都是数字且
- 都是
+0
- 都是
-0
- 都是
NaN
- 或都是非零而且非 [
NaN
]且为同一个值
- 都是
// 语法:Object.is(value1, value2)
Object.is(undefined, undefined) // true
Object.is(NaN, NaN) // true
NaN === NaN // false
Object.is(+0, -0) // false
7、Object.isExtensible(obj): 判断一个对象是否是可扩展的
// 新对象默认是可扩展的.
var empty = {};
Object.isExtensible(empty); // === true
// ...可以变的不可扩展.
Object.preventExtensions(empty);
Object.isExtensible(empty); // === false
// 密封对象是不可扩展的.
var sealed = Object.seal({});
Object.isExtensible(sealed); // === false
// 冻结对象也是不可扩展.
var frozen = Object.freeze({});
Object.isExtensible(frozen); // === false
8、Object.isFrozen(obj) : 判断一个对象是否被冻结
tips:一个对象是冻结的是指它不可扩展
,所有属性都是不可配置
的,且所有数据属性(即没有getter或setter组件的访问器的属性)都是不可写
的。
// 一个对象默认是可扩展的,所以它也是非冻结的.
Object.isFrozen({}); // === false
// 一个不可扩展的空对象同时也是一个冻结对象.
var vacuouslyFrozen = Object.preventExtensions({});
Object.isFrozen(vacuouslyFrozen) //=== true;
// 一个非空对象默认也是非冻结的.
var oneProp = { p: 42 };
Object.isFrozen(oneProp) //=== false
// 让这个对象变的不可扩展,并不意味着这个对象变成了冻结对象,
// 因为p属性仍然是可以配置的(而且可写的).
Object.preventExtensions(oneProp);
Object.isFrozen(oneProp) //=== false
// 此时,如果删除了这个属性,则它会成为一个冻结对象.
delete oneProp.p;
Object.isFrozen(oneProp) //=== true
// 一个不可扩展的对象,拥有一个不可写但可配置的属性,则它仍然是非冻结的.
var nonWritable = { e: "plep" };
Object.preventExtensions(nonWritable);
Object.defineProperty(nonWritable, "e", { writable: false }); // 变得不可写
Object.isFrozen(nonWritable) //=== false
// 把这个属性改为不可配置,会让这个对象成为冻结对象.
Object.defineProperty(nonWritable, "e", { configurable: false }); // 变得不可配置
Object.isFrozen(nonWritable) //=== true
// 一个不可扩展的对象,拥有一个不可配置但可写的属性,则它仍然是非冻结的.
var nonConfigurable = { release: "the kraken!" };
Object.preventExtensions(nonConfigurable);
Object.defineProperty(nonConfigurable, "release", { configurable: false });
Object.isFrozen(nonConfigurable) //=== false
// 把这个属性改为不可写,会让这个对象成为冻结对象.
Object.defineProperty(nonConfigurable, "release", { writable: false });
Object.isFrozen(nonConfigurable) //=== true
// 一个不可扩展的对象,值拥有一个访问器属性,则它仍然是非冻结的.
var accessor = { get food() { return "yum"; } };
Object.preventExtensions(accessor);
Object.isFrozen(accessor) //=== false
// ...但把这个属性改为不可配置,会让这个对象成为冻结对象.
Object.defineProperty(accessor, "food", { configurable: false });
Object.isFrozen(accessor) //=== true
// 使用Object.freeze是冻结一个对象最方便的方法.
var frozen = { 1: 81 };
Object.isFrozen(frozen) //=== false
Object.freeze(frozen);
Object.isFrozen(frozen) //=== true
// 一个冻结对象也是一个密封对象.
Object.isSealed(frozen) //=== true
// 当然,更是一个不可扩展的对象.
Object.isExtensible(frozen) //=== false
9、Object.is(obj):判断一个对象是否被密封
tips:如果这个对象是密封的,则返回 true
,否则返回 false
。密封对象是指那些不可 扩展
的,且所有自身属性都不可配置
且因此不可删除(但不一定是不可写)
的对象。
// 新建的对象默认不是密封的.
var empty = {};
Object.isSealed(empty); // === false
// 如果你把一个空对象变的不可扩展,则它同时也会变成个密封对象.
Object.preventExtensions(empty);
Object.isSealed(empty); // === true
// 但如果这个对象不是空对象,则它不会变成密封对象,因为密封对象的所有自身属性必须是不可配置的.
var hasProp = { fee: "fie foe fum" };
Object.preventExtensions(hasProp);
Object.isSealed(hasProp); // === false
// 如果把这个属性变的不可配置,则这个属性也就成了密封对象.
Object.defineProperty(hasProp, 'fee', {
configurable: false
});
Object.isSealed(hasProp); // === true
// 最简单的方法来生成一个密封对象,当然是使用Object.seal.
var sealed = {};
Object.seal(sealed);
Object.isSealed(sealed); // === true
// 一个密封对象同时也是不可扩展的.
Object.isExtensible(sealed); // === false
// 一个密封对象也可以是一个冻结对象,但不是必须的.
Object.isFrozen(sealed); // === true ,所有的属性都是不可写的
var s2 = Object.seal({ p: 3 });
Object.isFrozen(s2); // === false, 属性"p"可写
var s3 = Object.seal({ get p() { return 0; } });
Object.isFrozen(s3); // === true ,访问器属性不考虑可写不可写,只考虑是否可配置
10、Object.preventExtensions(obj):让一个对象变得不可扩展(永远不能再添加新的属性)
// Object.preventExtensions将原对象变的不可扩展,并且返回原对象.
var obj = {};
var obj2 = Object.preventExtensions(obj);
obj === obj2; // true
// 字面量方式定义的对象默认是可扩展的.
var empty = {};
Object.isExtensible(empty) //=== true
// ...但可以改变.
Object.preventExtensions(empty);
Object.isExtensible(empty) //=== false
// 使用Object.defineProperty方法为一个不可扩展的对象添加新属性会抛出异常.
var nonExtensible = { removable: true };
Object.preventExtensions(nonExtensible);
Object.defineProperty(nonExtensible, "new", { value: 8675309 }); // 抛出TypeError异常
11、Object.seal(obj) :封闭一个对象,阻止添加新属性,并将现有属性标记为不可配置,当前属性的值只要是原来是可写的就可以改变
tips:通常,一个对象是可扩展的
(可以添加新的属性)。密封一个对象会让这个对象变的不能添加新属性,且所有已有属性会变的不可配置。属性不可配置的效果就是属性变的不可删除
,以及一个数据属性不能被重新定义成为访问器属性
,或者反之。但属性的值仍然可以修改。尝试删除一个密封对象的属性或者将某个密封对象的属性从数据属性转换成访问器属性,结果会静默失败或抛出TypeError
(在严格模式 中最常见的,但不唯一)。
不会影响从原型链上继承的属性。但 __proto__
( ) 属性的值也会不能修改。
var obj = {
prop: function() {},
foo: 'bar'
};
// 可以添加新的属性
// 可以更改或删除现有的属性
obj.foo = 'baz';
obj.lumpy = 'woof';
delete obj.prop;
// 密封对象后
var o = Object.seal(obj);
o === obj; // true
Object.isSealed(obj); // === true
obj.foo = 'quux';// 仍然可以修改密封对象的属性值
Object.defineProperty(obj, 'foo', {
get: function() { return 'g'; }
}); // throws a TypeError 不能将属性重新定义成为访问器属性
obj.quaxxor = 'the friendly duck';// 添加属性将会失败
delete obj.foo;// 删除属性将会失败
// 在严格模式下,这样的尝试将会抛出错误
function fail() {
'use strict';
delete obj.foo; // throws a TypeError
obj.sparky = 'arf'; // throws a TypeError
}
fail();
Object.defineProperty(obj, 'ohai', {
value: 17
}); // throws a TypeError 通过Object.defineProperty添加属性将会报错
Object.defineProperty(obj, 'foo', {
value: 'eit'
}); // 通过Object.defineProperty修改属性值 可修改成功
12、Object.values() :返回一个给定对象自身的所有可枚举属性值的数组
(for...in.. 会枚举原型链上的属性)
var obj = { foo: 'bar', baz: 42 };
console.log(Object.values(obj)); // ['bar', 42]
// array like object
var obj = { 0: 'a', 1: 'b', 2: 'c' };
console.log(Object.values(obj)); // ['a', 'b', 'c']
// array like object with random key ordering
// when we use numeric keys, the value returned in a numerical order according to the keys
var an_obj = { 100: 'a', 2: 'b', 7: 'c' };
console.log(Object.values(an_obj)); // ['b', 'c', 'a']
// getFoo is property which isn't enumerable
var my_obj = Object.create({}, { getFoo: { value: function() { return this.foo; } } });
my_obj.foo = 'bar';
console.log(Object.values(my_obj)); // ['bar']
// non-object argument will be coerced to an object
console.log(Object.values('foo')); // ['f', 'o', 'o']