「这是我参与2022首次更文挑战的第2天,活动详情查看:2022首次更文挑战」。
1. 面向对象
面向对象是一种注重结果的思维方式
2. 面向对象与面向过程的关系
面向对象的本质是对面向过程的封装
3. 构造函数创建对象(new关键字原理)
1.创建空对象
2.this指向这个对象
3.对象的赋值
4.返回这个对象
4. 原型对象
1.原型对象:每一个函数创建的时候,系统都会自动创建一个与之对应的原型对象
2.原型对象的作用:解决构造函数内存资源的浪费,和全局变量的污染
3.原型对象的访问方式: 构造函数.prototype
5. 实例对象
调用构造函数的对象
实例对象可以访问原型对象中的一切
constructor 属性:原型对象的属性 指向构造函数
语法: 实例对象.constructor
作用:让实例对象知道是被那个构造函数创建的
6. 原型对象使用的注意点
1.那些属性可以放入原型中
所有实例对象共享的成员
2.对象访问原型的规则 就近原则
对象访问成员的时候 优先访问自身的 如果自身没有才会访问原型对象的
3.原型对象是可以覆盖的
实例对象访问覆盖前的原型对象还是访问覆盖后的原型对象 取决于实例对象的创建时间
覆盖前创建的 指向覆盖前的原型
覆盖后创建的 指向覆盖后的原型
7. 构造函数、原型对象、实例对象三者之间的三角关系
prototype:属于构造函数,指向原型对象
constructor:属于原型对象,指向构造函数
__proto__:属于实例对象,指向原型对象
8. 面向对象三大特征
封装
把需要复用的代码放入对象的方法
继承
一个对象拥有另一个对象所有的成员(三种继承方式:混入式继承,替换原型继承,混合式继承)
多态
一个对象在不同情况的多种状态
9. 三种继承方式
1.混入式继承 : 遍历父对象成员添加给子对象
* 特点: 适用于一个子对象
2.替换原型继承 : 将父对象作为子对象的原型
* 特点:可以实现多个子对象继承,但是会覆盖子对象默认的原型
3.混合式继承 : 混入式 + 替换原型
* 遍历父对象所有成员,添加给子对象的原型
* 特点: 可以实现多个子对象继承,并且不会覆盖子对象默认的原型
10. 原型链
js是通过原型链实现继承的
1.原型链: 对象有自己的原型,原型对象也是对象,也有自己的原型。以此类推形成链式结构,称之为原型链
2.对象访问原型链规则: 就近原则
先从自己找,自己没有从原型找,原型没有就找原型的原型。
以此类推,直到原型链终点null.如果还没有,属性则获取undefined,方法则报错xxx is not a function
11. 内置对象的原型链
arr 对象的原型链
//声明数组对象
let arr = [10,20,30]//new Array(10,20,30)
//1.查看arr对象的原型
console.log( arr.__proto__.constructor )//Array
console.log( arr.__proto__ === Array.prototype )//true
//2.查看arr对象的原型的原型
console.log( arr.__proto__.__proto__.constructor )//Object
console.log( arr.__proto__.__proto__ === Object.prototype )//true
/* js作者把数组所有的方法都会放在Array.prototype中
这样的话所有的数组实例对象都可以继承原型中的方法(节省内存资源)
js是通过原型链实现面向对象的继承
*/
arr.reverse()
Date 对象的原型链
//声明日期对象
let d1 = new Date()
/* js中有少部分的对象,无法通过log来打印的。 一旦使用log会自动转成字符串显示
* 日期对象Date 函数对象function DOM对象
如果想要看这三个对象的内存,则需要使用 console.dir()
*/
console.log(d1)
console.dir(d1)
//1.查看日期对象的原型
console.log(d1.__proto__.constructor) //Date
console.log(d1.__proto__ === Date.prototype) //true
//2.查看日期对象的原型的原型
console.log(d1.__proto__.__proto__.constructor )//Object
console.log(d1.__proto__.__proto__ === Object.prototype )//true
String 对象的原型链
//string对象
let str = new String('abc') //new String('abc')
console.log(str)
//1.查看str的原型
console.log( str.__proto__.constructor )//String
console.log( str.__proto__ === String.prototype )//true
//2.查看str的原型的原型
console.log( str.__proto__.__proto__.constructor )//Object
console.log( str.__proto__.__proto__ === Object.prototype )//true
DOM 对象的原型链
<body>
<div class="box">我是div</div>
<p class="pp">我是p标签</p>
<script>
let box = document.querySelector('.box')
let pp = document.querySelector('.pp')
console.log(box)
console.dir(box)
console.log(pp)
console.dir(pp)
console.log(box.__proto__)
console.log(box.__proto__.__proto__)
console.log(box.__proto__.__proto__.__proto__)
console.log(box.__proto__.__proto__.__proto__.__proto__)
console.log(box.__proto__.__proto__.__proto__.__proto__.__proto__)
</script>
</body>
函数对象的原型链
/*
1.函数也是对象类型
* 函数也有自己的原型链
*/
//如何证明一个函数也是对象类型 : 使用点语法证明(对象才有点语法)
function fn () {
console.log('111111')
}
//如果函数也可以像对象那样使用点语法存储属性,说明函数也是对象类型
fn.sex = '男'
fn.age = 38
console.log(fn) //只能打印代码
console.dir(fn) //只能打印代码
console.log(fn.sex) //男
console.log(fn.age) //38
//1.查看函数的原型链
console.log(fn.__proto__.constructor)//Function
console.log(fn.__proto__ === Function.prototype)//true
//2.查看函数原型的原型
console.log(fn.__proto__.__proto__.constructor)//Object
console.log(fn.__proto__.__proto__ === Object.prototype)//true
12. instanceof 关键字
- 与原型链相关的关键字: instanceof
- instanceof运算符 : 对象 instanceof 构造函数
- 检测右边构造函数的原型 在不在 左边实例对象的 原型链中
//测试1
// arr -> Array.prototype -> Object.prototype -> null
let arr = [10, 20, 30]
console.log(arr instanceof Array) //true
console.log(arr instanceof Object) //true
/* 任何函数原型链都是固定的(包含构造函数 fn、Person、Date、Array、Function、Object)
函数 -> Function.prototype -> Object.prototype -> null
*/
//测试2 : 左边的是函数对象 右边是 构造函数
//Function实例对象 -> Function.prototype -> Object.prototype -> null
console.log(Function instanceof Function)//true
console.log(Function instanceof Object)//true
//测试3 : 左边的是函数对象 右边是 构造函数
//Object实例对象 -> Function.prototype -> Object.prototype -> null
console.log(Object instanceof Function)//true
console.log(Object instanceof Object)//true
13. 静态成员与实例成员
静态成员: 属于函数对象的成员
实例成员: 属于实例对象的成员
//构造函数
function Person (name, age) {
this.name = name
this.age = age
}
//实例对象
let p1 = new Person('ikun', 32)
//实例成员
console.log(p1.name)
console.log(p1.age)
//静态成员
Person.sex = '男'
console.log(Person.sex)//'男'
// 实例对象 只能访问自己的 和 原型的成员(实例成员)。
//实例对象 不可以访问构造函数中的成员。(静态成员)
console.log( p1.sex )//undefined
14. class关键字
class关键字作用 : 声明一个类函数
* 类函数: 其实就是构造函数
* 类函数好处:
a. 把构造函数 和 原型 包在一个大括号内部,阅读性高
b. 类函数必须使用new调用,不使用new
class关键字语法 :
class 构造函数{
//(1)必须要有一个函数叫做constructor
constructor(name,age){
this.name = name
this.age = age
}
//(2)下面写原型中的成员
eat(){ //等价于: Person.prototype.eat = function(){}
}
}
15. ES5构造函数与ES6类函数的区别
1 . ES5构造函数
//构造函数
// function Person (name, age) {
// this.name = name
// this.age = age
// }
// //原型对象
// Person.prototype.eat = function () {
// console.log('我要吃饭')
// }
// //实例对象
// let p1 = new Person('班长', 38)
// console.log(p1)
2 . ES6类函数
//类函数
class Person {
//构造函数
constructor (name, age) {
this.name = name
this.age = age
}
//原型对象
eat () {
console.log('我要吃饭')
}
}
//使用类函数,其实底层跟以前一模一样,以前的语法完全可以直接用
Person.prototype.learn = function(){
console.log('111');
}
Person.prototype.type = '中国人'
//调用类函数
let p2 = new Person('ikun', 32)
console.log(p2)
16. extends关键字
1.作用 : 继承
2.原理 : 替换原型方式继承
3.语法 : class 子构造函数 extends 父构造函数
//类函数
class Person {
//(1)构造函数
constructor (name, age) {
this.name = name
this.age = age
}
//(2)原型对象
eat () {
console.log('我要吃饭')
}
}
//(3)调用类函数 : 创建实例对象
let p2 = new Person('ikun', 32)
console.log(p2)
/* 子构造函数
底层原理不是替换Student的原型,而是替换Student原型的原型
Student.prototype.__proto__ = Person.prototype
*/
class Student extends Person {
learn () {
console.log('我爱学习')
}
}
let s1 = new Student('班长', 38)
console.log(s1)
17. super关键字
1.作用: 子类中调用父类的方法
2.原理: 函数上下文调用
3.语法 : super关键字只能用于extends中
class Student extends Person {
//想自己写构造函数
constructor (name, age, score) {
/* 当子类 继承 父类的时候,如果子类想要自己写构造函数。
就必须要在自己的构造函数中调用super()
*/
super(name,age)
this.score = score
}
}
注意: 如果子类 也要写自己的构造函数, 就必须要先调用 super() 调用父类的构造函数