什么是对象:
JavaScript 中的所有事物都是对象:字符串、数字、数组、日期,等等。
在 JavaScript 中,对象是拥有属性和方法的数据。
对象Object:
- 在JS中有这样一句话,万物皆为对象,这也是我们以后的学习重点,以后我们所学的东西全部都是对象
- 对象不等于对象 ,不同于变量,两个对象的内容即便一模一样,他们也不相等,这其中涉及到一个内存问题,没创建一个对象,它就会在堆内存中开辟一个新的空间,拥有新的内存地址,所以每个对象的内存地址不同,他们就不相等
var a = 10;
var b = 10;
console.log(a === b);//输出true,表示即便是在严格模式下,他们也是相等的
//我们在来看一下对象
var obj1 = {name:"名字",age:18};
var obj2 = {name:"名字",age:18};
console.log(obj1 == obj2);//输出false,他们是不相等的,即使内容一致
对象的基本结构和操作:
对象其实也是用来保存数据的,它可以保存很多东西,不知道你现在还记不记得?在学习函数的时候我们曾经说过,函数也是对象,它和数组类似,但不同的是,它内部的每一个值都被单独的属性名所保存,我们来看一下:
//这其实也是构造函数创建,只不过Object是JS原生的构造函数
//我们声明一个变量也就是对象名来保存创建的对象,注意,在创建对象时需要 new
var obj = new Object();
//那么对象是怎么保存数据的呢?,我们用属性来保存
obj.name = "我的名字";
obj.age = "我的年龄";
//就这样,对象可以无限的创建保存属性,它怎么获取属性呢?
console.name( obj.name );//输出结果是 我的名字
//作为你的对象,她的心里当然要有你,不能光想着自己,下面我们把它保存的名字变成你的名字
obj.name = "你的名字";
console.log( obj.name )//你看,她心里有你了
//我们在上面已经使用了对象的 添加、获取、和修改,那么对象的属性能不能删除呢
delete obj.name; //我不爱你了,我们分手吧
console.log(obj.name);//输出undefined,果然没有了
下面我们来总结一下对象的常规操作:
-
声明一个对象:
var 对象名 = new Object;
- 给对象添加属性:
对象名.属性名 = 属性值;
-
获取对象保存的一个值:
对象名.属性名;
-
修改对象的一个属性的值:
对象名.属性名 = 新值;
-
删除对象的一个属性:
delete 对象名.属性名
对象属性的引用:
对象的属性的两种引用方法:
- 对象名.属性名 如:obj.name
- 对象名["属性名"] 如:obj["name"]
注意: 中括号里写的是一个字符串,所以才需要用引号包裹起来
对象的简写:
是不是觉得上面创建对象有点麻烦呢?没错,像函数一样,创建对象也有一种简化的方法:
var obj = {
name:"你的名字",
//这种简化的对象属性名前不用加对象名
age:"你的年龄",
//注意如果这个属性不是最后一个,要以逗号结尾,最后一个可以不加
//对象里可以保存任何东西,也可以是一个函数,这种被作为对象属性调用的函数被称为方法
myName:function(){
console.log(this.name);
}
//this也是一个小重点,它可以代表当前调用它的对象,即谁调用它它就是谁,
};//注意分号结尾
我们在来总结一下这种字面量创建方法:
- 不再需要new,而是将属性都放在花括号内:
var 对象名 = { 属性:值 };
- 属性名前不再需要对象名,等号改为冒号 : 代码后面的分号改成逗号
- 对象的属性可以存放任何数据,用任何方法创建的对象都是如此
当然,里面有一个关键字:this
,这个关键字可以让我们灵活的对对象进行设置,而不必担心把里面的某些数据写死上面的 this
是obj
For/In循环:
既然了解是什么是对象,那再让我们回顾之前说过的一个循环类型:for/in循环
之前说过,for/in循环可以遍历对象的属性我们来试一下:
//首先创建一个对象,
var obj = {
name:"名字",
age:18,
gender:"男"
};
//创建一个for/in循环
for(var i in obj){
console.log(i);
};
//输出结果是:name age gender
通过上面的例子我们可以了解到:
- for/in和for循环的区别在于for/in没有for的三个语句,取而代之的是:
变量 in 对象名
- for/in循环每次执行都会从对象中取出一个对象名,并赋值给变量
i
- 它的循环条件就是对象中的属性个数,当把对象中的属性取完,它就自动停止循环
this是什么:
JavaScript this 关键词指的是它所属的对象。它拥有不同的值,具体取决于它的使用位置:
- 在方法中,this 指的是所有者对象。
- 单独的情况下,this 指的是全局对象。
- 在函数中,this 指的是全局对象。
- 在函数中,严格模式下,this 是 undefined。在事件中,this 指的是接收事件的元素。
this指向问题简单来说就是:
- 函数内部的this指的是函数的调用者,如果是在构造函数中,则指向实例对象。如果是普通函数中,this指的window
- this有一些坑,会非常绕,所以在用的时候应严格按照上面这句话来分析。
更加详细的this的介绍请看这个
结合着实例的this初介绍请看这个
对象的不同创建方法:
当我们因为需要大量创建对象的时候,你是不是已经发现上面那种方法的弊端了?,没错,需要很大的工作量,而他们却又类似,那么有没有一种能够让我们更加高效的办法呢?
使用工厂模式创建对象:
//创建一个函数
function Person(name,age){
//在函数内创建一个对象,注意对象的属性名前应该是this
var obj = new Object;
obj.name = name ;
obj.age = age ;
obj.myName = function (){
console.log(this.name);
};
//然后把对象传给函数
return obj;
}
//现在,来创建我们需要的对象吧,
var obj1 = Person("你的名字",18);
var obj2 = Person("我的名字,"18);
//我们来调用一下myName方法看看
obj1.myName();//结果是 你的名字
obj2.myName();//结果是我的名字
通过这个例子我们可以看到,工厂模式的强大之处,可以让我们快速方便的创建大量的对象而防止了代码重复的问题。
但是,工厂模式有一个弊端,那就是所有的对象都有一个相同的名字,全都是Object不容易识别他们是哪一个对象的
构造函数:
还有一种构造自定义对象的方法,可以创建自定义的构造函数,从而定义自定义对象的属性和方法。使用构造函数的方法,既解决了重复实例化的问题,又解决了对象识别的问题。如下:
//创建一个函数
function Person(name,age){
//直接添加属性,记得前面是this,还记得吗?函数也是对象
this.name = name;
this.age = age;
this.myName = function (){
alert(this.name);
};
};
var obj1 = new Person("你的名字",18);
//通过这种方法创建的对象让你想到什么了?没错,和用Object创建的一样,这就是构造函数
var obj2 = new Person("我的名字",18);
- 通过构造函数创建的对象他们是不同的,比如你可以创建Person的对象,还可以创建Dog的对象
- 通过这种方法创建的对象我们称他们为实例,如:obj1和obj2都是Person的实例
- 按照惯例,构造函数应该以一个大写字母开头,而非构造函数则应该以一个小写字母开头。这不是强制要求的,但遵守惯例是良好的编程习惯
- 创建一个新的实例就是创建了一个新的对象,它会将这个构造函数的作用域和属性都赋与给这个实例,函数中的this也指向这个实例名。
原型对象:
我们创建的每一个函数都含有一个默认的对象:prototype
- prototype是我们构造函数创建的所有实例的原型,所以又叫做原型对象或对象原型、原型模式
- prototype也是对象,它拥有对象的一切功能但他最重要的作用是包含这个构造函数的共享属性和方法
- 原型对象里面创建的属性,由这个构造函数创建的所有实例都可以访问,它里面的内容是公共的
- 对象属性的查找方式: 想要获取一个对象的,某个属性,浏览器会先在它本身寻找,如果找不到就会去它的原型对象里寻找如果再找不到,就会返回undefined,
- 所以,当我们所有的实例都需要有一个相同的属性的时候,写在原型对象里往往是一个不错的选择
//创建一个函数
function Person(name,age){
//直接添加属性,记得前面是this,还记得吗?函数也是对象
this.name = name;
this.age = age;
this.myName = function (){
alert(this.name);
};
};
Person.prototype.love = function (name){
//设置一个型参,将她的名字作为实参传进去
alert("I Love"+name);
};
var obj1 = new Person("你的名字",18);
//通过这种方法创建的对象让你想到什么了?没错,和用Object创建的一样,这就是构造函数
var obj2 = new Person("我的名字",18);
obj.live("你的名字");
可以看到,在构造函数和实例中,我并没有设置live这个属性,可是还是可以使用,因为它在原型对象中找到了这个属性并拿来使用。
constructor
,prototype
和__proto__
:
1、constructor
属性返回对创建此对象的构造函数的引用,即返回对象实例的构造函数
语法:object.constructor
//创建一个构造函数,并创建一个实例
function Fun(name){
this.name=name;
}
var obj = new Fun("名字");
//使用constructor属性访问其构造函数并判断是否相等
console.log(obj.constructor == Fun);
//结果为ture,consturctor的访问结果确实是他的构造函数Fun
2、查找一个对象的原型,我们可以使用关键字 __proto__
//创建一个构造函数并创建一个实例
function Fun(name){
this.name=name;
}
//想要访问一个函数的对象原型可以使用prototype
var obj = new Fun("名字");
//我们来验证一下使用__proto__找到的对象原型是否就是其构造函数的对象原型
console.log(Fun.prototype == obj.__proto__);
//结果为true,__proto__的访问结果确实是其构造函数的对象原型
这里我们要说明一下:
__proto__
,constructor
和prototype
的区别:
-
prototype
是函数独有的,它只可以作为函数的原型对象,也就是说它的前面加的必须是函数名 -
__proto__
和constructor
属性是对象独有的,它的作用是查找对象的原型 - 我们可以用
__proto__
来查找一个对象是否有原型,也可以是实例用它来访问原型中的某个属性 - 当我们在一个实例中查找某个属性的时候,如果找不到,那么它的
__proto__
就会去它的原型中找,如果还找不到,就会去原型的原型中找,如果到最后也找不到,就会返回undefined
console.log(obj1.__proto__);
//查找原型
console.log(obj1.__proto__.__proto__);
//查找原型的原型,若找不到,会返回null
console.log(obj1.__proto__.name);
//若找不到,会返回undefined
注意一点: 找不到属性,返回undefined,找不到原型对象,返回null
总结一下:
-
通过构造函数找对象原型:
obj.prototype
-
通过对象实例找对象原型:
obj.__proto__
-
通过对象实例找构造函数:
obj.constructor
-
构造函数:
Fun
-
对象原型:
Fun.prototype或obj.__proto__
-
对象实例:
var obj = new Fun();
网友评论