目录
前言:
创建对象方式二
读取对象
枚举变量属性
区分变量和属性,函数和方法
this初印象
创建对象方式三
创建对象方式四
注意:三个特点
构造函数(new关键字)的执行流程
构造函数的弊端
对象的实例化
instanceof
原型对象
原型对象的作用
检查对象中是否含有某个属性
创建对象方式五
垃圾回收(GC)
前言:
在上一节对象初相识我们学习了使用new Object来创建对象,这是第一种创建方式
适用场景:不太清楚后期添加什么属性和方法
接下来我们将学习其他四种创建方式,其中几种是我们后期更加常用且方便的。
创建对象方式二
利用字面量创建对象
var obj = {};//创建一个空对象 === new Object() var obj2 = { name: "猪八戒", age: 28, gender: "男", sayHi: function () { console.log('方法写法二:匿名函数'); }, say() { console.log("方法写法五:es6简写方法"); }, };适用场景:对象创建时就知道有什么属性和方法
注意:
对象内的属性或者方法我们采取键值对的形式
键:值
属性名:属性值
多个属性或者方法中间用逗号隔开
最后一个属性或者方法逗号可以省略
读取对象
调用对象的属性 对象名.属性名
对象名['属性名']
调用对象的方法 对象名.方法名
//读取对象属性 console.log(obj2.name); console.log(obj2['age']); //读取对象方法 obj.sayHi()枚举变量属性
使用for...in语句
语法:for(var 变量 in 对象){}
作用:对象中有几个属性,循环体就会执行几次
每次执行时,会将对象中的一个属性的名字赋值给变量
var obj = { name: "孙悟空", age: 18, gender: "男", address: "花果山", say() { console.log("老孙来也"); }, }; for (let k in obj) { console.log(obj[k]);//通过变量k读取属性值, []读取变量 } obj.say();区分变量和属性,函数和方法
变量和属性都是用来存储数据的;
变量是单独声明并赋值,使用的时候直接写变量名,是单独存在的;
属性在对象中,不需要使声明,使用时,也是对象.属性,依托对象存在的;
函数和方法都是用来实现某种功能的,可以做某件事,但函数是单独存在的,方法是依托对象存在的
this初印象
解析器在调用函数每次都会向函数内部传递一个隐含的参数,这个隐含的参数就是this,this是参数,浏览器传输的,直接拿来用的,this指向的是一个对象,这个对象我们称为函数执行的上下文对象。
根据函数的调用方式的不同,this会指向不同的对象:
1:当以函数的形式直接调用时,this是window
2:当以方法的形式调用时, 谁调用方法,this就是谁
3:当以构建函数的形式调用时,this就是新创建的那个对象,this就是当前对象,我们找的this就是当前作用域取值范围(后面讲到构造函数时,用到的)
创建对象方式三
使用工厂方法创建对象,通过该方法可以大批量的创建对象
function createPer(name, age) { let per = { //new Object() name: name,//===name age, say() {//new Function(),开辟了一个新的空间,用来放say函数 console.log("hello"); }, }; return per; //返回创建的对象,让函数外部拿到结果 } // 函数外部拿到结果 let per1 = createPer("jack", 18); //在控制台输出 // console.log(per1); let per2 = createPer("tom", 19); //页面写入 // document.writeln(per2); let per3 = createPer("dana", 20); //弹出 let per4=createPer('来福',2) // alert(per3); console.log(per1); console.log(per2); console.log(per3); console.log(per4);问题:
使用工厂方法创建的对象,使用的构造函数都是Object
所以创建的对象都是Object这个类型
就导致我们无法区分多种不同类型的对象
创建对象方式四
利用构造函数来创建对象
构造函数:是一种特殊的函数,主要用来初始化对象,即为对象成员变量赋值初始值,它综合new运算符一起使用。我们可以把对象中一些公共属性和方法抽取出来,然后封装到这个函数里面
构造函数语法规范:
function 构造函数名(){ this.属性=值; this.方法=function(){} } new 构造函数名();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);注意:三个特点
构造函数就是一个普通的函数,创建方式和普通函数没有区别,不同的是构造函数习惯上首字母大写
构造函数和普通函数的区别就是调用方式的不同 ,普通函数是直接调用,构造函数需要使用new关键字来调用
构造函数创建属性和方法,必须结合this使用,此时的this就是新创建的那个对象;
构造函数(new关键字)的执行流程
a:立刻创建一个新的对象
b:将新建的对象设置为函数中this,在构造函数中可以使用this来引用新建的对象
c:逐行执行函数中的代码
d:将新建的对象作为返回值返回
new一个对象时,会在堆中开辟一片区域,new Person()会在堆中开辟一块区域
构造函数的弊端
将函数定义在全局作用域,污染了全局作用域的命名空间而且定义在全局作用域中也很不安全
优化:方法是在构造函数内部创建,也就是构造函数每执行一次就会创建一个新的sayName方法
但所有实例的sayName都是唯一的,这样就导致了构造函数执行一次就会创建一个新的方法,
执行一万次就会创建一万个新的方法而这一万个对象都是一样的,这是没有必要的,完全可以使所有的对象共享同一个方法
对象的实例化
使用同一个构造函数创建的对象,我们称为一类对象,也将一个构造函数称为一个类,例如明星汽车设计图纸
我们将通过一个构造函数创建的对象,称为该类的实例,例如刘德华、某一辆宝马车,
我们利用构造函数创建对象的过程,我们也称为对象的实例化
instanceof
使用instanceof可以检查一个对象是否是一个类的实例
语法:对象 instanceof 构造函数
如果是,则返回true,否则返回false
所有的对象都是Object的后代,
所以任何的对象和我们的instanceof 检查时,都是true
原型对象
我们所创建的每一个函数,解析器都会向函数中添加一个属性prototype,这个属性对应着一个对象,这个对象就是我们所谓的原型对象(prototype是属性名,它的值是一个对象,这个对象叫原型对象),默认情况下,它是一个空对象
如果我们的函数作为普通函数调用,prototype没有任何作用
原型对象的作用
原型对象就相当于一个公共的区域,所有同一个类的实例都可以访问到这个原型对象,我们可以将对象中共有的内容,统一设置到原型对象中,当我们访问对象的一个属性或方法时,它会先在对象自身中寻找,如果有就直接使用,如果没有就去原型对象中寻找,然后使用。
以后我们创建构造函数时,可以将这些对象共有的属性和方法,统一添加到构造函数中,这样就不用分别给每一个对象添加,也不会影响到全局作用域,就可以使每个对象,都具有这样的属性和方法了
/* 需求:创建一个Person类,在原型对象上添加属性a,以及添加一个sayHello方法 */ function Person(name, age) { this.name = name; this.age = age; } Person.prototype.a = 1; // 此时这个sayHello方法,就没有放在全局了,而是放在Person构造函数的原型对象上 Person.prototype.sayHello = function () { console.log("hello"); }; // 实例对象,都可以使用构造函数原型对象上的属性和方法 let per1 = new Person("jack", 18); let per2 = new Person("jack", 18); console.log(per1.a); per1.sayHello();检查对象中是否含有某个属性
in检查某个属性是否属于某个对象时,先在自身找,找不到则会往这个对象的类的原型对象上找,找到也会返回true 这样就会导致有歧义
可以使用对象的hasOwnProperty()来检查对象自身中是否含有该属性,使用该方法只有当对象自身中含有属性时,才会返回true
创建对象方式五
JavaScript 语言中,生成实例对象的传统方法是通过构造函数,
ES6 提供了更接近传统语言的写法,引入了 Class(类)这个概念,作为对象的模板。通过class关键字,可以定义类。(最好用的方式)
// 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();说明:使用class关键词 声明类,constructor为构造方法,constructor()方法,可以接收参数,更新类的静态属性
如果没有显式定义,一个空的constructor()方法会被默认添加,
this关键字则代表实例对象,getstr()为普通方法,不要用es5完整写法,getstr()存在 prototype上。
pn1.constructor === pn1.prototype.constructor // true
垃圾回收(GC)
就像人生活时间长了,会产生垃圾一样,程序运行过程中,也会产生一些垃圾
这些垃圾积攒过多以后,会导致程序运行的速度过慢,所以我们需要一个垃圾回收的机制
来处理程序运行过程中产生的垃圾
当一个对象没有任何的变量或者属性对它进行引用
此时我们将永远无法操作该对象,此时这种对象就是一个垃圾
这种对象过多,会占用我们大量的内存空间,导致我们程序运行变慢
这种垃圾我们必须清理
在JS中拥有自动的垃圾回收机制,会自动将这些垃圾对象从内存中销毁,我们不需要
也不能进行垃圾回收我们需要做的只是将不再使用的对象设置null即可
var obj=new Object(); //对对象进行各种操作 obj.prototype=123; console.log(obj.prototype) obj=null;