面向过程与面向对象
面向过程
=> 按照顺序一步一步来
面向对象(轮播图)
=> 找到一个对象, 能帮我完成轮播图
=> JS 本身没有, 我们需要第三方
=> swiper: 生成一个完成轮播图的对象
面向对象的本质:当你需要完成一个 功能A 的时候,我们找到 JS 有没有这个完成 功能A 的对象。如果没有, 我们 制造一个 "机器"。
"机器" 是什么:
+ 能力: 能创造一个 有属性 有方法 合理的 对象
+ 构造函数就是这个 "机器"
构造函数的书写和使用
明确: 构造函数也是函数, 只不过是在调用的时候和 new 关键字连用了
目的: 就是为了创建一个 有属性 有方法 合理的 对象
1. 调用必须有 new 关键字
=> 如果没有, 那么没有创建对象的能力
=> 只要有, 就会自动创建一个对象
2. 在构造函数内部不要写 return
=> 如果 return 基本数据类型, 写了白写
=> 如果 return 复杂数据类型, 构造函数白写
3. 构造函数在调用的时候, 如果不需要传递参数, 最后的小括号可以不写
=> 但是推荐我们都写上
4. 构造函数推荐首字母大写
=> 是为了直观看出和普通函数的区别
=> 看到首字母大写的函数, 基本上就要和 new 连用
5. 当函数和 new 关键字连用
=> 会创造对象, 我们关创造出来的对象叫做 实例对象
=> 我们管创造的过程叫做 实例化 的过程
=> 构造函数体内的 this 指向当前实例对象
=> 也就是本次 new 的时候创建的那个对象
构造函数的合理性与原型
一旦在构造函数体内书写方法的时候,你创建多少个实例化对象, 那么就有多少个方法要占用内存空间,不合理。
解决:利用函数自带的属性prototype
prototype (原型 / 原型对象)
定义: 每一个函数天生自带一个属性叫做 prototype, 他是一个对象
+ 只要函数定义好以后, 这个 prototype 就出生了
+ 构造函数也是函数, 构造函数也有 prototype, 我们可以像里面添加一些内容
+ 这个天生自带的 prototype 里面有一个属性叫做 constructor
=> 表示我是哪一个构造函数伴生的原型对象
proto
+ 定义: 每一个对象天生自带一个属性, 叫做 __proto__, 指向所属构造函数的 prototype
+ 实例化对象也是一个对象
+ 实例化对象也有 __proto__ 属性
function Person() {}
/向prototype 上添加一些属性和方法
Person.prototype.sayHi = function () { console.log('hello world') }
/因为 P1 是 Person 实例化出来的对象 所以 p1 所属的构造函数就是 Person
let p1 = new Person()
console.log(p1)
console.log('Person.prototype', Person.prototype)
console.log('p1.__proto__', p1.__proto__)
console.log(Person.prototype === p1.__proto__) /实例的proto指向构造函数的prototype
结果:
构造函数相关的 this 指向
1. 构造函数体内的 this 指向
=> 因为和 new 关键字连用, this 指向当前实例
2. 构造函数原型上的方法里面的 this 指向
=> 因为方法是依靠实例对象在调用
=> this 指向当前实例