目录
一、面向对象
1.概念
面向对象(Object Oriented,OO)是软件开发方法,面向对象是一种对现实世界理解和抽象的方法,是计算机编程技术发展到一定阶段后到产物,是一种高级的编程思想。
面向对象的概念和应用已超越了程序设计和软件开发,扩展到如数据库系统,交互式界面,应用结构,应用平台,分布式系统,网络管理结构,CAD技术,人工智能等领域。
2.面向对象与面向过程的区别
要理解这个,首先我们来回想一下以前我们完成一件事的过程,拿化妆来举例,
面向过程我们要考虑的是:先补水、再遮瑕、粉底、定妆、眼影、眼线....
面向对象我们要考虑的是让化妆师来替我们完成化妆
面向过程:强调的是功能行为,关注的是解决问题需要哪些步骤
面向对象:将功能封装进对象,强调具备了功能的对象,关注的是解决问题需要哪些对象
3.面向对象的特点
封装:不考虑内部实现,只考虑功能实现(把一些比较散的,单一的值,有结构的组装成一个整体。把一些隐藏的值不暴露给外界)
继承:从已有对象上,继承出新对象 (获取已存在的对象已有属性和和方式的一种方式)
多态:一个父类的引用变量,可以指向其任意一个子类对象(简单来说就是同一操作,作用于不同的对象,会产生不同的解释和行为)
4.创建对象的方式
面向对象的核心就是对象
(1)字面量
var obj = {
//给对象设置属性
name : "蔡徐坤",
age : 18,
//给对象设置方法
say : function(){
console.log("唱跳RAP篮球");
}
}
console.log(obj.name) // 蔡徐坤
obj.say() //唱跳RAP篮球
(2)new Object()
var obj = new Object();
//给对象设置属性
obj.name = "蔡徐坤";
obj.age = 18;
//给对象设置方法
obj.say = function(){
console.log("唱跳RAP篮球");
}
3.工厂函数
工厂函数:专门用于创建对象的函数
工厂方式创建对象:利于函数的特性,可以传递参数去创建对象,类似于生活中的工厂
//第一种形式
function person(name, age){
//创建一个空对象
var obj = new Object();
//设置属性
obj.name = name;
obj.age = age;
//设置方法
obj.say = function(){
console.log("唱跳RAP篮球");
}
//把对象返回出去给外界
return obj;
}
var p1 = person("小明", 18);
var p2 = person("小刚", 20);
console.log(p1, p2);
//第二种形式
function person(name, age){
var obj = {
name : name,
age : age,
say : function(){
console.log("唱跳RAP篮球");
}
}
return obj;
}
var p1 = person("小明", 18);
var p2 = person("小刚", 20);
console.log(p1, p2);
但这样会有一个问题:使用的都是同一个方法,发现竟然函数的存储地址是不一样的,这样的话对性能优化上不太友好
console.log(obj1.say == obj2.say) // false
解决:把say方法单独提出来,但是这样会造成全局变量污染,不推荐
4.构造函数创建对象
构造函数本质上来说是工厂函数的简写,要求首字母大写,需要使用new关键字来调用
// 构造函数创建对象
function Person(name, age){
// 添加属性
this.name = name
this.age = age
// 添加方法
this.say = function(){
console.log(this.name + '唱跳RAP篮球')
}
}
// 调用构造函数(实例化对象)
const p1 = new Person('蔡徐坤', 18)
console.log(p1)
p1.say()
5.class类来创建对象
class类:ES6为了解决构造函数语法使用便利的问题,提出了一个新的语法叫做class,和其他语言里面比较类似了;class不是真正的类,其实是一种语法糖
语法糖: js本身是没有类的能力,但是class确实太方便了(太香了),因此为了让你使用方便,就模拟了一个class的类出来让你使用,语法上其实本质上还是构造函数那一套,把这种情况称之为语法糖,说白了就是在语法上进行包装盒处理
class Person{
// 构造器,写在constructor里面的属性和方法,其实就是写在了构造函数内部
constructor(name, age){
this.name = name
this.age = age
// this.say = function(){
// console.log('唱跳RAP篮球')
// }
//此时 console.log(p1.say == p2.say) 为false
}
// 写在这里的代码其实就会默认给你放在原型对象里面
//此时 console.log(p1.say == p2.say) 为true
say(){
console.log('唱跳RAP篮球')
}
}
const p1 = new Person('蔡徐坤', 18)
const p1 = new Person('基尼太美', 18)
二、原型对象与原型链
1.原型对象(显式原型对象)
prototype原型对象:
每一个构造函数都有一个叫做prototype的属性,这个属性指向一个对象,把指向的这个对象称之为原型对象
原型对象里面保存的属性和方法可以被共享(被构造函数的实例化对象所共享)
constructor构造器:
专属于构造函数的,可以标识原型对象属于哪个构造函数
function Person(name, age){
this.name = name
this.age = age
}
// 查看Person构造函数的原型对象(prototype)
console.log(Person.prototype)
// 给原型对象添加方法
Person.prototype.say = function(){
console.log(this.name + '唱跳RAP篮球!')
}
// 给原型对象添加属性
Person.prototype.money = '抢银行就有了'
const p1 = new Person('蔡徐坤', 18)
const p2 = new Person('基尼太美', 16)
console.log(p1.say == p2.say) // true
2.隐式原型对象
__proto__:对于实例化对象(比如p1)来说,每一个实例化对象都有一个__proto__属性,这个属性指向的是实例化这个对象的构造函数的原型对象,也可以理解是隐式原型对象
3.对象三角恋关系
构造函数:对于构造函数来说,每一个构造函数都有一个prototype属性,这个属性指向一个对象,把这个指向的对象称之为原型对象(保存共享的数据)
原型对象:对于原型对象来说,每一个原型对象都有一个constructor属性,这个属性指向的是创建这个原型对象的构造函数(告诉你原型对象归属于谁那个构造函数)
实例化对象:对于实例化对象来说,每一个实例化对象都有一个__proto__属性,这个属性指向的是实例化这个对象的构造函数的原型对象
4.原型链
概念:就是实例对象与原型之间的链接,每一个对象都有原型,而原型本身又是对象,原型又有原型,依次类推形成的一种链式结构,称之为原型链
查找规则:
先查找当前对象, 当前对象有就使用当前对象的方法
当前对象没有再逐层在原型链上查找, 最先找到那个就使用哪个
如果找到null都没找到就报错
首先了解一下函数与对象:
(1)JavaScript中的函数是引用类型(对象类型),既然是对象,所以也是通过构造函数创建出来的, “所有函数”都是通过Function构造函数创建出来的对象
(2)JavaScript中只要是"函数",就有prototype属性。Function函数的prototype属性指向Function原型对象
(3)JavaScript中只要有原型对象就有constructor属性。Function原型对象的constructor指向它对应的构造函数
(4)JavaScript中万物皆对象,只要是对象就有__proto__
属性
“所有函数”都是通过Function构造函数创建出来的对象,怎么证明呢?用函数的三角恋关系去证明
//证明步骤:
// 证明步骤:
// 第一步:查看Function构造函数
console.log(Function)
// 第二步:查看Function构造函数的原型对象
console.log(Function.prototype) // ƒ () { [native code] } Function构造函数的原型对象就是函数,因为函数本身就是模板(类)
// 第三步:查看Person构造函数的__proto__隐式原型
console.log(Person.__proto__)
可以看到,是满足三角恋关系的,同理,我们平时经常使用的Object类型也与Function满足三角恋关系、还有原型对象与Object的原型对象也满足三角恋关系,但Object的原型对象的__proto__为空(null),所以可以得到扩展之后的原型链图