文章目录
前言
这部分学习一下面向对象编程思想,面向对象编程会使编程更加高效。
面向对象概念
1.对象
在实际开发中,对象是一个抽象的概念,可以将其简单理解为:数据集或功能集。
ECMAScript-262把对象定义为:无序属性的集合,其属性可以包含基本值、对象或者函数。
2.面向对象
面向对象编程——0bject Oriented Programming,简称 0OP,是一种编程开发思想。
它将真实世界各种复杂的关系,抽象为一个个对象,然后由对象之间的分工与合作,完成对真实世界的模拟。
面向对象特性:封装性、继承性、(多态性)抽象
面向对象优点:面向对象编程具有灵活、代码可复用、高度模块化等特点,容易维护和开发,比起由一系列函数或指令组成的传统的过程式编程,更适合多人合作的大型软件项目。
接下来两段代码初步体会一下,面向过程与面向对象的区别:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
// //面向过程
// var std1 = {name: "Bob",score: 96};
// var std2 = {name: "Mike",score: 88};
// //打印输出成绩
// function printScore(student) {
// console.log("姓名:" + student.name + "成绩:" + student.score);
// }
// //调用函数
// printScore(std1);
// printScore(std2);
//面向对象
function Student(name,score) {
this.name = name;
this.score = score;
this.printScore = function () {
console.log("姓名:" + this.name + "成绩:" + this.score);
};
}
//实例化
var std1 = new Student("Bob",96);
var std2 = new Student("Mike",88);
//调用实例对象自己的方法
std1.printScore();
std2.printScore();
</script>
</body>
</html>
3.创建对象的方法(构造函数)
(1)new Object构造函数
(2)对象字面量
(3)工厂函数
(4)自定义构造函数
这里重点讲解一下自定义构造函数:构造函数是根据具体的事物抽象出来的抽象模板,实例对象是根据抽象的构造函数模板得到的具体实例对象;
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
//自定义构造函数
function Person(name,age) {
this.name = name;
this.age = age;
this.isName = function () {
console.log(this.name);
}
}
//对象实例化
var per1 = new Person("gg",20);
var per2 = new Person("ax",22);
//调用方法
per1.isName();
per2.isName();
//判断实例和构造函数之间的关系
console.log(per1 instanceof Person);
</script>
</body>
</html>
4.实例成员和静态成员
使用构造函数方法创建对象时,可以给构造函数和创建的实例对象添加属性和方法,这些属性和方法都叫做成员。
(1)实例成员:在构造函数内部添加给 this的成员,属于实例对象的成员,在创建实例对象后必须由对象调用。
(2)静态成员:添加给构造函数自身的成员,只能使用构造函数调用,不能使用生成的实例对象调用。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
function Person(name,age) {
//实例成员,只能通过后期添加的实例对象进行调用
this.name = name;
this.age = age;
this.isName = function () {
console.log(this.name);
}
}
//静态成员,直接给构造函数添加的成员
Person.version = "1.0";
//对象实例化
var per1 = new Person("gg",20);
var per2 = new Person("ax",22);
//实例成员调用,只能实例对象调用,函数本身不能调用
console.log(per1.age);
console.log(Person.name);
//静态成员只能通过函数本身调用,不能通过实例对象调用
console.log(Person.version);
console.log(per1.version);
</script>
</body>
</html>
5.构造函数的问题
构造函数,可能会存在内存浪费的情况,这个时候可以采取以下解决办法:
(1)将公共的函数提取到构造函数之外
(2)存在多个公共函数,可以将多个公共函数存入构造函数之外的一个对象中
(3)原型对象
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
// //解决方法1:将公共函数提取出来
// function isName() {
// console.log(this.name);
// }
// function Person(name,age) {
// this.name = name;
// this.age = age;
// //多次创建,造成资源浪费
// this.isName = isName;
// }
// //对象实例化
// var per1 = new Person("gg",20);
// var per2 = new Person("ax",22);
// per1.isName();
//解决方法2:多个公共函数提取到一个对对象
var fns = {
isName: function () {
console.log(this.name);
},
isAge: function () {
console.log(this.age);
},
}
function Person(name,age) {
this.name = name;
this.age = age;
//多次创建,造成资源浪费
this.isName = fns.isName;
this.isAge = fns.isAge;
}
//对象实例化
var per1 = new Person("gg",20);
var per2 = new Person("ax",22);
per1.isAge();
</script>
</body>
</html>
原型对象
任何函数都具有一个 prototype属性,该属性是一个对象。可以在原型对象上添加属性和方法。
构造函数的prototype对象默认都有一个constructor属性,指向prototype对象所在函数。
通过构造函数得到的实例对象内部会包含一个指向构造函数的 prototype 对象的指针proto
实例对象可以直接访问原型对象成员。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
function Person(name,age) {
this.name = name;
this.age = age;
this.isName = function () {
console.log(this.name);
};
}
//构造函数的原型对象
console.log(Person.prototype);
//可以给原型对象添加属性
Person.prototype.type = "human";
Person.prototype.sayHi = function () {
console.log("hello");
}
//实例对象的构造函数的原型对象
var p1 = new Person("gg",20);
console.log(p1.__proto__);
</script>
</body>
</html>
解决构造函数导致内存浪费的最佳方法:原型对象prototype
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
function Person(name,age) {
this.name = name;
this.age = age;
}
//解决内存浪费的最佳方法
Person.prototype.type = "human";
Person.prototype.sayName = function () {
console.log(this.name);
};
Person.prototype.sayAge = function () {
console.log(this.age);
};
//对象实例化
var per1 = new Person("gg",20);
var per2 = new Person("ax",22);
per1.sayAge();
</script>
</body>
</html>
6.原型链
原型链的查找机制:
每当代码读取某个对象的某个属性时,都会执行一次搜索,目标是具有给定名字的属性:
1.搜索首先从对象实例本身开始
2.如果在实例中找到了具有给定名字的属性,则返回该属性的值
3.如果没有找到,则继续搜索指针指向的原型对象,在原型对象中查找具有给定名字的属性
4.如果在原型对象中找到了这个属性,则返回该属性的值
7.实例对象读取原型对象的成员
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
function Person(name,age) {
this.name = name;
this.age = age;
}
Person.prototype.type = "human";
Person.prototype.sayName = function () {
console.log(this.name);
};
Person.prototype.address = {
city: "北京"
};
//对象实例化
var per1 = new Person("gg",20);
//读取 属性和方法
console.log(per1.name);
console.log(per1.city);
console.log(per1.sayAge);
//通过实例对象添加新成员,给自己添加,屏蔽掉对原型对象的访问,不会给原型对象添加
per1.sex = "male";
//更改实例对象的成员,只会更改自己,会屏蔽掉对原型对象的访问,不会对原型对象进行更改
per1.type = "person";
console.dir(per1);
//通过实例来更改原型对象中 复杂类型的数据 这时会更改原型对象中的值,而实例对象自身不会增加新成员。
per1.address.city = "上海";
console.dir(per1);
</script>
</body>
</html>
8.更简单的原型语法
在进行定义构造函数时,可以通过成员的功能不同,而进行分别设置:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
function Person(name,age) {
this.name = name;
this.age = age;
}
//解决内存浪费的最佳方法
// Person.prototype.type = "human";
// Person.prototype.sayName = function () {
// console.log(this.name);
// };
// Person.prototype.sayAge = function () {
// console.log(this.age);
// };
//包含所有属性和方法的对象字面量 来重写原型对象 (不要忘记将constructor 指针重新指向构造函数)
Person.prototype = {
constructor: Person,
type: "human",
sayName: function () {
console.log(this.name);
}
}
//对象实例化
var per1 = new Person("gg",20);
per1.sayName();
</script>
</body>
</html>
9.内置构造函数的原型对象
给内置对象添加新的方法,用数组举例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
//不能用字面量的方式给内置对象添加新成员
//只能给内置对象添加一条新属性
Array.prototype.getEvenSum = function () {
//给数组计算偶数项 的和
//先写一个累加器
var sum = 0;
for (var i = 0;i < this.length;i++) {
if (i % 2 == 0) {
sum += this[i];
}
}
return sum;
};
//定义一个数组
var arr = [2,4,6,9,2,6];
console.log(arr.getEvenSum());
console.dir(Array.prototype);
</script>
</body>
</html>
总结
这部分学习了面向对象编程思想,可以通过案例的练习,来锻炼自己的编程思想。每天坚持学习前端,加油~