欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

一文搞定js的原型对象

程序员文章站 2024-03-13 10:43:51
...

js是一门面向对象语言,但是它并不是一门真正面向对象的语言。与完备面向对象语言java、c#的区别是没有类的概念(ES6之后新出现的类是一种语法糖),而是利用原型对象来实现面向对象继承的功能,那么原型对象到底是什么东西呢?没有类js是怎么实现的继承呢?下文就一步步的来搞定这个问题。

js对象

在java中,新建对象需要先新建类,然后通过 new 类 来得到对象,继承利用类来来实现,而js则是完全通过对象来实现的。

由于js在设计之初考虑其应用场景并没有设计太过复杂,所以没有原生 类 的概念。但是在使用中面向对象思想利于开发, 因此js之父利用其他方式实现了面对对象,也就是我们提到的原型对象

js中定义一个对象有不同的方式,最简单的就是字面量定义,如下:

	var person = {
		name = "alex",
		age = 3,
	}
	console.log(person)

除了这种方式,js还支持利用 new 关键字 来定义一个对象,等等,上边不是说 js 没有类的概念吗,那 去new 谁呢 ?

实际上 javac#在执行 new class也就是new 类来新建一个对象时其实执行的是类的构造函数,所以js之父设计了一种利用构造函数新建对象的方法,如下:

function person (name){
	this.name = name
}
var p1 = new person("alex");
console.log(p.name)

一文搞定js的原型对象
new的目标就是 构造函数构造函数和普通函数几乎完全相同,唯一区别就是多了 this, this指向了将要新建的实例,利用刚才的person 构造函数 其中this 指向了后来新建的 p1 实例。

上述 通过 new 构造函数 person 得到的对象 p ,如果我们想要新建一个 p2 那么可以执行:

p2 = new person("tom");
console.log(p2.name);

现在可以得到两个对象 p1 p2 ,我们都知道 对象是由属性和方法组成的,现在构造函数中只定义 name 属性,没有方法,如果我们想定义一个 sayName方法,我们可以修改 构造函数:

function person (name){
	this.name = name;
	this.sayName = function(){
		console.log("my name is ",this.name)
	}
}
var p1 = new person("alex");
var p2 = new person("alex");
p1.sayName();
p1.sayName();

在构造函数上新增方法能够实现对象的公共方法,但是却会造成内存浪费,因为生成的每个对象的 sayName方法是相同的,每个对象都拥有了一份相同代码。

能不能把相同公共的方法从每个对象中提取出来呢?答案是可以。

原型对象

在每个js对象中都有一个 prototype 属性 (在谷歌浏览器中表现为_proto_),该属性指向一个对象,也就是我们常说的原型对象
一文搞定js的原型对象
上图中的 Object 就是 原型对像,每个实例对象都指向同一个原型对象。
一文搞定js的原型对象
那么我们就可以将一些公共方法放在原型对象上了,只要在实例对象上定义一次,其他实例对象也可以使用该方法,如下

p1.__proto__.sayHello = function(){
	console.log("hello");
}
p1.sayHello();
p2.sayHello();

一文搞定js的原型对象
说明 实例对象 p1 和 p2 只存放了 对 sayHello的 指针,并没有复制 sayHello方法,解决上述内存占用过多的问题。(其实 存放指针这一说法并不准确,应该是向上查找,这里暂时这样理解)
一文搞定js的原型对象
在上图我们也可以直接看到 sayHello方法确实加到了实例对像 p1 的原型对象上。

从上图我们还可以看出,实例对象p1的原型对象中处理自定义的 sayHello方法还有一个 constructor属性,而且可以看到 它指向了我们之前定义的person构造函数。你可能会疑惑,这绕来绕去的是为了什么呢?其实就是为了下面将要提到的继承。

为了更好的理解,这里用一张图表示 实例对象原型对象构造函数之间的关系。
一文搞定js的原型对象
通过这张图,能很清晰看出三者关系:构造函数 new 出来实例对象,实例对象的prototype属性指向一个原型对象,原型对象的constructor属性又指向构造函数,三者形成一个闭环

面向对象语言的三个特点是:封装、继承和多态 ,那么js如何实现呢?

继承

js的继承并非像 java 语法上利用 extends 关键字就能简单的实现。
其实在上文中我们增加 实例对象p1 的原型对象的 sayHello 方法后 实例对象p2 就能调用该方法,这就变相实现了一种继承。

//todo 待续

封装

自执行函数