哇哦~今天迎来的是掘金后台编写文章的新页面,不知道这个页面是须要经过写文章才能打开的,仍是新上的啊哈哈啊哈javascript
其实本身平时在总结上是很是注重的,可是通常是总结的比较随意,会存放在本身的笔记软件中,推荐使用“语雀”,划分目录和页面的美观交互深得我心,固然,适合本身的一个笔记软件才是最重要的;接下来的半个月内,我也将从新回顾本身总结的知识点和项目中遇到的困难点,并整理到掘金文章中html
谈起对象,实际上是一个很需的概念,在大学课程java
学习中就留下了一个很是清晰的词语“面向对象”编程,对于对象而言,不只仅是去建立、去继承,与之相呼应的还有一些理论性的名词,这些名词在javascript
中多是不全体现的,更多体如今java语言程序中;java
我忽然想起大学考试卷子填写概念的场景了 🤯🤯🤯typescript
所谓对象,本质上就是指事物(包括人和物)在程序设计语言中的表现形式。这里的事物能够是任何的东西(如客观存在的对象,或者较为抽象的概念);
好比 小狗,咱们将其理解成对象,它是具备某些明确的特征的(体重、颜色、名字等),除此以外,还可以执行某些动做(汪汪叫、吃饭、睡觉等),在javascript
语言中这些明确的某些特征就是属性
,可以执行的行为就是方法
。编程
类就是具有某些共同特征的实体的集合,它是一种抽象的数据类型,它是对所具备相同特征实体的抽象。在面向对象的程序设计语言中,类是对一类“事物”的属性与行为的抽象。
好比:“老人”、“儿童”、“青年“、“中年人“是关于人的年龄层段的划分,他们的共有的某些特征,其实能够抽成“人”,segmentfault
在传统的OOP环境中,继承一般指的是类与类之间的关系,但因为javascript
中不存在类,所以它的继承只能发生在对象之间;
当一个对象继承自另外一个对象时,一般会往其中加入新的方法,以扩展被继承的老对象。一般将这一过程称之为“B继承自A”或“B扩展自A”。另外对于新对象来讲,它能够根据本身的须要,从继承的那组方法中选择几个来从新定义。这样作并不会改变对象的接口,由于其方法名是相同的,只不过当调用新对象时,该方法的行为与以前不一样了markdown
封装主要用于阐述对象中所包含的内容。封装概念一般由两部分组成:app
封装的目的是将信息隐藏,即方法与属性的可见性。通常而言,封装包括封装数据和封装实现 在许多语言的对象系统中,封装数据是由语法解析来实现的,这些语言提供了public、private、protected
这些关键字来限定方法和属性的可见性,这种限定分类定义了对象用户所能访问的层次; 但javascript
并无提供对这些关键字的支持,只能依赖变量的做用域来实现封装特性, 并且只能模拟出 public 和 private
这两种封装性。除了ECMAScript6
中提供的let以外,通常经过函数来建立做用域:不过typescript就另当别论了;ide
多态的实际含义是:同一个操做做用于不一样的对象上面,能够产生不一样的解释和不一样的执行结果。换句话说,给不一样的对象发送同一个消息的时候,这些对象会根据这个信息分别给出不一样的反馈; 本身停留理解不够深入,就不班门弄斧了,直接推荐连接阅读函数
javascript
的继承方式也有不少种,平常经常使用的方法也是很是多,而且不少书籍中,也有介绍继承的方法,本文参考《javascript 高级程序设计(第三版)》
在咱们了解的JavaScript
中,对于原型链的使用是很是多的,被建立的对象能够经过原型链访问上级的对象,而原型链继承的方式正式运用了此访问关系;
function Super() {
this.value = true;
}
Super.prototype.getValue = function () {
return this.value;
}
function Sub() { }
console.log("super", new Super())
//Sub继承super
Sub.prototype = new Super();
//将sub的构造函数指向 Sub
Sub.prototype.constructor = Sub;
//建立实例
var instance = new Sub();
console.log('sub', instance)
console.log(instance.getValue())
复制代码
而sub
、Super
以及instance
之间关系是:
原型链最主要的问题在于包含引用类型值的原型属性会被全部实例共享,而这也正是为何要在构造函数中,而不是在原型对象中定义属性的缘由。 在经过原型来实现继承时,原型实际上会变成另外一个类型的实例。因而,原先的实例属性也就瓜熟蒂落地变成了如今的原型属性了;
构造函数包含引用类型
function Super1() {
this.colors = ['red', 'blue', 'green'];
}
function Sub1() { };
//Sub继承了Super
Sub1.prototype = new Super1();
var instance1 = new Sub1();
//查看instance1中的属性
console.log('instance1',instance1)
instance1.colors.push('black');
console.log('instance1.colors',instance1.colors);//'red,blue,green,black'
var instance2 = new Sub1();
console.log('instance2 经过Sub1构造出来的',instance2.colors);//'red,blue,green,black'
复制代码
借助原型能够基于已有的对象来建立新对象,同时没必要所以建立自定义类型;
具体的实现方式;
function object(o) {
function F() { };
F.prototype = o;
return new F();
}
var superObj = {
init: function (value) {
this.value = value;
},
getValue: function () {
return this.value;
}
}
var subObj = object(superObj);
console.log('subObj',subObj)
subObj.init('sub');
console.log('subObj.getValue',subObj.getValue());//'sub'
复制代码
与原型链继承的关系;它们的一个重要区别是父类型的实例对象再也不做为子类型的原型对象
; 这种方式更相似于Object.create()
的实现
function Super(){
this.value = 1;
}
Super.prototype.value = 0;
function Sub(){};
Sub.prototype = Object.create(Super.prototype);
Sub.prototype.constructor = Sub;
//建立子类型的实例对象
var instance = new Sub;
console.log(instance.value);//0
复制代码
function F(){};
F.prototype = Super.prototype;
Sub.prototype = new F();
复制代码
由上面代码看出,子类的原型对象是临时类F的实例对象,而临时类F的原型对象又指向父类的原型对象;因此,实际上,子类能够继承父类的原型上的属性,但不能够继承父类的实例上的属性
; 原型继承和原型链继承都是共享父例引用类型的值;
function object(o) {
function F() { };
F.prototype = o;
return new F();
}
var superObj = {
colors: ['red', 'blue', 'green']
};
var subObj1 = object(superObj);
subObj1.colors.push("black");
var subObj2 = object(superObj);
subObj2.colors.push("white");
console.log('superObj.colors',superObj.colors);
console.log('subObj1.colors',subObj1.colors);
复制代码
借用构造函数,很是深入明了了,实际上是借助super的属性,即在子类型构造函数的内部调用超类型构造函数,经过使用apply()和call()方法在新建立的对象上执行构造函数;
//借用构造函数
function Super2() {
console.log("Super2执行了")
this.colors = ['red', 'blue', 'green'];
}
function Sub2() {
//继承了Super
Super2.call(this);
}
var instance2 = new Sub2();
instance2.colors.push('black');
console.log('instance2.colors',instance2.colors);// ['red','blue','green','black']
var instance3 = new Sub2();
console.log('instance3.colors',instance3.colors);// ['red','blue','green']
复制代码
此时咱们的引用类型也不会存在冲突啦,这个主要的缘由仍是由于当咱们Sub2中执行的时候,Super2
的当前执行做用域在Sub2中,造成了内部的变量关系;
Super2
中的原型上的方法是没法继续使用的借用构造函数可以帮助咱们解决对象引用
问题,原型链继承可以帮助咱们解决调用原型方法问题,若是将这两种方式组合在一块儿;岂不美哉~ 原型链继承+借用构造函数继承=既能够获取构造函数中的方法,也可以断引用;
组合继承(combination inheritance)
有时也叫伪经典继承,指的是将原型链和借用构造函数的技术组合到一块,从而发挥两者之长的一种继承模式。其背后的思路是使用原型链实现对原型属性和方法的继承,而经过借用构造函数来实现对实例属性的继承。这样,既经过在原型上定义方法实现了函数复用,又可以保证每一个实例都有它本身的属性;
var count = 0; //用于计数
function Super(name) {
console.log('Super==count',count++)
this.name = name;
this.colors = ['red', 'blue', 'green'];
}
Super.prototype.sayName = function () {
console.log('Super==this.name',this.name);
};
function Sub(name, age) {
console.log('Sub==count',count++)
// 第二次调用Super(),Sub.prototype又获得了name和colors两个属性,并对上次获得的属性值进行了覆盖
Super.call(this, name);
this.age = age;
}
//继承方法
// 第一次调用Super(),Sub.prototype获得了name和colors两个属性
Sub.prototype = new Super();
Sub.prototype.constructor = Sub;
Sub.prototype.sayAge = function () {
console.log('Sub===this.age',this.age);
}
var instance1 = new Sub("bai", 29);
instance1.colors.push("black");
console.log('instance1.colors',instance1.colors);//['red','blue','green','black']
instance1.sayName();//"bai"
instance1.sayAge();//29
console.log('Super',new Super())
复制代码
Super
中引用类型数据独立Super
中传入自定义的参数Super
调用次数问题,继承时候调用一次,实例化Sub
后再次调用了Super
Sub
的时候都会调用Super.call
寄生组合式继承带来的影响须要调用两次Super。寄生组合式继承与组合继承类似,都是经过借用构造函数来继承不可共享的属性,经过原型链的混成形式来继承方法和可共享的属性。只不过把原型继承的形式变成了寄生式继承。使用寄生组合式继承能够没必要为了指定子类型的原型而调用父类型的构造函数
寄生式继承
只继承了父类型的原型属性,而父类型的实例属性是经过借用构造函数的方式来获得的;也就是 咱们借用Super
的构造函数,可是去复制Super
的原型函数;
function Super(name) {
console.log("Super === 执行")
this.name = name;
this.colors = ["red", "blue", "green"];
}
Super.prototype.sayName = function () {
console.log("this.name",this.name)
return this.name;
};
function Sub(name, age) {
//第一次 借用构造函数
Super.call(this, name);
this.age = age;
}
//继承的方法 就是拷贝原型
if (!Object.create) {
Object.create = function (proto) {
function F() { };
F.prototype = proto;
return new F();
}
}
// 利用复制原型的方式进行操做 将Super.prototype的原型方法经过实例化给Sub
Sub.prototype = Object.create(Super.prototype);
Sub.prototype.constructor = Sub;
var instance1 = new Sub("bai", 29);
instance1.colors.push("black");
console.log('instance1.colors',instance1.colors);//['red','blue','green','black']
instance1.sayName();//"bai"
var instance2 = new Super("hu", 27);
console.log("instance2.colors",instance2.colors);//['red','blue','green']
instance2.sayName();//"hu"
复制代码
这三者的链式关系
ps:很久以前整理的,查过不少文档博客内容,可是没有一一记录下来,我仍是很尊重知识来源的的🥳🥳