理解JS的prototype
发布网友
发布时间:2024-10-03 22:10
我来回答
共1个回答
热心网友
时间:2024-11-18 10:24
起初学习前端时,我对JavaScript的prototype概念感到困惑。如今,当我深入理解了JavaScript之后,我将分享关于prototype的见解。
什么是prototype?JavaScript最初被设计为一种简单的网页脚本语言。在ES6之前,JavaScript没有Class的概念,所有的数据类型都是对象。为了实现实例对象的属性和方法共享,JavaScript为function引入了prototype的概念。prototype是一个对象。它是如何工作的呢?简单来说,JavaScript是一种基于原型的语言。当我们调用一个对象的属性时,如果对象没有该属性,JavaScript解释器就会从对象的原型对象上去寻找该属性,如果原型上也没有该属性,那就继续找原型的原型,直到最后返回null为止,null没有原型。这种属性查找的方式被称为原型链(prototype chain)。
当我们直接在控制台输出objA时,返回:
可以看出,该实例对象有3个属性,其中并没有methodB。这就是方法在构造函数内声明和在原型上声明的区别之一。将proto展开,发现mehtodB在这里。
Object.prototype的proto属性是一个访问器属性(一个getter函数和一个setter函数),它公开访问它的对象的内部[[Prototype]](对象或null)。proto的使用是有争议的,尽量不要使用。它从来没有被包括在EcmaScript语言规范中,但是现代浏览器实现了它。proto属性已在ECMAScript 6语言规范中标准化,用于确保Web浏览器的兼容性,因此它未来将被支持。它不赞成使用Object.getPrototypeOf / Reflect.getPrototypeOf和Object.setPrototypeOf / Reflect.setPrototypeOf(如果关注性能的话,应该避免设置对象的[[Prototype]]这样缓慢的操作)。
那么这样写有什么好处呢?现在我们再实例化一个objB对象出来:
和objA是不是长得一样,其实他们并不是相等的。
可以发现,methodA返回的是false,methodB是true。
把方法写在构造函数的内部,增加了通过构造函数初始化一个对象的成本(内存占用,因为两个实例对象就创建了两个一样的methodA),把方法写在prototype属性上就有效的减少了这种成本(它们指向了同一个methodB)。你也许会觉得,调用对象上的方法要比调用它的原型链上的方法快得多,其实并不是这样的,如果你的那个对象上面不是有很多层原型的话,它们的速度其实是差不多的。
从上面的例子可以看出,这种重复性的方法就可以写在原型中,当你的构造函数有相当多的方法,并且实例化也非常多时,提升是非常大的。在前端入门时必须掌握的一个框架就是jQuery,其实你每次调用$(“…”)时,都会返回一个实例化的新的jQuery对象出来(内部帮你执行了new方法,关于jQuery初始化这一段也是jQuery的精髓之一,实现的相当巧妙,有兴趣可以去看看),这样做既没有使实例对象私有属性相互影响(如上面的propA),又能共用方法(如上面的methodB)。
JavaScript 是基于原型的语言。想想我们是怎么创建新对象的:var obj = {}其实最终是通过var obj = new Object()创建的。是不是和上面的例子很像:通过new 构造函数 生成一个对象。当我们创建一个对象后,就可以通过“点”方法名的方式调用一些并不是我们手写的方法了,如obj.toString()。
其实我们调用的是Object.prototype.toString。现在是不是对JavaScript 是基于原型的语言这句话有些理解了。其实不止Object是这样的,Array、String、Number等都是这样的原理。
是不是很神奇,居然全等。想想这是为什么?还记得上面说的原型链吗?