今天又是一个美好的一天耶 ! ✌
一、面向对象
对象:
-
一组属性的无序集合,由key和value组成(相比数组来说,提升了查找速度和数据传输速度)
-
如果我们想对某个属性精准的操作控制,可以使用属性描述符 object.defineProperty
-
创建对象的有两种方式,一种是字面量,一种通过 new 关键字(构造函数)创建
构造函数:
- 构造函数,又称为构造器,通常是我们创建对象时会调用的函数
- proto.constructor 浏览器提供的
- object.getPrototypeOf es5之后官方提供的
二、new 的过程
- 在内存中开辟一个新的地址,创建一个新的对象
- 这个对象的【prototype】 属性会被赋值为他构造函数的 prototype
- 构造函数的this ,会指向创建的新对象
- 执行函数
- 如果构造器没有返回一个非空对象,就会返回这个新对象
三、原型 ( prototype )
-
js 中每个
对象
都一个内置属性 prototype(proto), 当我们通过引用对象的属性key 来获取一个value值时,他会触发get操作,这个操作会现在自身找是否有对应属性,如果没有就会通过这个内置属性 prototype 指向的对象上找 (这个内置属性只能用来查找) -
js 中每个
函数
有一个属性 prototype , -
但我们通过new 的方式创建出来的对象,他的prototype会指向他构造函数的内置属性【prototype】
function Pro(){
}
let obj= new Pro()
obj={}
obj.__proto__ = Pro.prototype
constructor 属性:
- 原型对象上有个属性 constrctor , 可以查看当前函数对象的指向
function Pro(){
}
let obj= new Pro()
console.log( obj._proto_.constructor )
console.log( Pro.prototype.constructor )
答 : js 中每个函数都有一个原型属性 prototype, js 中每个对象都有一个内置原型属性 prototype, 当通过new出来的对象他的内置属性prototype(proto)会指向该构造函数的prototype, 原型的优势就是:可以将公共的函数方法放在原型上,供new出来的对象共享
答 : 如果我们想获取一个对象的某个属性时,会先在本身找,找不到会他的原型上找,因为类似于一个链条,所以把这种查找方式称为原型链,原型链的最顶层的原型对象是 object的原型对象
四、构造函数的优势
封装:
可以将属性和方法封装到一个类中,这个过程叫做封装继承:
通过new构造出来的对象,在执行过程中其实每次都会开辟新的内存空间创建函数执行上下文, 特别费内存,可以将公共的函数方法放在原型上,让所有new出来的对象共享多态:
不同对象在执行时表现的不同状态
面向对象设计 OOD
- 我们在做功能时尽可能将需求拆分成能直接实现的小需求:高内聚,低耦合
- 高内聚:一个需求的所有功能和属性必须从属于一个主体(所有的功能和数据,尽可能从属于一个对象)
- 低耦合:减低功能之间的关系,每个功能可以独立使用或随时被替换 (功能尽可能拆分,依赖关系降到最低)
五、继承
1. 原型、原型链的继承
- 通过修改原型链实现继承 ,(假设构造函数一继承了构造函数二)
- 构造函数一继承的属性在打印时是看不到,因为是继承的是隐式原型 构造函数一new出的对象的proto 指向构造函数二 隐式原型打印时是看不到的
- 修改引用类型的值会互相影响
- 构造函数一在实现类的过程中是不能传参的
构造函数二
function Parent(msg) {
this.msg = msg;
}
Parent.prototype.init = function () {
console.log("哈哈哈哈");
};
构造函数一
function Child(msg) {
}
Child.prototype = new Parent() // 修改原型链
Parent.prototype = Child.prototype; // 修改原型
2. 借用构造函数继承
- 通过修改 this 指向实现继承
- 解决了原型原型链继承问题
- 缺点就是不能继承原型上的属性和方法
function Parent(msg) {
this.msg = msg;
this.show = function () {
console.log(this.msg);
};
}
Parent.prototype.init = function () {
console.log("哈哈哈哈");
};
function Child(msg) {
Parent.call(this, msg);
}
const C = new Child("hi");
C.show(); // c 就可以使用p的构造函数内的方法,
C.init(); // 但是他不能继承原型上的属性和方法 !!! 这就是继承的特点,
3. es6提供的继承方式
- 语法层面上的继承
- 但其实就是官方封装了方法
- 官方封装了 构造函数+ 原型链继承
// 定义 class 而不是之前的 function,
// 注意 属性和方法的写法
// 通过 extends 继承,可以使用 super 传递给被继承的
// 这是官方封装好的
class Parent {
constructor(msg) {
this.msg = msg;
}
show() {
console.log(this.msg);
}
}
class Child extends Parent {
constructor(m) {
super(m);
}
}
const P = new Parent("hello");
const C = new Child("hi");
你学废了吗?
😂 谢谢阅读,谢谢点赞并关注(没错我就要道德绑架你!)
原型链的弊端:
- 直接打印看不到这个属性,因为他的属性是保存在构造函数上的
- 这些属性会被多个对象共享,因为对象是一个引用类型,可能会造成问题
- 不能给构造函数传参,因为这个对象是一个性创建的(没办法定制化)