前言本文是JavaScript基础系列的第六篇深入讲解对象的方方面面。内容包括对象的四种创建方式new构造函数、对象字面量、工厂函数、构造函数、属性枚举、this指向规则、原型对象与原型链、垃圾回收机制以及ES6的class语法。掌握这些内容你将真正理解JavaScript面向对象编程的精髓。一、对象的创建方式四种1.1 new构造函数创建对象var obj new Object(); obj.name jack; obj.age 18;特点使用new关键字调用的函数称为构造函数专门用来创建对象。1.2 对象字面量创建对象使用花括号{}包含属性和方法适合在定义对象时同时设置属性值。let obj2 { // 完整写法 name: tom, age: 18, gender: 男, // 属性写法二属性名简写ES6 // name, // 等同于 name: name // 方法写法一完整写法 sayHi: function() { console.log(hi); }, // 方法写法二匿名函数提出去 // sayHi: fun, // 方法写法三简写方式ES6 sayHi() { console.log(hi); } };注意属性与方法采用键值对形式属性名: 属性值多个属性或方法中间用逗号隔开最后一个属性或方法后面的逗号可以省略方法冒号后跟的是一个匿名函数1.3 读取对象// 调用对象的属性 obj2.name; // 对象名.属性名 obj2[age]; // 对象名[属性名] // 调用对象的方法 obj2.sayHi(); // 对象名.方法名()1.4 对象方法定义函数作为对象的属性保存时称为这个对象的方法method。let obj {}; obj.sayHi function() { console.log(hi); }; obj.sayHi(); // 调用方法注意方法与函数本质上没有区别只是名称上的区分——方法依托于对象存在。二、对象属性枚举for...in语句var obj { name: 孙悟空, age: 18, gender: 男, address: 花果山 }; for (let key in obj) { console.log(key); // 输出属性名 console.log(obj[key]); // 输出属性值 }特点对象中有几个属性循环体就执行几次每次执行时将对象中的一个属性名赋值给变量key通过obj[key]获取对应的属性值三、变量与属性、函数与方法的区别对比项变量 vs 属性函数 vs 方法存储内容都是用来存储数据都是用来实现功能声明方式变量单独声明属性在对象中无需声明函数单独存在方法是对象的属性使用方式变量直接写变量名属性通过对象.属性名函数直接调用方法通过对象.方法名()四、this关键字4.1 this的本质解析器在调用函数时每次都会向函数内部传递一个隐含的参数——this。this指向的是一个对象称为函数执行的上下文对象。4.2 this的指向规则function fun() { console.log(this.name); } var obj { name: 孙悟空, sayName: fun }; var obj2 { name: 沙和尚, sayName: fun }; fun(); // 1. 函数形式调用this指向window obj.sayName(); // 2. 方法形式调用this指向调用方法的对象obj obj2.sayName(); // 3. this指向obj2this指向总结调用方式this指向函数形式调用window方法形式调用调用方法的那个对象构造函数形式调用新创建的那个对象五、工厂函数创建对象使用工厂方法可以大批量地创建对象。function createObj(name, age) { let obj1 { name: name, age: age, study() { console.log(学习); } }; return obj1; } let p1 createObj(jack, 18); let p2 createObj(tom, 19);问题创建的对象都是Object类型无法区分不同类型的对象比如无法区分人和狗。六、构造函数6.1 构造函数定义构造函数是一种特殊的函数主要用来初始化对象为对象成员变量赋值初始值通常与new运算符一起使用。function Person(name, age) { this.name name; this.age age; this.sayHi function() { console.log(hi); }; } let per1 new Person(jack, 18); let per2 new Person(tom, 18);6.2 构造函数规范规范说明函数名首字母大写便于区分普通函数必须使用new关键字调用否则会污染全局作用域使用this添加属性和方法this指向新创建的对象6.3 构造函数执行流程立即创建一个新对象将新对象设置为函数中的this逐行执行函数中的代码将新对象作为返回值返回6.4 对象的实例化类使用同一个构造函数创建的一类对象如人类实例通过构造函数创建的具体对象如刘德华实例化利用构造函数创建对象的过程6.5 instanceof运算符检查一个对象是否是一个类的实例。console.log(per1 instanceof Person); // true console.log(per1 instanceof Object); // true所有对象都是Object的后代七、构造函数优化7.1 存在的问题每次创建对象时方法都会被重新创建一次造成内存浪费。function Person(name, age) { this.name name; this.age age; this.sayNam function() { // 每次创建都会生成一个新函数 alert(hello大家好我是 this.name); }; }7.2 优化方案将方法提取到全局function Person(name, age, gender) { this.name name; this.age age; this.gender gender; this.sayNam fun; // 所有实例共享同一个方法 } // 将方法定义在全局作用域中 function fun() { alert(hello大家好我是 this.name); } var per new Person(孙悟空, 18, 男); var per2 new Person(猪八戒, 28, 男); per.sayNam(); // 孙悟空 per2.sayNam(); // 猪八戒 console.log(per.sayNam per2.sayNam); // true问题将函数定义在全局作用域会污染全局命名空间也不安全。更好的解决方案使用原型对象。八、原型对象prototype8.1 原型对象的定义每一个函数都有一个属性prototype指向一个对象——原型对象默认情况下原型对象是一个空对象当函数作为构造函数调用时所创建的对象都会有一个隐含属性__proto__指向该构造函数的原型对象function MyClass() {} // 向原型对象添加属性和方法 MyClass.prototype.a 1; MyClass.prototype.study function() { console.log(study); }; let mc new MyClass(); console.log(mc.__proto__ MyClass.prototype); // true8.2 原型对象的作用作用说明公共区域所有同类实例都可访问避免污染全局作用域属性和方法定义在原型上不在全局实现属性和方法共享所有实例共享原型上的属性和方法8.3 属性检测// in运算符会沿着原型链查找 console.log(a in p1); // true原型上有也算 // hasOwnProperty只检测当前对象自身 console.log(p1.hasOwnProperty(a)); // false原型上的不算自身九、垃圾回收GC9.1 什么是垃圾当一个对象没有任何变量或属性对它进行引用时我们就无法再操作该对象这种对象就是垃圾。9.2 JS的垃圾回收机制JS拥有自动的垃圾回收机制会自动将垃圾对象从内存中销毁我们不需要也不能手动进行垃圾回收我们只需要将不再使用的对象设置为nullvar obj new Object(); // 使用对象... obj null; // 标记为垃圾等待回收9.3 面试题null一般什么时候使用场景说明垃圾回收手动将不需要的变量设置为null占位准备放对象但还没想好放什么时先用null占位清除事件可以用来清除事件绑定十、ES6类语法class10.1 class定义类ES6提供了更接近传统语言的写法通过class关键字定义类。class Person { // 构造函数 constructor(name, age, height) { this.name name; this.age age; this.height height; } // 类方法存在prototype上 sayHi() { console.log(hi); } } let p1 new Person(jack, 18, 180);说明使用class关键字声明类constructor()为构造方法可以接收参数初始化实例属性如果没有显式定义一个空的constructor()方法会被默认添加this关键字代表实例对象普通方法如sayHi()存在于prototype上pn1.constructor pn1.prototype.constructor返回true10.2 狗类示例class Dog { constructor(name, age) { this.name name; this.age age; } sayW() { console.log(汪汪); } } let d1 new Dog(来福, 2); d1.sayW(); // 汪汪总结本文系统梳理了JavaScript对象的深入知识主题核心要点对象创建方式new构造函数、对象字面量、工厂函数、构造函数this指向函数调用→window方法调用→调用对象构造函数→新对象构造函数首字母大写、new调用、this添加属性、四步执行流程原型对象公共区域、共享属性和方法、避免污染全局垃圾回收自动回收、将无用对象设为nullES6 classconstructor构造方法、方法写在prototype上掌握这些内容你就真正理解了JavaScript面向对象编程的核心思想。