“万物皆对象”。对象是单个事物的抽象;对象是一个容器,封装了属性和方法;属性是对象的状态;方法是对象的行为。
在实际开发中,对象是一个抽象的概念,可以将其简单理解为:数据集或功能集。
一、JavaScript中的对象
面向对象编程——Object Oriented Programming,简称 OOP,是一种编程开发思想。它将真实世界各种复杂的关系,抽象为一个个对象,然后由对象之间的分工与合作,完成对真实世界的模拟。
JavaScript中的编程就是面向对象的编程。而对象就是对生活中对象的一个抽象,是一些无序属性的集合。
其中属性可以包含基本值、对象或函数。对象就是一组没有顺序的值。我们可以把JavaScript中的对象想象成键值对,其中值可以是数据和函数。
二、面向对象基本特性
- 封装性:将对象运行所需的资源(方法和数据)封装在程序对象中。也可以理解把客观事物封装成抽象的类。封装可以隐藏实现细节,使得代码模块化。
- 继承性:通过继承创建的新类称为“子类”或“派生类”。继承的过程,就是从一般到特殊的过程。继承可以扩展已存在的代码模块(类),提高复用,减少冗余。
- 多态性:具体表现为重载和重写。重载就是函数或方法有相同的名称,但参数列表不相同的情形。重写就是子类可继承父类中的方法,而不需要重写编写相同的方法,也可在该方法上做修改。多态可以实现方法的个性化,灵活多变。
三、设计思想
- 抽象出 Class(构造函数)
- 根据 Class(构造函数)创建 Instance(实例)
- 指挥 Instance 得结果
四、创建对象的几种方式
- 原始模式: 即对象字面量。
// 通过对象字面量 创建 一个 对象 var person = { // name 为 属性名;zhangsan 为 属性值 name : 'zhangsan', age : 20, sayHi : function () { console.log(this.name + "向你说您好"); } }; // 更改 数据 person.age = 18; // 添加新数据 person.weight = 120; // 删除 数据 delete person.age;
- new Object() 创建对象:
JavaScript 原始提供 Object对象,JavaScript的素有对象都继承自Object对象,即那些对象都是Object的实例。
Object本身是一个函数,可以当做工具方法使用,将任意值转为对象。此处的 Object() 可以当做构造函数,前面可以使用 new 命令。
new 在这的功能是做了以下事情:
- 在内存中创建了一个新的空对象
- 会让 this 指向这个新的空对象
- 执行构造函数 (目的:给这个新对象加属性和方法)
- 会返回这个新对象
var obj = new Object();
- 工厂模式
如果要创建多个类似的对象,可以将 new Object() 过程封装到一个函数中,将来调用函数就 能创建一个对象,相当于一个生产对象的函数工厂,用来简化代码。
// 创建 函数工厂
function createPerson(name,age) {
var obj = new Object; //或obj = {} 原材料阶段
obj.name = name; // 加工
obj.age = age; // 加工
return obj; // 输出产品
}
// 实例化
var person1 = createPerson("zs","19");
var person2 = createPerson("lisi","20");
- 自定义构造函数
在 JavaScript 中,用 new 关键字来调用的函数,称为构造函数。构造函数首字母一般大写,以便于普通函数进行区分。
自定义一个创建具体对象的构造函数,函数内部不需要new一个构造函数的过程,直接使用this代替对象进行属性和方法的书写,不需要return。
function CreatePerson(name,age) {
//不需要自己创建对象了
this.name = name; //添加属性,this指向构造函数的实例对象
this.age = age;
// 不需要自己 return 了
}
// 实例化
var ps = new CreatePerson("zhangsan","23");
var ps2 = new CreatePerson("lisi", "21");
五、遍历对象
For in 循环。输出每一项的属性名和属性值。
语法:
for(var k in obj) {
console.log(k + “项的属性值是” + obj[k]);
}
六、构造函数的相关内容
1. 构造函数和实例对象的关系
构造函数是根据具体的事物抽象出来的抽象模块。
实例对象是根据抽象的构造函数模块得到的具体实例对象。
每一个实例对象都通过一个 constructor 属性,指向创建该实例的构造函数。
2. 静态成员和实例成员
使用构造函数方法创建对象时,可以给构造函数和创建的实例对象添加属性和方法,这些属性和方法都叫做 成员。
实例成员:在构造函数内部添加给this 的成员,属于实例对象的成员,在创建实例对象后必须由对象调用。
静态成员:添加给构造函数自身的成员,只能使用构造函数调用,不能使用生成的实例对象调用。
//创建一个构造函数
function Person(name, age) {
// 通过 this 添加的 内部属性,就是 实例成员
this.name = name;
this.age = age;
// 构造函数 可能存在的问题
this.type = "human";
this.sayName = function () {
console.log(this.name);
};
}
// 通过 构造函数自身添加的成员 就是 静态成员
Person.version = "1.0";
// 生成 实例对象
var p = new Person("zhangsan", "24");
// 判断一个对象的具体对象类型,需要使用 instanceof 进行判断
console.log(p instanceof Person);
从上段代码中可以了解到 Person 这个构造函数中有个 值不变的实例成员和一个 sayName 方法。每实例化一个对象,对象里面都会有这不变的属性和 方法。就会存在一个浪费内存的问题。引入下一个知识点 Prototype 原型。
七、Prototype 原型
JavaScript 规定,每一个构造函数都有一个 prototype
属性,指向构造函数的原型对象。这个原型对象的所有属性和方法,都会被构造函数的实例对象所拥有。因此我们可以把所有对象实例需要共享的属性和方法直接定义在 prototype
对象上。
构造函数上的 prototype
对象默认都有一个 constructor
属性,指向 prototype
对象所在函数。
通过构造函数得到的实例对象内部会包含一个指向构造函数的 prototype 对象的指针 _proto_(原型链)。
构造函数、实例、原型对象三者之间的关系图
function Person(name, age) {
this.name = name;
this.age = age;
}
//方法写在 原型 里面
Person.prototype.sayName = function () {
console.log(this.name);
}
// 不变的属性 也可以写入 原型里面
Person.type = "human";
//生成 实例对象
var person1 = new Person("zhangsan","25");
var person2 = new Person("lisi","23");
// 这时所有实例的sayName 方法,都是同一个内存地址,指向prototype对象,因此就提高了运行效率。
console.log(person1.sayName === person2.sayName);
八、__proto__
原型链
constructor是属于构造函数的 原型对象的属性。
所有的对象都有一个__proto__
的属性,是一个指针,指向的就是生成实例对象的 构造函数的原型对象 prototype。
__proto__
属性并不是一个标准的属性,是浏览器自己根据语法自动生成的,在实际开发过程中,不会书写该属性,
原型链的查找机制
每当代码读取某个对象的某个属性时,都会执行一次搜索,目标是具有给定名字的属性:
- 首先从对象实例本身开始搜索
- 如果在实例中找到了具有给定名字的属性,则返回该属性的值。
- 如果没有找到,则继续搜索指针指向的原型对象,在原型对象中查找具有给定名字的属性
- 如果原型对象中找到了这个属性,则返回该属性的值。
原型对象使用的建议
在定义构造函数时,可以根据成员的功能不同,分别进行设置。
- 私有成员(一般就是非函数成员)放到构造函数中
- 共享成员(一般就是函数)放到原型对象中
- 如果重置了 prototype ,记得手动将 constructor 的指向正确的构造函数。
function Person(name , age ) {
// 私有成员
this.name = name;
this.age = age;
}
// 公共成员
// 重置 直接使用一个对象字面量对 原型对象进行赋值
Person.prototype = {
constructor : Person, // 需要手动 将 constructor 属性指向正确的构造函数
type : "human",
sayName : function () {
console.log(this.name);
}
}
// 生成实例对象
var person1 = new Person("zhangsan","14");