Javascript对象
1.创建对象
创建一个新的对象可以用对象字面值(对象初始化器),即大括号来创建,里面定义一系列的键值对key:value
用来描述对象的属性,多个键值对(属性)之间用逗号分隔开。例如创建一个员工对象:
var employee = {
name:"张三", //姓名叫张三
position:"前端工程师", //职位是前端工程师
signIn:function (){ //创建一个打卡上班的行为
console.log("张三打卡上班");
}
}
console.log(employee);
另外一种方法是先创建一个空的对象,然后再进行属性的赋值:
var employee2 = new Object(); //创建一个空的对象
employee2.name = "李四"; //进行属性的赋值
employee2.signIn = function () {
console.log("李四打卡上班");
}
console.log(employee2);
2.对象属性
每一个对象定义时候的键值对都是这个对象的属性,它可以是任何形式的数据,字符串,数字,数组甚至是对象。
获取某个对象的属性值用对象名.属性名
或者对象名["属性名"]
的方式来获取。例如:
console.log(employee.name);
console.log(employee["name"]);
修改某个对象的某个属性的话直接用赋值语句:对象名.属性名 = xxx;
或者对象名["属性名"] = xxx;
即可。
employee.name = "王五";
employee["name"] = "王五";
同样的想要给对象添加属性的话也可以直接用上面的方法进行赋值。
属性名(name,position等等)不能出现-
,例如:birth-date
这样的格式是不允许的,必须加上双引号"birth-date"
,当然在后面访问该属性的时候就不能用对象名.属性名
的格式来访问了,必须用对象名["属性名"]
。
var employee3 = {
"birth-date":"1999-01-01"; //属性名中出现-时属性名必须加引号
birth-date:"1999-01-01";
}
如果要避免这种情况,可以用驼峰命名法:当有两个单词拼接组成的变量名时,第二个单词首字母大写(例如birthDate)。
3.省略key
当对象的属性的值是一个变量,并且属性名和变量名相同时就可以将属性名(键key)省略。例如:
var name = "小徐";
var employee3 = {
name:name, //这里可以简写成一个name
signIn() { //还可以在对象内部直接写函数体作为属性
console.log("小徐打卡");
}
};
console.log(employee3.name); //输出结果小徐
4.遍历对象属性
遍历对象属性有两种方式:
Object.keys()
var employee = {
name:"张三",
position:"前端工程师",
signIn:function (){
console.log("张三打卡上班");
}
}
console.log(Object.keys(employee)); //获取到employee的全部属性名(数组形式),不是值
2. for循环
for(key in employee) {
console.log(key);
}
5.删除对象属性
删除对象的某个属性可以用delete
关键字,语句格式为:
delete employee.name //删除employee对象的name属性
6.构造函数
使用构造函数是创建对象的另一种方式,与之前两种创建对象的方法的不同之处在于它可以事先确定好对象有哪几种属性,然后在使用new
关键字创建一个对象的同时将属性赋值进去。
function Employee(name,position) { //构造函数
this.name = name; //这里的this指的就是下面的emp1,emp2实例本身
this.position = position;
}
var emp1 = new Employee("张三","前端工程师");
console.log(emp1);
var emp2 = new Employee("李四","后端工程师");
console.log(emp2);
7.this
var emp3 = {
name:"李四",
position:"后端工程师",
signIn() {
console.log(this.name + "上班打卡");
}
}
emp3.signIn(); //输出结果李四上班打卡
emp3.gotoWork = function() { //在外部新增加对象的函数也能用this指向
console.log(this.name + "去上班");
};
emp3.gotoWork(); //输出结果李四去上班
但是如果将一般的函数改成箭头函数,this
指向的就不是对应的实例了,而是window对象:
emp3.gotoWork = () => {
console.log(this.name + "去上班"); //无法正确输出
};
要想使用箭头函数的话,需要在构造函数中定义函数才能取到this.name
:
function Employee(name,position) {
this.name = name;
this.position = position;
this.signIn = () => {
console.log(this.name + "去上班");
}
}
8.对象getters和setters
getters
和setters
的作用是利用关键字get
和set
来获取到对象的属性以及设置对象的属性。
var person = {
firstName:"三",
lastName:"张",
get fullName() { //利用get关键字来获取到对象的全名
return this.lastName + this.firstName;
},
set fullName(fullName) { //利用set关键字来设置对象的firstName和lastName属性,注意参数只能是一个
let [lastName,firstName] = fullName.split(","); //利用split将参数的姓和名进行解构
this.lastName = lastName; //分别重新设置对象的姓和名等属性
this.firstName = firstName;
}
}
console.log(person.fullName);
person.fullName = "李,四";
console.log(person.fullName);
console.log(person.lastName,person.firstName);
上面是用字面值来直接创建的对象,如果是在构造器里面创造的对象,用Object.defineProperty()
来创建set
和get
:
function Employee2(name,position) {
this.name = name;
this.position = position;
}
var emp5 = new Employee2("赵六","前端工程师");
Object.defineProperty(emp5,"info", { //第一个参数是对象,第二个参数是get和set方法的属性
get:function() {
return this.name + " " + this.position;
},
set:function (info) {
let [name,position] = info.split(" ");
this.name = name;
this.position = position;
}
});
console.log(emp5.info);
emp5.info = "赵云 后端工程师";
console.log(emp5.name);
console.log(emp5.position);
9.对象原型
在利用构造函数创建对象时,通过new来创建一个新的实例对象就是根据构造函数中的对象原型来创建的。
function Employee(name,position) {
this.name = name;
this.position = position;
this.signIn = function() {
console.log(this.name + "打卡");
};
}
var emp1 = new Employee("张三","前端工程师"); //创建两个对象实例
var emp2 = new Employee("李四","后端工程师");
console.log(emp1);
console.log(emp2);
console.log(Employee.prototype); //原型
Employee.prototype.age = 18; //在对象原型中添加一个age属性,在这个原型下的全部对象都会继承到这个age属性
console.log(emp1.age); //输出结果18
console.log(emp2.age); //输出结果18
Employee.prototype.printInfo = function() { //在构造器原型中新添加一个属性printInfo
console.log(this.name,this.age,this.position);
};
emp1.printInfo(); //原型下的全部对象都能继承到这个属性并执行
emp2.printInfo();
console.log(emp1.__proto__); //查看某个对象的原型使用对象名.__proto__
console.log(Employee.prototype); //查看构造器的原型
console.log(emp1.__proto__ === Employee.prototype); //输出结果true
console.log(Object.getPrototypeOf(emp2)); //这是另外一种获取对象原型的方法
10.对象object.create()
object.create()
方法用于在一个已知对象的基础上再创键一个对象(其实就是父子对象),子对象会继承父对象的全部属性,并且子对象还可以有自己的一些特殊属性。
function Employee(name,position) {
this.name = name;
this.position = position;
this.signIn = function() {
console.log(this.name + "打卡");
};
}
var emp1 = new Employee("张三","前端工程师");
var emp2 = new Employee("李四","后端工程师");
for(key in emp1) { //遍历查看对象emp1的全部属性名
console.log(key);
}
var manager = Object.create(emp1); //创建一个新对象manager继承emp1
console.log(manager);
for(key in manager) {
console.log(key); //对象manager的属性名应该和emp1的属性名全部一致
}
console.log(manager.name); //输出结果张三,继承下来的属性名
manager.name = "经理"; //重新设置manager的name属性的值
manager.position = "经理职位"; //重新设置manager的position属性的值
console.log(manager);
manager.signIn(); //方法也能继承
console.log(Object.getOwnPropertyNames(manager)); //可以获取到manager相比于父对象的新的属性
11.原型链
原型链就是指某个对象的原型是另一个对象(就相当于父子关系),当存在许多对象有一层一层的原型关系时就形成了原型链(跟串葡萄一样)。在Javascript中的最顶层对象是Object
,它的原型是Object.Prototype
,它的原型的原型就是null
,这就是原型链的顶端。
var protoOfManager = Object.getPrototypeOf(manager); //获取manager对象的原型的方法
console.log(protoOfManager); //输出emp1,因为manager就是在emp1的基础上生成的,所以他的原型就是emp1
var protoOfemp1 = Object.getPrototypeOf(protoOfManager); //这里就相当于找manager原型的原型
console.log(protoOfemp1); //这里能得到创建对象emp1时的构造函数
var protoOfemp = Object.getPrototypeOf(protoOfemp1); //再往上找一层原型(即构造函数的原型)
console.log(protoOfemp);
var protoOfobj= Object.getPrototypeOf(protoOfemp); //再往上找一层原型
console.log(protoOfobj); //到达了原型链的顶端,NULL
概括来说就是manager
的原型是emp1
,
因为之前在申明的时候:
var manager = Object.create(emp1);
emp1
的原型是emp1
的构造函数,emp1
的构造函数的原型是Object的构造函数
,最后Object的构造函数
的原型是null
。即console.log(Object.getPrototypeOf(Object.prototype));
输出也为null
。
Object
所有的一些方法会传到最底层也就是manager
中。例如toString
:
console.log(manager.toString);
console.log(manager.toString());
12.修改原型指向
function Manager() {
}
Manager.prototype.department = "技术部"; //自定义prototype.department属性
Object.setPrototypeOf(manager,Manager.prototype); //将自定义的属性赋值给manager对象
console.log(manager.department);
console.log(Object.getPrototypeOf(manager)); //在manager对象的原型中就有了department属性
for(key in manager) {
console.log(key);
}
增加完属性之后,manager
的原型就不再是emp1
了,因为多了一个属性department
。
13.spread操作符
Spread操作符...
用于将某个对象的全部属性复制到另一个对象中。当然也可以自己新增属性。另外主要作用就是将一个数组转为用逗号分隔的参数序列(就是将一个数组拆开成单个参数传入函数)。
var post = { //定义一个对象post
id: 1,
title: "标题1",
content: "这是内容"
};
console.log(post);
var postClone = {...post}; //将post对象中的全部属性复制到对象postClone中
console.log(postClone);
console.log(post === postClone); //注意,post和postClone虽然属性及值一模一样但是内存地址不同它们不是同一个对象,因此这里会输出false
var post2 = {
...post,
author: "小明" //也可以自己新增属性
};
console.log(post2);
var arr = [1,2,3]; //不仅仅是对象,数组也适用
var arrClone = [...arr];
console.log(arrClone); //输出[1,2,3]
var arr2 = [...arr,4,5,6];
console.log(arr2); //输出[1,2,3,4,5,6]
function savePost(id,title,content) {
console.log("保存了文章",id,title,content);
}
savePost(...[2,"标题","内容"]); //这里就是将数组[2,"标题","内容"]中的值拆分成单个参数传入函数中
复制属性,拆分数组参数
14.destructuring和rest
destructuring
解构操作,rest
取位符:
var post = {
id: 1,
title: "标题1",
content: "这是内容"
};
var {id,title} = post;
console.log(id,title); //输出1,"标题1"
var {id:article_id,title:article_title} = post; //使用自定义名称
console.log(article_id,article_title); //输出1,"标题1",仅仅变换了变量名
var {id,title,comments = "没有评论"} = post; //定义默认值
console.log(comments); //输出没有评论
var [a,b = 2] = [1]; //数组也可以设置默认值
console.log(a,b); //输出1,2
var post2 = {
id: 2,
title: "标题2",
content: "这是内容2",
comments: [
{
userid: 1,
comment: "评论1"
},
{
userid: 2,
comment: "评论2"
},
{
userid: 3,
comment: "评论3"
}
]
};
var {
comments:[,{comment}] //获取第二个对象的comments属性中的第二个comment属性值
} = post2;
console.log(comment); //输出评论2
function getId(idKey,obj) { //获取某个对象的id,对象是变化,不确定的
let {[idKey]: id} = obj; //因此解构的key值也是不确定的,用[]包括
return id;
}
console.log(getId("userid",{userid:3})) //输出3
var { comments, ...rest } = post2; //将除了comments外的其它属性存放在rest中
console.log(rest); //输出id,title,content的值
function savePostObj({id,title,content,...rest}) { //rest操作符还能当作函数参数来进行使用,用来接收剩余全部参数
console.log("保存了文章",id,title,content);
console.log(rest); //输出结果小明
}
savePostObj({id:4,title:"这是标题",content:"这是内容",author:"小明"});
15.值传递和引用传递
在Javascript中,array
数组或者Object
对象类型的数据作为函数参数时是用引用传递的,即依赖内存地址。即如果在外部定义数据并传入函数进行了修改,就等于外部数据被修改了。而值传递仅仅是将变量的值传入函数,相当于拷贝了一份数据,原数据并不会被修改。
function byReference(arr) {
arr[0] = 5;
}
var array = [1,2,3,4,5];
byReference(array);
console.log(array); //输出[5,2,3,4,5]
function byReferenceObj(obj) {
obj.title="修改后的标题";
}
var post = {
id:1,
title:"原标题"
}
byReferenceObj(post);
console.log(post); //输出{id: 1, title: "修改后的标题"}
function byReferenceStr(str) {
str = "abcd"; //在内部又申明了一个新地址的str
}
var test = "test";
byReferenceStr(test);
console.log(test); //输出仍然是test
function byValue(num) { //这里是按值传递仅仅是将值传递了进来,相当于拷贝了一份数据
num = 10;
console.log(num); //输出10
}
var testNum = 1;
byValue(testNum);
console.log(testNum); //输出1
16.call,apply和bind
call
,apply
和bind
都是用于修改函数的this指向。
var emp = {
id:1,
name:"小明",
printInfo() {
console.log("员工姓名:" + this.name); //这里的this指向的是对象emp
},
department: {
name:"技术部",
printInfo() {
console.log("部门名称:" + this.name); //这里的this指向的是对象emp的属性department
}
}
}
emp.printInfo(); //输出员工姓名:小明
emp.department.printInfo(); //输出部门名称:技术部
如果是在对象外部定义的一个printInfo()
方法,直接调用的话是无法输出name
值的。
var emp = {
id:1,
name:"小明"
}
function printInfo() {
console.log("员工姓名:" + this.name); //因为这个方法定义在外部,这里的this指向的是全局windows对象,但是windows对象没有name属性
}
printInfo(); //输出员工姓名: 无法输出name
call()方法
var emp = {
id:1,
name:"小明"
}
function printInfo(dep1,dep2,dep3) {
console.log("员工姓名:" + this.name,dep1 ,dep2 ,dep3);
}
printInfo();
printInfo.call(emp,"技术部","办公部","保卫部"); //通过call将printInfo的this绑定到emp对象上,绑定完之后会调用该方法。如果需要传递参数,直接在后面加上,但是只能单独传。
apply()方法
apply()
与call()
的区别就是apply()
在传递参数的时候可以以数组形式一起传入。
printInfo.apply(emp,["技术部","办公部","保卫部"])
bind()方法
bind()
的不同之处是它会返回一个修改了this
指向后的新函数,并且不会立即调用。
printInfo.bind(emp,"技术部","办公部","保卫部");
需要显示结果的话:
var empprintInfo = printInfo.bind(emp,"技术部","办公部","保卫部");
empprintInfo();