1. 编程思想
1.1 面向过程
面向过程就是分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候再一个一个的依次调用就可以了。
面向过程,就是按照我们分析好了的步骤,按照步骤解决问题
eg:蛋炒饭
优点:性能比面向对象高,适合跟硬件联系很紧密的东西,例如单片机就采用的面向过程编程。
缺点:没有面向对象易维护、易复用、易扩展
1.2 面向对象(oop)
面向对象是把事务分解成为一个个对象,然后由对象之间分工与合作。
面向过程,是以对象功能来划分问题,而不是步骤
eg:盖浇饭
在面向对象程序开发思想中,每一个对象都是功能中心,具有明确分工
面向对象编程具有灵活、代码可复用、容易维护和开发的优点,更适合多人合作的大型软件项目
面向对象的特性:封装性、继承性、多态性
优点:易维护、易复用、易扩展,由于面向对象有封装继承、多态性的特性,可以设计出低耦合的系统,使系统更加灵活、更加易于维护
缺点:性能比面向过程低
2. 构造函数
封装是面向对象思想中比较重要的一部分,is面向对象可以通过构造函数实现的封装
同样的将变量和函数组合到了一起并能通过 this 实现数据的共享,所不同的是借助构造函数创建出来的实例对象之间是彼此不影响的
function Star(uname, age){
this .uname = uname
this.age = age
this.sing = function () {
console.log("我会唱歌")
}
}
//实例对象,获得了构造函数中封装的所有逻辑
const ldh = new star("刘德华",18)
const zxy = new Star('张学友',19)
总结:
1.构造函数体现了面向对象的封装特性
2.构造函数实例创建的对象彼此独立、互不影响
- 可以借助构造函数来实现面向对象编程的封装性、继承性
- 构造函数方法很好用,但是
存在浪费内存的问题
3. 原型
3.1 原型
- 构造函数通过原型分配的函数是所有对象所
共享的
。 - JavaScript 规定,
每一个构造函数都有一个 prototype 属性
,指向另一个对象,所以我们也称为原型对象 - 这个对象可以挂载函数,对象实例化不会多次创建原型上函数,节约内存
- 我们可以把那些
不变的方法,直接定义在 prototype 对象上
,这样所有对象的实例
就可以共享这些方法
构造函数和原型对象中的this 都指向 实例化的对象
function star(uname,age){
this.uname = unae
this .age = uge
}
console.log(Star.prototype) // 返回一个对象数为原型对象
Star.prototype.sing = function () {
console.log("我会唱歌")
}
const ldh = new star("刘德华",18)
const zxy = new star("张学友",19)
console,log(ldh.sing === zxy.sing)
// 结果是 true 说明俩函数一样 ,共享
3.2 constructor属性
每个原型对象里面都有个constructor 属性 (constructor 构造函数
作用:该属性指向该原型对象的构造函数,简单理解,就是指向我的爸爸,我是有爸爸的孩子
使用场景:
如果有多个对象的方法,我们可以给原型对象采取对象形式赋值但是这样就会覆盖构造函数原型对象原来的内容,这样修改后的原型对象 constructor 就不再指向当前构造函数了此时,我们可以在修改后的原型对象中,添加一个 constructor 指向原来的构造函数。
function star(name){
this.name = name
}
Star.prototype = {
sing: functior(){console.log('唱歌') },
dance: function () { console.log('跳舞') }
}
console.log(star.prototype.constructor) // 指向 Object
function star(name){
this.name = name
}
Star.prototype = {
//手动利用constructor 值回 Star的构造函数
constructor: star,
sing: function () {console.log("唱歌") },
dance: function () { console.log("跳舞") }
}
console.log(Star.prototype.constructor) // 指向 star
3.3 对象原型
对象都会有一个属性__proto __
指向构造函数的 prototype 原型对象,之所以我们对象可以使用构造函数 prototype原型对象的属性和方法,就是因为对象有_proto 原型的存在。
注意:
- __ proto__是S非标准届性
- [[prototype]]和 __ proto __意义相同
- 用来表明当前实例对象指向哪个原型对象prototype
- __ proto __ 对象原型里面也有一个 constructor属性,
指向创建该实例对象的构造函数
3.4 原型继承
继承是面向对象编程的另一个特征,通过继承进一步提升代码封装的程度,JavaScript 中大多是借助原型对象实现继承
的特性。
<body>
<script>
// 继续抽取 公共的部分放到原型上
// const Person1 = {
// eyes: 2,
// head: 1
// }
// const Person2 = {
// eyes: 2,
// head: 1
// }
// 构造函数 new 出来的对象 结构一样,但是对象不一样
function Person() {
this.eyes = 2
this.head = 1
}
// console.log(new Person)
// 女人 构造函数 继承 想要 继承 Person
function Woman() {
}
// Woman 通过原型来继承 Person
// 父构造函数(父类) 子构造函数(子类)
// 子类的原型 = new 父类
Woman.prototype = new Person() // {eyes: 2, head: 1}
// 指回原来的构造函数
Woman.prototype.constructor = Woman
// 给女人添加一个方法 生孩子
Woman.prototype.baby = function () {
console.log('宝贝')
}
const red = new Woman()
console.log(red)
// console.log(Woman.prototype)
// 男人 构造函数 继承 想要 继承 Person
function Man() {
}
// 通过 原型继承 Person
Man.prototype = new Person()
Man.prototype.constructor = Man
const pink = new Man()
console.log(pink)
</script>
</body>
3.5 原型链
基于原型对象的继承使得不同构造函数的原型对象关联在一起,并且这种关联的关系是一种链状的结构,我们将原型对象的链状结构关系称为原型链
只要是对象就有__proto__,只要是原型对象里面就有constructor
<body>
<script>
// function Objetc() {}
console.log(Object.prototype)
console.log(Object.prototype.__proto__)
function Person() {
}
const ldh = new Person()
// console.log(ldh.__proto__ === Person.prototype)
// console.log(Person.prototype.__proto__ === Object.prototype)
console.log(ldh instanceof Person)
console.log(ldh instanceof Object)
console.log(ldh instanceof Array)
console.log([1, 2, 3] instanceof Array)
console.log(Array instanceof Object)
</script>
</body>
查找原则:
① 当访问一个对象的属性(包括方法)时,首先查找这个对象自身有没有该属性。
② 如果没有就查找它的原型(也就是 __proto__指向的 prototype 原型对象)
③ 如果还没有就查找原型对象的原型(Object的原型对象)
④ 依此类推一直找到 Object 为止(null)
⑤ __proto__对象原型的意义就在于为对象成员查找机制提供一个方向,或者说一条路线
⑥ 可以使用 instanceof 运算符用于检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上