什么是原型原型其实就是一个特殊的对象,在声明函数的时候自动创建的。<!– more –>比如,我们现在声明一个构造函数 A ,除了会申请保存函数的内存空间,还会额外申请一个内存空间,用于存储构造函数 A 的原型对象。所有函数中(Function.prototype.bind 除外)默认都有一个 prototype 的属性,它保存了函数的原型对象的地址(引用)(也就是它指向了原型对象)。而在原型对象中默认有一个 constructor 属性存储了构造函数的地址(引用)(也就是 constructor 指向了构造函数)。如果不理解上面所说的,那我们看下面的图:浏览器控制台中:_ proto _ 与 prototype刚开始接触原型的时候这两个东西很容易就搞混了。先记住以下两点,就很容易就区分了:prototype 是函数中才有的属性__proto__ 是所有对象都有的属性我们已经知道了函数中的 prototype 属性指向的是它的原型对象,那么对象中的 proto 代表什么?一般情况下,对象中的 proto 属性是指向它的构造函数的原型对象(prototype)的。用一段简单的代码:function A() {}var a = new A().png)上图看着不够简便,我们简化一下:还有一点,proto 不是一个规范属性,ie(除了 ie10) 不支持。对应的标准属性是 [[Prototype]] ,但是这个属性我们没法直接访问到。开发者尽量不要用这种方式去访问,因为操作不慎会改变这个对象的继承原型链。在使用 Object.create(参数) 方式创建对象时,对象的 proto 属性指向的是传入的参数。原型链由于 proto 是所有对象都具有的属性,而 proto 本身指向的原型(函数.prototype)也是一个对象,它也有 proto 属性。所以这样会形成由 proto 将对象和原型连起来的链条。这就是原型链。原型链的顶端是 Object.prototype(Object 是所有对象的祖宗) ,Object.prototype.__proto__的值为 null 。还是看之前的代码:function A() {}var a = new A()它的原型链如下:构造函数 A 其实也是一个对象。所有函数都是由 Function 函数构造的。(声明函数 function A() {} 等价于 var A = new Function()) 。所以所有函数的 proto 指向的都是 Function.prototype 。更新上图:Function 也是一个函数,它的 proto 指向的也是 Functon.prototype 即 Funtion.proto === Function.prototype。继更新上图:Object 同样是一个函数,所以 Object.proto === Function.prototype到了这里,我们应该可以看懂下面这张图了:原型的作用当 JS 引擎查找对象属性时,先查找对象本身是否存在该属性,如果不存在,会在对象的 proto 里找,还找不到就会沿着原型链一直找到原型链顶端(Object.prototype) 直到找到属性为止,最后在原型链顶端都没找到就返回 undefined 。由于上面的机制,原型的作用就很明显了——共享属性,节省内存空间。function Animal() { this.name = ‘动物’ this.eat = function() { console.log(‘在吃···’) }}var a1 = new Animal()var a2 = new Animal()console.log(a1.eat === a2.eat) // false// 每个对象的 eat 方法不是同一个,但方法类容一样,浪费内存使用 原型解决:function Animal(name) { this.name = ‘动物’}Animal.prototype.eat = function() { console.log(‘吃’)}var a1 = new A()var a2 = new A()console.log(a1.eat === a2.eat) //true// a1.eat 和 a2.eat 都同一个方法(Animal.prototype.eat)原型非常适合封装共享的方法。但是上面的代码把构造函数和原型分开写了。封装不到位。使用动态类型模式解决。function Animal() { this.name = ‘动物’ /* 判断 this.eat 是不是 函数类型, 如果不是,则表示是第一次创建对象或者调用 Animal 函数, 会将 eat 添加到原型中去。 如果是,则表示原型中存在了 eat 方法,不需要再添加。 */ if(typeof this.eat !== ‘function’) { Person.prototype.eat = function() { console.log(‘吃’) } }}var a = new Animal()a.eat()原型基于之前的共享属性和方法,是实现 JS 中继承的基础。与原型有关的方法hasOwnProperty()通过之前的学习,我们知道了去访问一个对象的属性时,会在原型链上查找。所以我们并不知道这个属性来自哪里。hasOwnProperty() 方法返回一个布尔值,可以判断一个属性是否来自对象本身。function Animal() {}Animal.prototype.name = ‘动物’var a = new Animal()a.age = 3console.log(a.hasOwnProperty(’name’)) // falseconsole.log(a.hasOwnProperty(‘age’) // truein 操作符in 操作符用返回一个布尔值,用来判断一个属性能否在对象上找到。在对象的原型链上找到也返回 true。function Animal() {}Animal.prototype.name = ‘动物’var a = new Animal()a.age = 3console.log(’name’ in a) // trueconsole.log(‘age’ in a) // trueconsole.log(‘sex’ in a) // false总结原型就是一个对象,声明函数就会创建原型对象prototype 只存在于函数中所有对象都有一个 proto 属性,它指向对象的构造函数的原型原型 也是对象,也有 proto 属性,proto 将对象和原型连接起来,形成原型链Object.prototype 是原型链的顶端访问对象的属性会沿着对象的原型链找下去原型可以共享属性和方法,是继承的基础阅读原文参考资料:https://juejin.im/post/5835853f570c35005e413b19https://blog.csdn.net/u012468376/article/details/53121081https://juejin.im/book/5bdc715fe51d454e755f75ef/section/5bed40d951882545f73004f6