面向对象
概述:
面向对象是一种编程思维(oop),他的核心就是找有对应方法的对象做对应的事情(万物皆对象 (万物都可以被当作对象))
示例
需求:我想泡个脚
面向过程的思维:(按照对应的步骤走)
1.准备一个盆
2.烧水
3.把水倒入盆中
4.脱鞋子
5.泡脚
面向对象的思维:(找一个会做事情的对象去做)
去洗脚城(找个技师)
面向对象的核心 对象(将一切不是动作的内容抽取为属性 将一切是动作的行为抽取为方法)
对象的创建
第一种通过构造方法创建(new关键词)
构造方法是什么
构造方法是一个方法(函数)他是一个匿名函数 他的名字就是你对应class的名字(首字母大写)
//构造函数创建 new关键词 构造函数的首字母必须大写
function Person(){
console.log(this);
}
//class的写法 其实他的底层就是上面的构造函数
// class Person{
// //构造函数
// constructor(){
// console.log(this);
// }
// }
//对象实例的创建
var person = new Person()
person.name = "hello"
第二个使用工厂方法模式创建
//工厂方法模式 (设计模式 类似于一个复用工厂 出产对应的对象 Object是属于对象超类 所有对象默认都继承Object)
function factor(name){
//准备一个对象
var obj = new Object()
//将所有要设置的属性 设置给这个对象
obj.name = name
//将这个对象返回
return obj
}
var person1 = factor("jack")
console.log(person1);
第三种创建 使用字面量
var person = {
name:'tom',
age:18,
eat(){
console.log("吃饭")
}
}
总结
构造函数创建的过程
- 自动创建对象
- 手动添加属性
- 自动返回对象
工厂方法创建的过程
- 手动创建对象
- 手动添加属性
- 手动返回对象
细讲一下构造函数
特性:
1.首字母必须大写
2.和普通的函数没有区别(可以自由传值 以及可以指定默认参数)
function Person(name="tom",age){
this.name = name //this指向用户实例 person.name = name
this.age = age //相当于perosn.age = age
this.sayHi = function(){ //perosn.sayHi
console.log('Hi')
}
}
var person = new Person('jack',18)//创建对象实例
person.sayHi()
3.需要new关键词修饰(如果没有参数可以省略后面的括号)
function Person(){
}
var person = new Person //可以省略对应的括号
示例(汽车的对象)
//汽车的构造
function Car(name,color,price){
this.name = name
this.color = color
this.price = price
//跑的方法
this.run = function(){
console.log(`我开着${this.price}元${this.color}的${this.name}在跑`)
}
}
var car = new Car('二手五菱宏光','金色',300)
var car1 = new Car('兰博基尼','金色',28888888)
car.run()
car1.run()
//false 这个里面new俩个对象 开辟了俩个内存 这个俩个内存里面的数据是不是分别开辟的内容
console.log(car.run == car1.run);
经过上述代码我们发现对应的一个对象在new的时候 会重新开辟一个新的内存空间 在这个时候里面的属性和方法都会被重新开辟一个空间来存储,所以就导致我们对应的俩个对象的方法的指向是不一样的(俩个方法存在着俩个内存空间)这个时候就会产生一个资源浪费的问题。
为了解决这个问题 就产生了一个内容叫做原型。
所以在这个时候我们就明白了原型中一般存储方法。
原型
prototype
概述:prototype是每一个函数都有的一个空间(对象),里面就可以存放一些内容了
function test(){
}
console.log(test.prototype)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-izE6RjAP-1655896958397)(C:\Users\29769\AppData\Roaming\Typora\typora-user-images\image-20220620152938595.png)]
constructor
这个会指向对应的对象的构造函数,相对构造函数本身
prototype拥有的方法
hasOwnProperty 返回一个boolean类型的值 判断当前的对象上是否存在对应的属性
// hasOwnProperty 判读当前的对象上是否具备对应的属性
function Person(){
}
Person.prototype.hello = 'jack'
var person = new Person()
person.name = 'hello'
// console.log(Person.prototype.hasOwnProperty());
console.log(person.hasOwnProperty('hello')); //false
console.log(person.hasOwnProperty('name')); //true
isProtoTypeOf 返回一个boolean类型的值 判断当前的对象是否处在对应的原型链上
//isPrototypeOf
// object 参数是 Object 类型的一个对象,将对其原型链进行检查。
// console.log(Person.prototype.isPrototypeOf());
console.log(Person.isPrototypeOf(person)); //false
-
因为对应的构造函数也是一个函数 所以他同样具备这个内存空间(prototype)
-
prototype是属于我们的构造函数的
因为对应的构造函数有这个内存空间(对象)所以我们可以往这个对象里面设置属性和方法
//构造函数
function Person(){
}
//构造函数的原型prototype
Person.prototype.name = 'jack'
Person.prototype.sayHello = ()=>{
console.log('hello')
}
//当前person实例会自动读取到原型中的内容
var person = new Person()
//打印的属性是原型中的
console.log(person.name) //jack
//原型中的方法
person.sayHello()
通过对应的对象实例.属性名 可以访问到构造函数里面的prototype里面的值
console.log(person.sayHello == person1.sayHello);//true
那么通过上面的代码我们就知道构造函数的问题就被解决了
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cd5noxFi-1655896958398)(C:\Users\29769\AppData\Roaming\Typora\typora-user-images\image-20220620154635350.png)]
总结
- 我们一般将对应的属性存储在构造方法里面
- 将对应的方法存储在原型上
- 存储在原型上的内容可以直接通过对象实例.去获取
对应的对象怎么去获取prototype里面的值呢 他如何来指向的呢
__
proto__
概述:
所有的对象都具备一个属性__
proto__
这个也是一个对象空间
var obj = {
}
console.log(obj.__proto__)
那么同样的我们的实例化对象也是一个对象 所以他也存在对应的一个空间__
proto__
那么这个空间指向哪?
function Person(){
}
Person.prototype.name = "jack"
var person = new Person()
console.log(person.__proto__)
//我们的实例对象的__proto__和构造函数的prototype的指向是一致 这个俩个东西就是一个东西
console.log(person.__proto__ == Person.prototype)
经过上述我们发现对应的实例对象的__
proto__
和构造函数的prototype的指向是一致
在构造函数里面的我们是先编译出一个构造函数(函数在预编译阶段先加载)再自动生成一个对象(构造函数先诞生 对象后诞生)
经过上述的讲解我们知道 实例对象的__
proto__
指向对应构造函数的prototype的
所以我们往prototype存东西 我们可以通过实例对象的__
proto__
来获取 同样的我们也可以通过对应的实例对象的__
proto__
来设置数据进入到构造函数的prototype
function Person(){
}
Person.prototype.name = "jack" //往原型中存储数据
var person = new Person()
person.__proto__.age = '18' //往原型中存数据
var person1 = new Person()
console.log(person1.age)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qCkqDbyg-1655896958399)(C:\Users\29769\AppData\Roaming\Typora\typora-user-images\image-20220620162213089.png)]
原型链
- 构造函数的prototype是一个对象 里面可以存放的对应的数据(不会二次的开辟空间)
- 实例对象的
__
proto__
他指向对应的构造函数的prototype - 那么请问我们的构造函数是不是也是一个对象 那么他同时也具备对应的
__
proto__
他的__
proto__
指向哪里?
那么这个就诞生了原型链
概述:
对象在原型(__
proto__
)上找属性的过程被称为原型链
Object.name = 'hello'
Object.prototype.username = 'hi'
function Person(){
}
Person.prototype = new Son()
Person.prototype.age = 18
function Son(){
}
var son = new Son()
var person = new Person()
console.log(son.name) //undefinde
console.log(person.name) //undefinde
console.log(son.age) //undefinde
console.log(person.age) //18
console.log(son.username) //hi
console.log(person.username) //hi
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DyUa8ZJ0-1655896958400)(C:\Users\29769\AppData\Roaming\Typora\typora-user-images\image-20220620170220816.png)]
总结
原型链找的过程
- 先找自己的
__
proto__
是否存在(构造函数的prototype) - 再找父类的
__
proto__
是否存在 (构造函数的prototype) - 再找对应的父类,直到找到Object的
__
proto__
为止 如果还找不到 - 找到null 并且返回
原型链是会忽略对象的赋值的
- 没有就创建这个属性
- 有就更改这个属性
- 他跟
__
proto__
没有关系
我们在创建构造函数的时候会将对应的属性写在构造函数上 将方法写在原型上
写一个tab切换(面向对象)
Ua8ZJ0-1655896958400)]
总结
原型链找的过程
- 先找自己的
__
proto__
是否存在(构造函数的prototype) - 再找父类的
__
proto__
是否存在 (构造函数的prototype) - 再找对应的父类,直到找到Object的
__
proto__
为止 如果还找不到 - 找到null 并且返回
原型链是会忽略对象的赋值的
- 没有就创建这个属性
- 有就更改这个属性
- 他跟
__
proto__
没有关系
我们在创建构造函数的时候会将对应的属性写在构造函数上 将方法写在原型上