目录
1、创建对象方式一
(1)、利用字面量创建对象
对象字面量:就是花括号{}里面包含了表达这个具体事物(对象)的属性和方法
<script>
var obj = {};//创建一个空对象
var obj2 = {
name: "猪八戒",
age: 28,
gender: "男",
sayHi: function () {
console.log('hi~');
}
};
</script>
注意:
对象内的属性或者方法我们采取健值对的形式,
键:值
属性名:属性值
多个属性或者方法中间用逗号隔开,最后一个属性或者方法逗号可以省略
方法冒号后跟的是一个匿名函数
读取对象
调用对象的属性对象名.属性名
对象名['属性名']
调用对象的方法对象名.方法名
<script>
//读取对象属性
console.log(obj2.name);
console.log(obj2['age']);
//读取对象方法
obj.sayHi()
</script>
(2)、对象的方法
函数也可以成为对象的属性,如果一个函数作为一个对象的属性保存,那么我们称这个函数是这个对象(obj)的方法,调用函数就说调用对象(obj)的方法(method), 但是他只是名称上的区别,跟函数没有其他的区别
<script>
/* 创建对象一*/
var obj=new Object();
//向对象中添加属性
obj.name="孙悟空";
obj.age=18;
//对象的属性值可以是任何的数据类型,也可以是个函数
obj.sayName=function(){
console.log(obj.name);
};
console.log(obj.sayName);//打印函数属性
obj.sayName();//调用obj.sayName()函数。也叫调用obj的sayName方法
/* 创建对象二 */
// function sayHi(){
// console.log('hallo')
// }
var obj2={
name:'小明',
age:18,
sex:'男',
job:123,
// 第一种写法
// sayHi:sayHi,
// 第二种写法
// sayHi:function(){
// console.log(obj2.name)
// }
// 第三种写法es6
sayHi(){
console.log('hallo')
}
};
console.log(obj2.name)
console.log(obj2['sex'])
console.log(obj2.sayHi)
obj2.sayHi()
</script>
(3)、枚举(遍历)对象属性
使用for...in 语句
语法:
for(var 变量 in 对象){ }
for...in语句 对象中有几个属性,循环体就会执行几次,每次执行时,会将对象中的一个属性的名字赋值给 变量
<script>
var obj={
name:"孙悟空",
age:18,
gender:"男",
address:"花果山"
};
console.log(obj.name)
for(var n in obj){
console.log('属性名:'+n)//对象中每个属性的名字赋值给n
console.log('属性值:'+obj[n]);//通过变量n读取属性值, []读取变量
}
</script>
(4)、区分变量和属性,函数和方法
变量和属性都是用来存储数据的;
变量是单独声明并赋值,使用的时候直接写变量名,是单独存在的;
属性在对象中,不需要使声明,使用时,也是对象.属性,依托对象存在的;
函数和方法都是用来实现某种功能的,可以做某件事,但函数是单独存在的,方法是依托对象存在的
(5)、this的初印象
解析器在调用函数每次都会向函数内部传递一个隐含的参数,这个隐含的参数就是this,this是参数,浏览器传输的,直接拿来用的,this指向的是一个对象,这个对象我们称为函数执行的上下文对象。
根据函数的调用方式的不同,this会指向不同的对象:
1:当以函数的形式调用时,this是window
2:当以方法的形式调用时, 谁调用方法,this就是谁
3:当以构建函数的形式调用时,this就是新创建的那个对象,this就是当前对象,我们找的this就是当前作用域取值范围(后面讲到构造函数时,用到的)
<script>
//需求:可以输出各自obj的名字
//创建一个fun()函数
function fun() {
console.log(this.name);
}
//创建两个对象
var obj = {
name: "孙悟空",
sayName: fun,
};
var obj2 = {
name: "沙和尚",
sayName: fun,
};
var name = "全局的name属性";
fun(); //==window.fun() 以函数的形式调用,this就是window
obj.sayName(); //孙悟空 以方法的形式调用,this是调用方法的对象
obj2.sayName(); //沙和尚
</script>
2、创建对象方式二
使用工厂方法创建对象,通过该方法可以大批量的创建对象
<script>
//需求:创建一个对象
var obj = {
name: "孙悟空",
age: 18,
gender: "男",
sayName: function () {
alert(this.name);
},
};
/* 需求:批量的创建对象
使用工厂方法创建对象
*/
function createPerson(name,age,gender){
//创建一个新的对象
var obj=new Object();
//向对象中添加属性
obj.name=name;
obj.age=age;
obj.gender=gender;
obj.sayName=function(){
alert(this.name);
};
//将新的对象返回
return obj;
}
var obj2=createPerson("猪八戒",28,"男");
var obj3=createPerson("沙和尚",38,"男");
var obj4=createPerson("白骨精",18,"女");
</script>
问题:
使用工厂方法创建的对象,使用的构造函数都是Object
所以创建的对象都是Object这个类型
就导致我们无法区分多种不同类型的对象
3、创建对象方式三
(1)、利用构造函数创建对象
构造函数:是一种特殊的函数,主要用来初始化对象,即为对象成员变量赋值初始值,它综合new运算符一起使用。我们可以把对象中一些公共属性和方法抽取出来,然后封装到这个函数里面
构造函数语法规范:
function 构造函数名(){
this.属性=值;
this.方法=function(){}
}
new 构造函数名();
<script>
function Person(name, age, gender) {
//alert(this);//this就是新建的对象,然后赋值给per
this.name = name;
this.age = age;
this.gender = gender;
this.sayName = function () {
alert(this.name)
};
}
var per = new Person("孙悟空", 18, "男");
var per2 = new Person("玉兔精", 16, "女");
var per3 = new Person("沙和尚", 28, "男");
console.log(per);
console.log(per2);
console.log(per3);
</script>
注意:
构造函数就是一个普通的函数,创建方式和普通函数没有区别,不同的是构造函数习惯上首字母大写
构造函数和普通函数的区别就是调用方式的不同,普通函数是直接调用,构造函数需要使用new关键字来调用
构造函数创建属性和方法,必须结合this使用,此时的this就是新创建的那个对象;
(2)、构造函数(new关键字)的执行流程:
a:立刻创建一个新的对象
b:将新建的对象设置为函数中this,在构造函数中可以使用this来引用新建的对象
c:逐行执行函数中的代码
d:将新建的对象作为返回值返回
new一个对象时,会在堆中开辟一片区域,new Person()会在堆中开辟一块区域
(3)、对象的实例化
使用同一个构造函数创建的对象,我们称为一类对象,也将一个构造函数称为一个类,例如明星汽车设计图纸
我们将通过一个构造函数创建的对象,称为该类的实例,例如刘德华、某一辆宝马车,
我们利用构造函数创建对象的过程,我们也称为对象的实例化
(4)、instanceof
作用:使用instanceof可以检查一个对象是否是一个类的实例
语法:对象 instanceof 构造函数,如果是,则返回true,否则返回false
注意:所有的对象都是Object的后代,所以任何的对象和我们的instanceof 检查时,都是他的
<script>
console.log(dog instanceof Person);
</script>
(5)、构造函数优化
以上demo,我们创建一个Person构造函数,在Person构造函数中, 为每一个对象都添加了一个sayName的方法
目前我们的方法是在构造函数内部创建的,也就是构造函数每执行一次就会创建一个新的sayName方法,也是所有实例的sayName都是唯一的,这样就导致了构造函数执行一次就会创建一个新的方法,执行一万次就会创建一万个新的方法,而这一万个对象都是一样的,这是没有必要的,完全可以使所有的对象共享同一个方法
<script>
function Person(name,age,gender){
this.name=name;
this.age=age;
this.gender=gender;
// 向对象中添加一个方法
this.sayNam=fun;
}
//将sayName方法在全局作用域中定义
function fun(){
alert("hello大家好,我是"+this.name);
};
//创建一个Person实例
var per=new Person("孙悟空",18,"男");
var per2=new Person("猪八戒",28,"男");
per.sayNam();//孙悟空
per2.sayNam();//猪八戒
console.log(per.sayNam==per2.sayNam);//true
</script>
注意:以上优化也有一定的问题,如将函数定义在全局作用域,污染了全局作用域的命名空间
而且定义在全局作用域中也很不安全
案例:
创建一个电脑对象,该对象要有颜色、重量、品牌、型号、可以看电影,听音乐、打游戏、敲代码
<script>
// 创建一个电脑对象
var computer = {
color: '黑色',
weight: '2.5kg',
brand: '联想',
model: 'ThinkPad T480',
// 看电影的方法
watchMovie: function() {
console.log('正在播放电影...');
},
// 听音乐的方法
listenMusic: function() {
console.log('正在播放音乐...');
},
// 打游戏的方法
playGame: function() {
console.log('正在玩游戏...');
}
};
// 使用电脑看电影
computer.watchMovie();
// 使用电脑听音乐
computer.listenMusic();
// 使用电脑打游戏
computer.playGame();
</script>
4、原型对象
(1)、 原型对象定义
我们所创建的每一个函数,解析器都会向函数中添加一个属性prototype,这个属性对应着一个对象,这个对象就是我们所谓的原型对象(prototype是属性名,它的值是一个对象,这个对象叫原型对象),默认情况下,它是一个空对象
如果我们的函数作为普通函数调用,prototype没有任何作用,
当函数以构造函数的形式调用时,它所创建的对象都会有一个隐含的属性,指向该构造函数的原型对象,我们通过__proto__来访问该属性
(2)、原型对象的作用
原型对象就相当于一个公共的区域,所有同一个类的实例都可以访问到这个原型对象,我们可以将对象中共有的内容,统一设置到原型对象中,当我们访问对象的一个属性或方法时,它会先在对象自身中寻找,如果有就直接使用,如果没有就去原型对象中寻找,然后使用。
以后我们创建构造函数时,可以将这些对象共有的属性和方法,统一添加到构造函数中,这样就不用分别给每一个对象添加,也不会影响到全局作用域,就可以使每个对象,都具有这样的属性和方法了
<script>
//创建函数
function MyClass() {}
//向MyClass的原型对象中添加属性a
MyClass.prototype.a = 123;
//向MyClass中添加一个方法
MyClass.prototype.sayHello = function () {
alert("hello");
};
//console.log(MyClass.prototype, );
//添加实例
var mc = new MyClass(); //隐含属性__proto__
var mc2 = new MyClass();
console.log(MyClass.prototype,"MyClass.prototype");//object
console.log(mc.__proto__,'mc.__proto__');//object
// console.log(MyClass.prototype==mc.__proto__);//true
// mc.sayHello();
/*简单理解:
MyClass 是mc,mc2的祖先,祖先有一个宝藏,里面放一些宝藏,
它的后代都可以看到,如果后代本身就有这个宝藏,就不用祖先藏宝库里,没有就用
*/
</script>
(3)、检查对象中是否含有某个属性
a:使用in检查对象中是否含有某个属性时,如果对象中没有,原型中有,也会返回true
b:可以使用对象的hasOwnproperty()来检查对象自身中是否含有该属性,使用该方法只有当对象自身中含有属性时,才会返回true
<script>
/* 创建一个构造函数 */
function MyClass() {}
//向MyClass的原型中添加一个name属性
MyClass.prototype.name = "我是原型中的name";
var mc = new MyClass();
mc.age = 18;
console.log(mc.name);
console.log("name" in mc); //true
console.log(mc.hasOwnProperty("name")); //false
</script>
(4)、 原型链
原型对象也是对象,所以它也有原型
当我们使用一个对象的属性或方法时,会先在自身中寻找,自身中如果有,则直接使用,如果没有,则去原型对象中寻找,如果原型对象中有,则使用,如果没有,则去原型对象的原型中寻找,直到找到Object对象的原型,Object对象的原型没有原型,如果在Object中依然没有找到,则返回undefined
(具体在js高级的时候讲述)
<script>
/* toString是属于Object原型上的一个方法。
toString返回 '[object type]' 其中type是对象的类型,type的值可以是Object, */
var obj = { sex: "男" };
console.log(obj.toString());// [object Object]
//返回来的确实是返回一个【表示对象】的【字符串】
</script>
5、垃圾回收
就像人生活时间长了,会产生垃圾一样,程序运行过程中,也会产生一些垃圾,这些垃圾积攒过多以后,会导致程序运行的速度过慢,所以我们需要一个垃圾回收的机制,来处理程序运行过程中产生的垃圾
当一个对象没有任何的变量或者属性对它进行引用,此时我们将永远无法操作该对象,此时这种对象就是一个垃圾这种对象过多,会占用我们大量的内存空间,导致我们程序运行变慢,这种垃圾我们必须清理
在JS中拥有自动的垃圾回收机制,会自动将这些垃圾对象从内存中销毁,我们不需要也不能进行垃圾回收
我们需要做的只是将不再使用的对象设置null即可
<script>
var obj=new Object();
//对对象进行各种操作
obj.prototype=123;
console.log(obj.prototype)
obj=null;
</script>
6、创建对象方式四 class
JavaScript 语言中,生成实例对象的传统方法是通过构造函数,
ES6 提供了更接近传统语言的写法,引入了 Class(类)这个概念,作为对象的模板。通过class关键字,可以定义类。
class初体验
<script>
// //es5通过构造函数实现
// function PersonO(username, password) {
// this.username = username;
// this.password = password;
// }
// // 添加方法
// PersonO.prototype.getstr = function () {
// console.log("用户名:" + this.username + ",密码:" + this.password);
// };
// // 实例化对象
// const po1 = new PersonO("章三", "abc123");
// console.log(po1);
// po1.getstr();
// es6实现 class方法实现
class PersonN {
//构造方法 constructor名字不能修改
// 当我们new实例对象的时候,这个方法自动执行
constructor(username, password) {
this.username = username;
this.password = password;
}
//方法必须使用该语法, 不能使用 ES5 的对象完整形式
getstr() {
console.log("用户名:" + this.username + ",密码:" + this.password);
}
//ES5 的对象完整形式 报错
// getstr:function () {}
}
const pn1 = new PersonN("123456", "789012");
pn1.getstr();
</script>
说明:使用class关键词 声明类,constructor为构造方法,一个类必须有constructor()方法,
如果没有显式定义,一个空的constructor()方法会被默认添加,
this关键字则代表实例对象,getstr()为普通方法,不要用es5完整写法,getstr()存在 prototype上。
pn1.constructor === pn1.prototype.constructor // true