all
Object()
Object是JavaScript的一种 数据类型 。它用于存储各种键值集合和更复杂的实体。Objects可以通过 **Object()**构造函数或者使用 对象字面量 的方式创建。Object构造函数为给定的参数创建一个包装类对象(object wrapper),具体有以下情况:
- 如果给定值是 null 或 undefined,将会创建并返回一个空对象
- 如果传进去的是一个基本类型的值,则会构造其包装类型的对象
- 如果传进去的是引用类型的值,仍然会返回这个值,经他们复制的变量保有和源对象相同的引用地址
语法:
let num = 123;
let numObj1 = new Number(num); // 通过 new Number() 转换成类型对象
console.log(numObj1); // 结果为 Number {123}
let numOjb2 = Object(num); // 通过 Object() 转换成类型对象
console.log(numOjb2); // 结果为 Number {123}
let str = 'abc';
let strObj1 = new String(str); // 通过 new String() 转换成类型对象
console.log(strObj1); // 结果 String {'abc'}
let strObj2 = Object(str); // 通过 Object() 转换成类型对象
console.log(strObj2); // 结果 String {'abc'}
let bool = true;
let boolObj1 = new Boolean(bool); // 通过 new Boolean() 转换成类型对象
console.log(boolObj1); // 结果 Boolean {true}
let boolObj2 = Object(bool); // 通过 Object() 转换成类型对象
console.log(boolObj2); // 结果 Boolean {true}
Object.assign()
Object.assign() 方法用于从一个或多个源对象拷贝自身可枚举的属性(String属性和Symbol属性),并且覆盖目标对象的同名属性。将所有可枚举属性的值分配到目标对象。它将返回目标对象。 **Object.assign()**中的目标对象不可以是null
或者undefined
,否则会报错。**Object.assign()**中的源对象对象如果是null
或者undefined
,会直接跳过。
语法
Object.assign(target, ...sources)
- target: 目标对象。
- sources: 源对象。
返回值
目标对象。
应用场景
-
拷贝对象: 拷贝源对象自身可枚举的属性(String属性和Symbol属性),并且覆盖目标对象的同名属性。
const s1Symbol = Symbol('s1');
const s2Symbol = Symbol('s2');
const obj1 = {
type1:'obj1',
[s1Symbol]:'s1Symbol'
}
Object.defineProperty(obj1,'value1',{
value:'哈哈',
writable:true,
enumerable:false,
configurable:true
});
const obj2 = {
type2:'obj2',
[s2Symbol]:'s2Symbol'
}
Object.defineProperty(obj2,'value2',{
value:'哈哈',
writable:true,
enumerable:true,
configurable:true
});
const obj = Object.assign({},obj1,obj2);
console.log(obj); // {type1: 'obj1', type2: 'obj2', value2: '哈哈', Symbol(s1): 's1Symbol', Symbol(s2): 's2Symbol'} -
Object.assign()
中的目标对象为null
或者undefined
会报错: Object.assign() 中的目标对象不可以是 null 或者undefinedconst s1Symbol = Symbol('s1');
const s2Symbol = Symbol('s2');
const obj1 = {
type1:'obj1',
[s1Symbol]:'s1Symbol'
}
Object.defineProperty(obj1,'value1',{
value:'哈哈',
writable:true,
enumerable:false,
configurable:true
});
const obj2 = {
type2:'obj2',
[s2Symbol]:'s2Symbol'
}
Object.defineProperty(obj2,'value2',{
value:'哈哈',
writable:true,
enumerable:true,
configurable:true
});
const obj = Object.assign(null,obj1,obj2);
console.log(obj); // Cannot convert undefined or null to object
原理(Polyfill)
这个polyfill不支持symbol属性, 由于 ES5 中本来就不存在 symbols :
Object.assign = function(target){
if(target === null || target === undefined){
throw new TypeError('Cannot convert undefined or null to object');
}
var object = Object(target);
for(var index=1; index < arguments.length ; index++){
var nextSource = arguments[index];
if(nextSource !== null && nextSource !== undefined){
for(var nextKey in nextSource){
if(Object.prototype.hasOwnProperty.call(nextSource,nextKey)){
object[nextKey] = nextSource[nextKey];
}
}
}
}
return object;
}
const obj1 = {
type1:'obj1',
}
Object.defineProperty(obj1,'value1',{
value:'哈哈',
writable:true,
enumerable:false,
configurable:true
});
const obj2 = {
type2:'obj2',
}
Object.defineProperty(obj2,'value2',{
value:'哈哈',
writable:true,
enumerable:true,
configurable:true
});
const obj = Object.assign({},obj1,obj2);
console.log(obj); // {type1: 'obj1', type2: 'obj2', value2: '哈哈'}
Object.create()
Object.create()方法创建一个新对象,使用现有的对象来提供新创建的对象的proto。
语法
Object.create(proto,[propertiesObject])
- proto: 新创建对象的原型对象。
- propertiesObject: 可选。需要传入一个对象,该对象的属性类型参照Object.defineProperties()的第二个参数。如果该参数被指定且不为 undefined,该传入对象的自有可枚举属性(即其自身定义的属性,而不是其原型链上的枚举属性)将为新创建的对象添加指定的属性值和对应的属性描述符。
Object.create()
的第二个参数与Object.defineProperties()
的第二个参数一样:每个新增属性都通过各自的描述符来描述。以这种方式添加的属性会遮蔽原型对象上的同名属性。
返回值
一个新对象,带着指定的原型对象和属性。
应用场景
-
通过
Object.create()
创建对象const prototype = {
type:'prototype'
}
const obj = Object.create(prototype,{
name:{
value:'obj',
writable:true,
enumerable:true,
configurable:true
},
type:{
value:'obj对象',
writable:true,
enumerable:true,
configurable:true
}
});
console.log(obj); // {name: 'obj', type: 'obj对象' [[Prototype]]: {type: "prototype"}} -
实现原型式继承
const person = {
name: "一个人",
friends: ["小明", "小红"],
};
const anotherPerson1 = Object.create(person, {
name: {
value: "另一个人",
writable: true,
enurmable: true,
configurable: true,
},
friends: {
value: ["另一个人的小明", "另一个人的小红"],
writable: true,
enurmable: true,
configurable: true,
},
});
console.log(anotherPerson1);
// F {}
// [[Prototype]]: Object
// friends: (2)['小明', '小红']
// name: "一个人"
// [[Prototype]]: Object
const anotherPerson2 = Object.create(person, {
name: {
value: "另一个人",
writable: true,
enurmable: true,
configurable: true,
},
friends: {
value: ["另一个人的小明", "另一个人的小红"],
writable: true,
enurmable: true,
configurable: true,
},
});
console.log(anotherPerson2);
原理(Polyfill)
Object.create = function (obj, descriptorMap) {
function converToDescriptor(descriptor) {
function hasProperty(obj, property) {
return Object.prototype.hasOwnProperty.call(obj, property);
}
var descriptorNew = {};
if (hasProperty(descriptor, "value")) {
descriptorNew.value = descriptor.value;
}
if (hasProperty(descriptor, "writable")) {
descriptorNew.writable = !!descriptor.writable;
}
if (hasProperty(descriptor, "enurmable")) {
descriptorNew.enumerable = !!descriptor.enumerable;
}
if (hasProperty(descriptor, "configurable")) {
descriptorNew.configurable = !!descriptor.configurable;
}
if (hasProperty(descriptor, "get")) {
var g = descriptor.get;
if (typeof g !== "function" && g != null) {
throw new TypeError("bad get");
}
descriptorNew.get = g;
}
if (hasProperty(descriptor, "set")) {
var s = descriptor.set;
if (typeof s !== "function" && s != null) {
throw new TypeError("bad set");
}
descriptorNew.set = s;
}
if (
("get" in descriptorNew || "set" in descriptorNew) &&
("value" in descriptorNew || "writable" in descriptorNew)
) {
throw new TypeError("identify-confused descriptor");
}
return descriptorNew;
}
if (typeof obj !== "object" && typeof obj !== "function") {
throw new TypeError(
"Object.create support only object as the first argument"
);
} else if (obj == null) {
throw new TypeError(
"Object.create support only object as the first argument"
);
}
if (typeof descriptorMap !== "object" && descriptorMap != null) {
throw new TypeError(
"Object.create support only object as the second argument"
);
}
function F() {}
F.prototype = obj;
var objNew = new F();
var keyArray = Object.keys(descriptorMap);
var descriptorArray = [];
for (var i = 0; i < keyArray.length; i++) {
descriptorArray.push([
keyArray[i],
converToDescriptor(descriptorMap[keyArray[i]]),
]);
}
for (var i = 0; i < descriptorArray.length; i++) {
Object.defineProperty(
objNew,
descriptorArray[i][0],
descriptorArray[i][1]
);
}
return objNew;
};
const obj = Object.create({},{
name:{
value:'柏拉图',
writable:true,
enurmable:true,
configurable:true
},
age:{
value:23,
writable:true,
enumerable:true,
configurable:true
}
});
console.log(obj);
Object.defineProperties()
**Object.defineProperties()**方法直接在一个对象上定义新的属性或修改现有属性,并返回该对象。
语法
Object.defineProperties(obj, props)
- obj: 在其上定义或修改属性的对象。
- props: 要定义其可枚举属性或修改的属性描述符的对象。对象中存在的属性描述符主要有两种:数据描述符和访问器描述符(更多详情,请参阅Object.defineProperty())。
返回值
应用场景
-
创建、修改、删除属性
-
通过数据描述符创建、修改、删除属性
const obj = {};
Object.defineProperties(obj,{
name:{
value:'柏拉图',
writable:true,
enumerable:true,
configurable:true
},
age:{
value:23,
writable:true,
enumerable:true,
configurable:true
}
});
console.log(obj.name);
console.log(obj.age);
obj.name = '柏拉图修改';
obj.age = '23修改';
console.log(obj.name);
console.log(obj.age);
for(let key in obj){
console.log(key);
}
delete obj.name;
delete obj.age;
console.log(obj); -
通过存取描述符创建、修改、删除属性
const obj = {};
Object.defineProperties(obj,{
name:{
enumerable:true,
configurable:true,
get(){
console.log('访问操作');
return this._name;
},
set(newValue){
console.log('设置操作');
this._name = newValue;
}
},
age:{
enumerable:true,
configurable:true,
get(){
console.log('访问操作');
return this._age;
},
set(newValue){
console.log('设置操作');
this._age = newValue;
}
}
});
console.log(obj.name);
console.log(obj.age);
obj.name = '柏拉图修改';
obj.age = '23修改';
console.log(obj.name);
console.log(obj.age);
for(let key in obj){
console.log(key);
}
delete obj.name;
delete obj.age;
console.log(obj);
-
原理(Polyfill)
Object.defineProperties = function (obj, properties) {
function converToDescriptor(desc) {
function hasProperty(obj, prop) {
return Object.prototype.hasOwnProperty.call(obj, prop);
}
if (typeof desc !== "object" || desc === null) {
throw new TypeError("bad desc");
}
var descriptor = {};
if (hasProperty(desc, "enumerable")) {
descriptor.enumerable = !!desc.enumerable;
}
if (hasProperty(desc, "configurable")) {
descriptor.configurable = !!desc.configurable;
}
if(hasProperty(desc,'value')){
descriptor.value = desc.value;
}
if(hasProperty(desc,'writable')){
descriptor.writable = !!desc.writable;
}
if(hasProperty(desc,'get')){
var g = desc.get;
if(!typeof g === "function" && typeof g !== 'undefined'){
throw new TypeError('bad get');
}
descriptor.get = g;
}
if(hasProperty(desc,'set')){
var s = desc.set;
if(!typeof s === "function" && typeof s !== "undefined"){
throw new TypeError("bad set");
}
descriptor.set = s;
}
if(('get' in descriptor || 'set' in descriptor) && ('value' in descriptor || 'writable' in descriptor)){
throw new TypeError('identity-confused descriptor');
}
return descriptor;
}
if(typeof obj !== 'object' || obj === null){
throw new TypeError('bad obj');
}
var propertiesObj = Object(properties);
var keyArray = Object.keys(propertiesObj);
var descriptorArray = [];
for(var i=0;i<keyArray.length;i++){
console.log(converToDesCriptor(propertiesObj[keyArray[i]]));
descriptorArray.push([keyArray[i],converToDesCriptor(propertiesObj[keyArray[i]])]);
}
for(var i=0;i<descriptorArray.length;i++){
Object.defineProperty(obj,descriptorArray[i][0],descriptorArray[i][1]);
}
console.log(obj);
return obj;
};
const obj = {};
Object.defineProperties(obj, {
name: {
value: "柏拉图",
writable: true,
enumerable: true,
configurable: true,
},
age: {
value: 23,
writable: true,
enumerable: true,
configurable: true,
},
});
console.log(obj);
Object.entries()
Object.entries()
方法返回一个给定对象自身****可枚举属性的键值对数组,
语法
Object.entries(obj)
- obj: 可以返回其可枚举属性的键值对的对象。
返回值
给定对象自身可枚举属性的键值对数组。
应用场景
经典问题
-
如何遍历对象属性?有几种方法以及各自的特点?
-
通过
Object.keys(obj)
遍历对象属性,获取的是对象自身的所有可枚举属性const obj = {};
Object.defineProperty(obj,'name',{
value:'柏拉图',
writable:true,
enumerable:true, // 属性可枚举
configurable:true
});
Object.defineProperty(obj,'age',{
value:'柏拉图',
writable:true,
enumerable:false, // 属性不可枚举
configurable:true
});
obj.__proto__ = {
nameProto:'柏拉图',
ageProto:23
}
console.log(Object.keys(obj)); // ['name'] -
通过
for……in
遍历对象属性,获取的是对象自身以及对象原型上的所有可枚举属性const obj = {};
Object.defineProperty(obj,'name',{
value:'柏拉图',
writable:true,
enumerable:true, // 属性可枚举
configurable:true
});
Object.defineProperty(obj,'age',{
value:'柏拉图',
writable:true,
enumerable:false, // 属性不可枚举
configurable:true
});
obj.__proto__ = {
nameProto:'柏拉图',
ageProto:23
}
for(let key in obj){
console.log(key); // 输出 name nameProto ageProto
} -
通过
Object.getOwnPropertyNames(obj)
遍历,获取的是对象自身所有可枚举和不可枚举属性。const obj = {};
Object.defineProperty(obj,'name',{
value:'柏拉图',
writable:true,
enumerable:true, // 属性可枚举
configurable:true
});
Object.defineProperty(obj,'age',{
value:'柏拉图',
writable:true,
enumerable:false, // 属性不可枚举
configurable:true
});
obj.__proto__ = {
nameProto:'柏拉图',
ageProto:23
}
const result = Object.getOwnPropertyNames(obj);
console.log(result); ['name', 'age'] -
通过
Object.entries(obj)
遍历属性,获取的是对象自身可枚举属性键值对数组const obj = {};
Object.defineProperty(obj,'name',{
value:'柏拉图',
writable:true,
enumerable:true, // 属性可枚举
configurable:true
});
Object.defineProperty(obj,'age',{
value:'柏拉图',
writable:true,
enumerable:false, // 属性不可枚举
configurable:true
});
obj.__proto__ = {
nameProto:'柏拉图',
ageProto:23
}
const result = Object.entries(obj);
console.log(result); /// [0: (2) ['name', '柏拉图']]
-
-
如何获取对象
自身
所有可枚举属性?有几种方法?-
通过
Object.keys(obj)
遍历对象属性,获取的是对象自身的所有可枚举属性const obj = {};
Object.defineProperty(obj,'name',{
value:'柏拉图',
writable:true,
enumerable:true, // 属性可枚举
configurable:true
});
Object.defineProperty(obj,'age',{
value:'柏拉图',
writable:true,
enumerable:false, // 属性不可枚举
configurable:true
});
obj.__proto__ = {
nameProto:'柏拉图',
ageProto:23
}
console.log(Object.keys(obj)); // ['name'] -
通过
for……in
遍历对象属性,获取的是对象自身以及对象原型上的所有可枚举属性,然后通过obj.hasOwnProperty(prop)
进行过滤const obj = {};
Object.defineProperty(obj,'name',{
value:'柏拉图',
writable:true,
enumerable:true, // 属性可枚举
configurable:true
});
Object.defineProperty(obj,'age',{
value:'柏拉图',
writable:true,
enumerable:false, // 属性不可枚举
configurable:true
});
obj.__proto__ = {
nameProto:'柏拉图',
ageProto:23
}
for(let key in obj){
if(obj.hasOwnProperty(key)){
console.log(key); // 输出 name
}
}
-
-
如何获取对象
自身
所有不可枚举属性?有几种方法?-
通过
Object.getOwnPropertyNames(obj)
遍历,获取的是对象自身所有可枚举和不可枚举属性。然后通过Object.keys(obj)
过滤const obj = {};
Object.defineProperty(obj,'name',{
value:'柏拉图',
writable:true,
enumerable:true, // 属性可枚举
configurable:true
});
Object.defineProperty(obj,'age',{
value:'柏拉图',
writable:true,
enumerable:false, // 属性不可枚举
configurable:true
});
obj.__proto__ = {
nameProto:'柏拉图',
ageProto:23
}
const allSelfEnumerable = Object.keys(obj);
const result = Object.getOwnPropertyNames(obj).filter(key=>{
if(!allSelfEnumerable.includes(key)){
return true;
}
return false;
});
console.log(result); // ['age']
-
-
如何获取对象
自身
所有可枚举和不可枚举属性?有几种方法?-
通过
Object.getOwnPropertyNames(obj)
遍历,获取的是对象自身所有可枚举和不可枚举属性。const obj = {};
Object.defineProperty(obj,'name',{
value:'柏拉图',
writable:true,
enumerable:true, // 属性可枚举
configurable:true
});
Object.defineProperty(obj,'age',{
value:'柏拉图',
writable:true,
enumerable:false, // 属性不可枚举
configurable:true
});
obj.__proto__ = {
nameProto:'柏拉图',
ageProto:23
}
const result = Object.getOwnPropertyNames(obj);
console.log(result); ['name', 'age']
-
原理(Polyfill)
Object.entries = function(obj){
var keyArray = Object.keys(obj);
var length = keyArray.length;
var result = new Array(length);
var index = 0;
while(index < length){
result[index] = [keyArray[index],obj[keyArray[index]]];
index++;
}
return result;
}
const obj = {
type:'对象',
data:[]
}
console.log(Object.entries(obj));
Object.freeze()
Object.freeze() 方法可以冻结一个对象。一个被冻结的对象再也不能被修改;冻结了一个对象则不能向这个对象添加新的属性,不能删除已有属性,不能修改该对象已有属性的可枚举性、可配置性、可写性,以及不能修改已有属性的值。此外,冻结一个对象后该对象的原型也不能被修改。
语法
Object.freeze(obj)
- obj: 要被冻结的对象。
返回值
被冻结的对象。
应用场景
-
冻结对象
const obj = {
name: "柏拉图",
age: 23,
};
Object.freeze(obj);
obj.like = '编程'; // 已冻结对象不可添加新属性,添加失效
obj.name = '柏拉图修改'; // 已冻结对象不可修改属性,修改失效
delete obj.name; // 已冻结对象不可删除属性,删除失效
console.log(obj); -
冻结数组
const array = ['哈哈','呵呵'];
Object.freeze(array);
array[0] = '哈哈修改';
console.log(array[0]); // 哈哈
经典问题
-
如何使对象变得不可扩展?有几种方法可以实现
-
通过
Object.seal(obj)
变得不可扩展const obj = {
name: "柏拉图",
age: 23,
};
if (Object.isExtensible(obj)) {
Object.seal(obj);
}
obj.like = "编程";
console.log(obj); // {name: '柏拉图', age: 23} -
通过
Object.freeze()
变得不可扩展const obj = {
name: "柏拉图",
age: 23,
};
if (Object.isExtensible(obj)) {
Object.freeze(obj);
}
obj.like = "编程";
console.log(obj); // {name: '柏拉图', age: 23} -
通过
Object.preventExtensions(obj)
-