js作为一种基于对象的弱类型脚本语言,在前后端分离的今天担任着不可或缺的一部分任务,随着前端的发展,越来复杂的逻辑,让前端程序猿们不再满足于这种基于对象的编程方式,这时候js基于原型链的一种面向对象的实现方法被越来越多的人所采纳
js基于对象而不是面向对象
js是一种基于对象的语言,所谓基于对象,简单来说就是在js中有对象的概念,但是没有类的概念,学过java的人都知道,在java中,要创建一个对象实例,首先需要一个有一个这个对象的类,用类去创建这个类的对象实例,而基于对象则是用对象去创建对象。举个网上的例子:
-
面向对象就是先设计一个房子的图纸,然后按照图纸的设计去建造一个房子
-
基于对象就是先建造一个房子,然后根据已有的房子的样子再去建造一个房子
也就是说:
-
面向对象: 先有一个对象的抽象描述(类),然后根据这个类去构建一个新的对象
-
基于对象:现有一个具体对象,然后根据这个具体的对象,去创建一个新的对象
由此看来js中的所有对象都是同一个对象的子对象。
面向对象的三大基本特征:封装,多态,继承,然而基于对象和面向对象最大的区别也在这里,基于对象虽然也使用了对象,但是无法利用现有对象模板产生新的对象类型,产生新的对象,所以就没有继承这一说,没有继承也就没有多态了。
多态体现的就是继承,一般体现在抽象类上。js语言基于对象,它封装了一些对象,调用对象的方法,设置对象的属性,但是没办法产生新的类,只能使用现有的对象的方法和属性。
原型链
我们在js中创建一个对象的时候,会使用new关键字,他具体做了什么事情呢,其实他就干了三件事
-
- 创建一个空对象:
var obj = {}
- 创建一个空对象:
-
- 使这个空对象的_proto_指向基函数prototype :
obj._proto_ = Basr.prototype
- 使这个空对象的_proto_指向基函数prototype :
-
- 将基函数的this指向改为新的对象:
Base.call(obj)
- 将基函数的this指向改为新的对象:
其实,所有的函数都是 Function 的实例。在构造函数上都有一个原型属性 prototype,该属性也是一个对象;那么在原型对象上有一个 constructor 属性,该属性指向的就是构造函数;而实例对象上有一个 proto 属性,该属性也指向原型对象,并且该属性不是标准属性,不可以用在编程中,该属性用于浏览器内部使用。
// _proto_
在函数里有一个属性prototype
由该函数创建的对象默认会连接到该属性上
//prototype 与 _proto_ 的关系
_proto_是站在对象角度来说的
prototype 是站在构造函数角度来说的
所谓原型链就是有限的实例对象和原型之间组成有限链,就是用来实现共享属性和继承的。一个对象有原型对象,原型对象也有一个原型对象,一个对象的末级原型对象也就是Object的原型对象是null。
// 原型链示例
7 var arr = [];
8 arr -> Array.prototype ->Object.prototype -> null
9 var o = new Object();
10 o -> Object.prototype -> null;
js面向对象
es5面向对象继承实现:
function Animal() { }
function Dog() { }
Object.defineProperties(Animal.prototype, {
name: {
value() {
return 'Animal';
}
},
say: {
value() {
return `I ' m ${this.name()}`
}
}
})
Dog.prototype = Object.create(Animal.prototype);
console.log(new Dog().say()); // 输出 I'm Animal
多态就是子类重写父类方法
function Animal() { }
function Dog() { }
Object.defineProperties(Animal.prototype, {
name: {
value() {
return 'Animal';
}
},
say: {
value() {
return `I ' m ${this.name()}`
}
}
})
Dog.prototype = Object.create(Animal.prototype, {
name: {
value() {
return 'Lucy';
}
}
});
console.log(new Dog().say()); // 输出 I'm Lucy
在es6中提供了语法糖 ,一定程度上简化了继承与多态的实现:
class Person {
say() {
console.log('我姓' + this.xs);
}
}
class PersonZ extends Person {
xs = '张';
}
new PersonZ().say(); // 输出 我姓张