理解JS的prototype

理解JS的prototype

刚开始写前端那会儿,一直不太理解js的prototype。现在对js理解深入之后,来谈一谈prototype。

prototype是什么

JavaScript在设计之初,是作为一种网页脚本语言,没有设计得很复杂,这种语言只要能够完成一些简单操作就够了。Javascript里面所有的数据类型都是对象(object)。在ES6之前,js中是没有Class的概念的(ES6中的类也是语法糖,本质还是基于原型),为了实现实例对象的属性和方法共享,就给function设计了一个prototype的概念。
prototype是一个对象。他是如何工作的呢?
简单地说,JavaScript 是基于原型的语言。当我们调用一个对象的属性时,如果对象没有该属性,JavaScript 解释器就会从对象的原型对象上去找该属性,如果原型上也没有该属性,那就去找原型的原型,直到最后返回null为止,null没有原型。这种属性查找的方式被称为原型链(prototype chain)。

var TestPrototype = function () {
    this.propA = 1;
    this.methodA = function() {
        return this.propA;
    }
}

TestPrototype.prototype = {
    methodB: function() {
        return this.propA;
    }
}

var objA = new TestPrototype();

objA.methodA() // 1
objA.methodB() // 1

当我们直接在控制台输出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]]这样缓慢的操作)。
( Object.prototype.proto - JavaScript | MDN

那么这样写有什么好处呢?
现在我们再实例化一个objB对象出来:

var objB = new TestPrototype();


和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等都是这样的原理。

”JavaScript一切皆对象“


是不是很神奇,居然全等。想想这是为什么?还记得上面说的原型链吗?

编辑于 2020-03-22 11:32