共计 11356 个字符,预计需要花费 29 分钟才能阅读完成。
什么是对象
对象是 JavaScript 的根本数据类型。是属性的无序汇合,每个属性都是一个键值对。属性又分为两种:一种是数据属性,一种是办法属性。(另一种说法是:对象是键值对的汇合,对象是由属性和办法形成的)
对象属性名是字符串,所以对象又能够看成是字符串到值的映射。字符串到值的映射这种构造,通常还有一些其它的叫法,比方:散列表、字典、关联数组。
JavaScript 对象是动静的,咱们能够对对象执行新增属性,删除属性的操作。在 JS 当中除了字符串、数字、true、false、null、undefined 这些值之外,其它所有的值都是对象。
对象的创立形式
对象间接量
创建对象最简略的形式就是应用对象间接量。比方如下代码:
// 创立一个空对象
const o1 = {};
// 创立一个带有属性和办法的对象
const o2 = {
name: "thirteen",
class: "class",
age: 18,
say: function () {console.log("console.log: say hello");
}
};
console.log(o2.class, "关键字当做属性名");
o2.say();
new 运算符(构造函数)
new 运算符创立并初始化一个新对象,new 运算符前面紧跟一个函数调用。new 后追随的函数被成为构造函数。
应用构造函数创建对象
let o = new Object(); // 创立一个空对象,和{}(对象间接量)一样
let a = new Array(); // 创立一个空数组对象,和 [] 一样
function papa(){};
let child = new papa(); // 通过实例化构造函数 papa 来创立一个对象。
Object.create
Object.create 办法是 ES5 中新增创建对象的一个办法。该办法有两个参数,第一个参数必选是新创建对象的原型,第二个参数是对对象属性的形容。Object.create 办法返回一个新的对象
语法
Object.create(proto,[propertiesObject])
// 创立没有原型的新对象
const o1 = Object.create(null);
// 从该办法的介绍中咱们能够看到,第一个参数是新创建对象的原型,// o1 创立的时候传入 null,则示意 o1 是没有原型的新对象,没有原型,也就没有继承任何的办法和属性。// 创立一个具备原型的对象
const o2 = Object.create(Object.prototype); // 相当于 {} 和 new Object()创建对象一样
// 创立一个以另一个空对象为原型, 且领有一个属性 p 的对象
const o3 = Object.create({}, { p: { value: 42} })
const o4 = Object.create(Object.prototype, {
// foo 会成为所创建对象的数据属性
foo: {
writable:true,
configurable:true,
value: "hello"
},
// bar 会成为所创建对象的拜访器属性
bar: {
configurable: false,
get: function() { return 10},
set: function(value) {console.log("Setting `o.bar` to", value);
}
}
});
// 创立一个继承现有对象的新对象
const person = {
name:"thirteen",
age:18,
say:function(){console.log(`name:${this.name},age:${this.age} `);
}
}
const o3 = Object.create(person);
o3.name === "thirteen" // true
o3.age === 18 // true
o3.say(); // name:thirteen,age:18
用 Object.create 实现类式继承
// 父类
function parent(){
this.x = 0;
this.y = 0;
}
// 父类的办法
parent.prototype.move = function(x,y){
this.x += x;
this.y += y;
console.log('move 执行了');
}
// 子类
function child(){parent.call(this);
}
// 子类继承父类
child.prototype = Object.create(parent.prototype);
child.prototype.constructor = child;
// 实例化
var o1 = new child();
console.log(o1 instanceof child);
console.log(o1 instanceof parent);
o1.move(2,2);
对象的属性
一个 JavaScript 对象有很多属性。一个对象的属性能够被解释成一个附加到对象上的变量。对象属性和一般的 JavaScript 变量根本没有什么区别,仅仅是属性属于某个对象。
属性查问和设置(批改)
属性的查问和设置有两种形式,第一种是应用(•)点运算符.,第二种是应用([])方括号运算符。在 ES3,应用 ”.” 点运算符前面是不能跟 JS 当中的保留字的,例如:for,class,function 等,不过在 ES5 之后就不存在这种问题了,所以上面的代码在古代浏览器外面是不会有问题的.obj.for = "for"
。如果应用方括号[],方括号两头在 ES6 之前必须是一个计算结果为字符串的表达式。在古代浏览器当中,方括号表达式两头还能够是 Symbol 类型。
点运算符
// 定义一个对象 o1
const o1 = {
name:"thirteen",
age:18
}
// 读取对象 o1 的属性
o1.name // thirteen
o1.age // 18
// 批改对象 o1 的属性,如果属性名原来就有,就是批改,如果原来对象上没有该属性,就是新增
o1.sex = "男";
o1.say = function(){console.log('i say');
}
console.log(o1.name);
//
const name = "thirteen";
const age = 18;
const o2 = {
name,
age
}
o2.name // thirteen
o2.age // 18
方括号运算符
当通过 [] 来拜访(新增,批改)对象的属性时,属性名通过字符串来示意。字符串是 JS 的根本数据类型,在程序运行时咱们能够批改和创立他们。因为有方括号这种拜访对象的形式,有时候对象也被叫做关联数组,只不过数组的索引是数字,对象的索引是字符串。
const addr = "";
const obj = {
p0:"p0",
p1:"p1",
p2:"p2",
p3:"p3"
};
for(i=0;i<4;i++){addr += obj["p"+i] + '\n';
}
// 当对象的属性名字无奈确认(动静)的时候,只能通过方括号拜访
function addStock(portfolio,name,shares){portfolio[name] = shares;
}
// 同时创立四个变量,用逗号宰割
const myObj = new Object(),
str = "myString",
rand = Math.random(),
obj = new Object();
myObj.type = "点运算符";
myObj['data create'] = '有空格的字符串';
myObj[str] = "字符串值";
myObj[rand] = "随机数";
myObj[obj] = "Object 对象";
myObj[""] =" 空字符串 ";// PS:方括号中所有的键都将转换为字符串类型。
两种形式比拟
点运算符
- 使用方便灵便
- 有肯定的限度,当对象的属性是数字结尾的字符串、空字符串、连字符就不能应用点运算符来拜访
- 点运算符前面紧跟的标识符是动态的,必须写死在程序中
方括号运算符
- 应用全面,所有点运算符能拜访的不能拜访的属性,方括号都能够拜访
- 当对象的属性是无奈提前得悉的时候,只能应用方括号运算符
属性的删除
delete 运算符能够删除对象的属性;不过只能删除对象本身的属性,不能删除对象继承的属性。另外,如果对象的属性的可配置值是 false 的时候,也是不可能被删除的。delete 表达式执行胜利后,会返回一个 true
const o1 = {name:"thirteen"}
Object.defineProperty(o1, 'age', {
value: 42,
configurable: false
});
// 能够删除
delete o1.name
console.log(o1.name) // 返回 undefined
// 不能够删除,因为属性的可配置值 configurable 是 false
delete o1.age
console.log(o1.age) // 返回 42
// 不能够删除
delete o1.toString
属性的枚举
属性遍历的秩序
- 先遍历数字键,依照谁小谁先的形式
- 再遍历字符串键,依照在对象中的地位排列
- 最初遍历 Symbol,依照退出工夫升序排列。
// 对象属性遍历的秩序
Reflect.ownKeys({[Symbol()]:0,
b:0,
10:0,
2:0,
a:0
})
// 返回后果
['2','10','a','b',Symbol()]
for…in 循环
该办法顺次拜访一个对象以及其原型链中所有可枚举的属性
const o = {
x: 1,
y: 2,
z: 3,
};
// 对象 o1 继承 对象 o
const o1 = Object.create(o, {
foo: {
writable: true,
configurable: true,
enumerable:true, // 能够被枚举
value: "hello",
},
// bar 会成为所创建对象的拜访器属性
bar: {
configurable: false,
get: function () {return 10;},
set: function (value) {console.log("Setting `o.bar` to", value);
},
},
});
console.log("打印对象 o1 的属性名和属性值");
for (prop in o1) {console.log(`${prop}:${o1[prop]}`);
}
// foo:hello x:1 y:2 z:3
// 给对象 o1 新增 a 属性,属性可枚举配置为 true 可能遍历失去
Object.defineProperty(o1, "a", {
value: "4",
enumerable: true,
});
// 给对象 o1 新增 b 属性,属性可枚举配置为 false 不能可能遍历失去
Object.defineProperty(o1, "b", {
value: "5",
enumerable: false,
});
console.log("打印对象 o1 可枚举的属性名和属性值");
for (prop in o1) {console.log(`${prop}:${o1[prop]}`);
}
//foo:hello x:1 y:2 z:3 a:4
Object.keys(obj)
该办法返回对象 obj 本身蕴含(不包含原型中)的所有可枚举属性的名称数组
const o = {
x: 1,
y: 2,
z: 3,
};
// 对象 o1 继承 o,
const o1 = Object.create(o);
o1.name = "thirteen";
o1.age = 18;
const resultArray = Object.keys(o1);
console.log(resultArray,'打印对象可枚举属性的名称数组');
// [name,age]
// 给对象 o1 新增 a 属性,属性可枚举配置为 true 可能遍历失去
Object.defineProperty(o1, "a", {
value: "4",
enumerable: true,
});
// 给对象 o1 新增 b 属性,属性可枚举配置为 false 不能可能遍历失去
Object.defineProperty(o1, "b", {
value: "5",
enumerable: false,
});
const resultArray1 = Object.keys(o1);
console.log(resultArray1,'打印对象可枚举属性的名称数组');
// [name,age,a]
Object.getOwnPropertyNames(obj)
该办法返回对象 obj 本身蕴含(不包含原型中)的所有属性(无论是否可枚举)的名称的数组。
const o = {
x: 1,
y: 2,
z: 3,
};
const o1 = Object.create(o, {
sex: {
enumerable: false,
value: "男",
},
height: {
enumerable: true,
value: 165,
},
});
o1.name = "thirteen";
o1.age = 18;
const resultArray = Object.getOwnPropertyNames(o1);
console.log(resultArray, "打印对象可枚举属性的名称数组");
// [sex,height,name,age]
// 给对象 o1 新增 a 属性,属性可枚举配置为 true 可能遍历失去
Object.defineProperty(o1, "a", {
value: "4",
enumerable: true,
});
// 给对象 o1 新增 b 属性,属性可枚举配置为 false 不能可能遍历失去
Object.defineProperty(o1, "b", {
value: "5",
enumerable: false,
});
const resultArray1 = Object.getOwnPropertyNames(o1);
console.log(resultArray1, "打印对象可枚举属性的名称数组");
// [sex,height,name,age,a,b]
Object.getOwnPropertySymbols(obj)
返回一个数组,蕴含对象 obj 本身所有 Symbol 属性的键名
const mySymbol = Symbol("mySymbol");
const mySymbol1 = Symbol("mySymbol1");
const mySymbol2 = Symbol("mySymbol2");
const mySymbol3 = Symbol("mySymbol3");
const o = {[mySymbol]: 1,
y: 2,
z: 3,
};
const o1 = Object.create(o, {
sex: {
enumerable: false,
value: "男",
},
height: {
enumerable: true,
value: 165,
},
});
o1.name = "thirteen";
o1.age = 18;
o1[mySymbol1] = "mySymbol1";
const resultArray = Object.getOwnPropertySymbols(o1);
console.log(resultArray, "打印对象 Symbol 属性的键名数组");
// [symbol(mySymbol1)]
// 给对象 o1 新增 a 属性,属性可枚举配置为 true 可能遍历失去
Object.defineProperty(o1, mySymbol2, {
value: "4",
enumerable: true,
});
// 给对象 o1 新增 b 属性,属性可枚举配置为 false 不能可能遍历失去
Object.defineProperty(o1, mySymbol3, {
value: "5",
enumerable: false,
});
const resultArray1 = Object.getOwnPropertySymbols(o1);
console.log(resultArray1, "打印对象 Symbol 属性的键名数组");
// [symbol(mySymbol1),symbol(mySymbol2),symbol(mySymbol3)]
Reflect.ownKeys(obj)
返回一个数组,蕴含对象本身所有键名,不论键名是 Symbol 或字符串,也不论是否可枚举。
const mySymbol = Symbol("mySymbol");
const mySymbol1 = Symbol("mySymbol1");
const mySymbol2 = Symbol("mySymbol2");
const mySymbol3 = Symbol("mySymbol3");
const o = {[mySymbol]: 1,
y: 2,
z: 3,
};
const o1 = Object.create(o, {
sex: {
enumerable: false,
value: "男",
},
height: {
enumerable: true,
value: 165,
},
});
o1.name = "thirteen";
o1.age = 18;
o1[mySymbol1] = "mySymbol1";
const resultArray = Reflect.ownKeys(o1);
console.log(resultArray, "打印对象本身所有属性的键名数组");
// [sex,height,name,age,Symbol(mySymbol1)]
// 给对象 o1 新增 a 属性,属性可枚举配置为 true 可能遍历失去
Object.defineProperty(o1, mySymbol2, {
value: "4",
enumerable: true,
});
// 给对象 o1 新增 b 属性,属性可枚举配置为 false 不能可能遍历失去
Object.defineProperty(o1, "b", {
value: "5",
enumerable: false,
});
const resultArray1 = Reflect.ownKeys(o1);;
console.log(resultArray1, "打印对象 Symbol 属性的键名数组");
// ["sex", "height", "name", "age", "b", Symbol(mySymbol1), Symbol(mySymbol2) ]
属性的个性
除了蕴含名字和值之外,属性还蕴含一些标记他们可写,可枚举和可配置的个性。在 ES3 中无奈设置这些内容,ES5 之后就能够了。属性能够分为『存取器属性』(getter 和 setter 定义的属性)和『数据属性』,不同的属性有不同的个性。
存取器属性
- get // 读取
- set // 写入
- enumerable // 是否能够被枚举(遍历读取)
- configurable // 当且仅当该属性的 configurable 键值为 true 时,该属性的描述符才可能被扭转,同时该属性也能从对应的对象上被删除。
数据属性
- value // 属性值
- writable // 属性是否可写(是否能够批改)
- enumerable // 是否能够被枚举(遍历读取)
- configurable
获取属性的属性形容
通过调用 Object.getOwnPropertyDescriptor 办法能够取得某个对象特定属性的属性形容,例如:
const o = {
x: "我是 X",
y: 2,
z: 3,
};
const o1 = Object.create(o);
o1.age = 18;
Object.defineProperty(o1, "name", {
value: "thirteen",
writable: true,
configurable: true,
enumerable: true,
});
const ageDesc = Object.getOwnPropertyDescriptor(o1, "age");
const nameDesc = Object.getOwnPropertyDescriptor(o1, "name");
const xDesc = Object.getOwnPropertyDescriptor(o1, "x");
//
console.log(ageDesc, "获取自有属性 age 默认的属性形容");
console.log(nameDesc, "获取自有属性 name 配置的属性形容");
console.log(xDesc, "获取继承属性 X 的属性形容");
// 如果想要获取继承的属性的属性形容,须要通过 Object.getPrototypeOf 办法先遍历原型链
const xdesc2 = Object.getOwnPropertyDescriptor(Object.getPrototypeOf(o1),
"x"
);
console.log(xdesc2, "获取继承属性 X 的属性形容");
属性 getter 和 setter
对象的属性是由名字、值和一组个性形成的。在 ES5 之后属性的值能够用一个或两个办法代替,这两个办法就是 getter 和 setter。由 getter 和 setter 定义的属性称作『存取器属性』,不同于『数据属性』,数据属性只有一个简略的值。
当咱们应用 getter 和 setter 定义属性的时候,咱们就能够监听属性的读取和写入动作,比方 VUE 框架当中就应用了 Object.defineProperty 办法重写了 data 对象当中的所有属性,这样当 data 的值产生扭转的时候,就能够更新 vue 当中的模板了;
存取器属性还能够智能查看属性的写入值,以及在属性每次读取的时候返回不同的值;
// 如何定义,第一种
const o1 = {
name: "thirteen",
$age: 18,
get age() {return this.$age;},
set age(v) {this.$age = v;},
};
console.log("第一种返回");
console.log(o1.age); // 18
o1.age = 20;
console.log(o1.age); // 20
// 第二种
const o2 = {$age: 18,};
let ageValue = 18;
Object.defineProperty(o2, "age", {get: function () {return ageValue;},
set: function (value) {ageValue = value;},
});
console.log("第二种返回");
console.log(o2.age); // 18
o2.age = 20;
console.log(o2.age); // 20
// 第三种:当应用 Object.create 办法创建对象的时候
const o3 = Object.create(Object.prototype, {
// foo 会成为所创建对象的数据属性
foo: {
writable: true,
configurable: true,
value: "hello",
},
// bar 会成为所创建对象的拜访器属性
bar: {
configurable: false,
get: function () {return 10;},
set: function (value) {console.log("Setting `o.bar` to", value);
},
},
});
console.log("第三种返回");
console.log(o3.bar); // 10
o3.bar = 20; // 打印『Setting o.bar to 20』// 读取对象属性时,每次返回不同的值
const serialnum = {
$n: 0,
get next() {return this.$n++;},
set next(n) {if (n >= this.$n) this.$n = n;
else throw "序列号的值不能比以后值小";
},
};
console.log("序列号属性返回")
console.log(serialnum.next); // 0
console.log(serialnum.next); // 1
console.log(serialnum.next); // 2
console.log(serialnum.next); // 3
console.log(serialnum.next); // 4
console.log(serialnum.next); // 5
// 每次读取属性都返回一个随机数
const random = {get octet() {
// 返回 0~255 之间的数字
return Math.floor(Math.random() * 256);
},
get uint16() {
// 返回 0~65535 之间的数字
return Math.floor(Math.random() * 65536);
},
get int16() {
// 返回 -32768~(65535-32768)之间的数字
return Math.floor(Math.random() * 65536) - 32768;
},
};
console.log("随机数打印后果")
console.log(random.octet);
console.log(random.octet);
console.log(random.octet);
console.log(random.uint16);
console.log(random.uint16);
console.log(random.uint16);
console.log(random.int16);
console.log(random.int16);
console.log(random.int16);
对象的办法
当咱们通过对象间接量、new Object()和 Object.create()不传入 null 的时候创立的对象,都会和另一个对象关联,『另一个』对象就是咱们熟知的原型,每一个对象都从原型继承属性;
所以当咱们新创建一个对象的同时,对象就有一些办法能够应用,这些办法就是从原型继承的。
toString
返回一个示意调用这个办法的对象值的字符串。
toLocaleString
同 toString 相似,不同的是针对不同类型的对象做了定制解决,比方 Data 和 Number 对象
valueOf
和 toString 相似,经常在 JavaScript 须要将对象转换为某种原始值而非字符串的时候才会调用它。
其它
new Object()
通过构造函数的模式创建对象,new Object()办法可承受一个参数;上面看一些例子:
const o = new Object();
console.log(o,'不传入任何参数');
const o1 = new Object(null);
console.log(o1,'传入 null');
const o2 = new Object(undefined);
console.log(o2,'传入 undefined');
// 相当于 const o3 = new Boolean(true);
const o3 = new Object(true);
console.log(o3,'传入 true');
// 相当于 const o4 = new String("3");
const o4 = new Object("3");
console.log(o4,'传入字符串');
const o5 = new Object(function(){});
console.log(o5,'传入函数');
const o6 = new Object(function(){return [1,2,3]
});
console.log(o6,'传入函数');
// 相当于 const o4 = new Boolean(false);
const o7 = new Object(Boolean());
console.log(o7,'传入对象');
打印后果:
super 关键字
对象当中的 this 指向以后所在的对象,ES6 中新增了一个 super 关键字,super 关键字指向对象的原型对象;
const parent = {name: 'papa'};
const child = {
name: 'child',
say() {return super.name;}
};
// 通过 setProtoTypeOf 设置对象 child 的原型是 parent
Object.setPrototypeOf(child, parent);
child.say() // "papa"
PS:留神,super 关键字示意原型对象时,只能用在对象的办法之中,用在其余中央都会报错。
详情参考:ES6——对象的扩大
更多 JavaScript 对象的扩大内容,参考阮一峰的 ES6 对象的扩大一节