一文搞定js的原型对象

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)

在这里插入图片描述
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_),该属性指向一个对象,也就是我们常说的原型对象
在这里插入图片描述
上图中的 Object 就是 原型对像,每个实例对象都指向同一个原型对象。
在这里插入图片描述
那么我们就可以将一些公共方法放在原型对象上了,只要在实例对象上定义一次,其他实例对象也可以使用该方法,如下

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

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

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

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

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

继承

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

//todo 待续

封装

自执行函数

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值