什么是构造函数和类
- 构造函数与类其实是差不多的,说通俗点,类就是ES6版本的构造函数,而构造函数则是出现在ES6之前,ES5的类
- 虽然我这样说可能有些不标准,但是通俗点可以这样理解
构造函数与类的共同点
我上面也讲到了,构造函数和类差不多,所以他们之间的共同点也是蛮多的
- 构造函数与类都需要通过 new 来创建一个它们各自的实例对象
// 创建一个构造函数
function Con(x, y) {
this.x = x;
this.y = y;
}
// 在 Con 构造函数的原型上定义了一个 toStr 方法
Con.prototype.toStr = function() {
console.log('调用了toStr方法')
}
// 实例化 Con 构造函数
let obj = new Con()
等同于
// 创建一个类
class Fun {
// 在类的 constructor 方法上定义了
constructor(x, y) {
this.x = x;
this.y = y;
}
// 在 Con 类的内部定义了一个 toStr 方法
toStr() {
console.log('调用了toStr方法');
}
}
// 实例化 Con 类
let obj = new Con()
- 看到这,有些小伙伴可能会有疑惑,为啥构造函数的方法需要定义在原型上,而类的方法不需要呢?
- 因为定义在类内部的方法本身就在该类的原型上,别问我怎么知道的,因为我试过,不信看下面打印的结果:
// 这块代码是对应上面所定义的 Con 类
console.log(Con.toStr); // undefined
- 好,看到这里有些不懂的小伙伴可能又会问,你都没在方法后面加小括号,怎么可能会打印呢?
- 既然你这么真情实意的问了,那我便大发慈悲的告诉你,加了小括号会报错,不信看下面的代码:
console.log(Con.toStr()) // Uncaught TypeError: Fun.toStr is not a function
// 不信你自己去试试,试试就知道我说的对不对了,如果我说的对的话,请你狠狠的给我点个赞吧
- 上面说了类的方法即使是定义在类自己内部的,但却也是定义在原型上面的,因为只有通过原型去调用它,它才会打印
// 注意了,注意了,这段代码也是对应最上面所定义的 Con 类的
console.log(Con.prototype.toStr) // 打印 toStr 方法
// 注意了,如果你已经通过 new Con() 得出了一个实例类的话,就不能这样写了
console.log(obj.__proto__.toStr) // 打印 toStr 方法
// 这两个打印出来的都是一样的,所以我们将它们相比较你会发现,它们打印的是 true
console.log(Con.prototype.toStr === obj.__proto__.toStr) // true
注意:如果大伙觉得上下来回翻滚累的话,可以把最上面的类 copy 下来,放到你的编辑器里,这样方便阅读,如果是一个屏幕的小伙伴的话,第一步操作不变,copy 下来,然后 alt + tab 编辑器和文章之间来回切换
- 大伙注意哈,我上面那段代码中,通过 new 得出来的实例对象是没有 prototype 的,为什么呢,这你就要去问JavaScript的开发者了,我也不知道,反正它就是没有
- 但是呢,虽然没有
prototype
原型了,但是 new 出来的实例对象,它有一个__proto__
啊,__proto__
和prototype
本质上是一样的,它俩是全等的(这里看不懂的可以跳过) - 上面我们说了
obj.__proto__.toStr
===Con.prototype.toStr
,由此可得obj.__proto__
===Con.prototype
console.log(obj.__proto__ === Con.prototype) // true
-
既然已经说到这里了,那我就在给大家提一个注意点吧
-
虽然
obj.__proto__
===Con.prototype
,但是,它们俩里面的toStr
方法却不全等哦 -
obj
直接调用toStr
方法,得到的是toStr
方法,但Con
直接调用toStr
方法的话,得到的并不是toStr
方法
由上图可见,它俩既不全等,也不相等 -
但是,
obj.toStr
和Con.prototype.toStr
却是全等的哦 -
好,到了这里,有小伙伴就要疑惑了,为什么它俩会全等呢?
-
细心的小伙伴可能发现了,我上面说过类的方法虽然是定义在它内部的,但实则是在原型上的,既然是定义在原型上的,自然就需要通过
prototype
来调用了,否则怎么可能得到这个方法呢对吧 -
好,又有小伙伴会有疑惑,那为啥
obj
不需要通过__ptoto__
来调用呢? -
因为
obj
是Con
这个类new
出来的实例对象,类里面的属性和方法它自然也有,当然,我这样解释你们可能会听不太懂哈,通俗点就是,obj
包含了Con
这个类中所有的属性,以及Con
原型上的方法 -
也就是说,
obj
在某种情况下,和Con
是全等的 -
既然
obj
拥有toStr
, 还是从Con
身上得到的,那么两者的toStr
方法自然是一样的,既然是一样的,肯定是全等的
console.log(obj.toStr === Con.prototype.toStr) // true
console.log(obj.__proto__.toStr === Con.prototype.toStr) // true
上面代码块中的第二行是什么意思呢?
大家不要着急,我来给大家解惑
-
obj
是 通过new Con
得出来的实例对象是吧,那么我们暂时可以这样理解,obj === Con
,既然obj === Con
,那么就解释的通了,obj.__proto__ === Con.prototype
,Con
的原型上有toStr
这个方法,所以obj
的原型上自然也有toStr
这个方法了呀,所以可以通过obj.__proto__.toStr
来调用toStr
这个方法了 -
我上面说过,某种情况下,
obj
在某种情况下全等于Con
对吧,说的就是这种情况
console.log(obj.__proto__ === Con.prototype) // true
文章到这里也是接近尾声了,我在这里给大伙啰嗦两句吧,这是我的第一篇文章,我也不知道写的到底好不好,如果有不好或者不足的地方大伙可以在评论区提出来的,没关系的,当然,大伙如果觉得还可以的话,可以点点赞,收收藏啥的,对吧,毕竟谁会不喜欢自己的文章火呢
大伙可以加我一起交流哦,虽然我也不是很厉害