day24面向对象
面向对象
概述:
面向对象是一种编程思维(opp),他的核心就是找有对应方法的对象做对应的事情(万物皆对象)
示例
需求:我想泡个脚
面向过程的思维:(按照对应步骤走)
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 //可以省略对应的括号
原型
prototype
概述:prototype
概述:prototype是每一个函数都有的一个空间(对象),里面就可以存放一些内容了
function test(){ } console.log(test.prototype)
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
那么通过上面的代码我们就知道构造函数的问题就被解决了
总结
我们一般将对应的属性存储在构造的方法里
将对应的方法存储在原型上
存储在原型上的内容可以直接通过对象实例去获取
__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__构造函数的protoptype的指向是一样的
在构造函数里面我们是先编译一个构造函数(函数在预编译阶段先加载)再自动生成一个对象(构造函数先诞生 对象后诞生)
经过上述讲解我们知道实例对象的__proto__是指向对应构造函数的prototype的
所以我们往prototype存东西我们可以通过实例对象的__proto__来获取 同样的我们也可以通过对应的实例对象的__proto__来设置数据
原型链
构造函数的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
总结
原型链找的过程
先找到自己的__proto__是否存在(构造函数的protoype)
再找父类的__proto__是否存在(构造函数的prototype)
再找到对应的父类,直到找到Object的__proto__为止 如果还找不到返回null
原型链会忽略对象赋值
没有就创建这个属性
有就更改这个属性
他跟 __ proto __ 没有关系
我们在创建构造函数的时候会将对应的属性写在构造函数上 将方法写在原型上