什么是原型与原型链 红太狼 2021-11-05 14:02 274阅读 0赞 ## 前言 ## 此文参照了阮一峰大神在自己博客写的几篇关于JS继承原理的文章,在此直接放出连接: * [Javascript继承机制的设计思想][Javascript] * [Javascript 面向对象编程(一):封装][Javascript 1] * [Javascript面向对象编程(二):构造函数的继承][Javascript 2] * [Javascript面向对象编程(三):非构造函数的继承][Javascript 3] -------------------- ## JS一切皆是对象? ## JS中一切皆是对象吗?这句话其实是错的,首先从设计语言上来考虑,如果一切皆是对象,那就不会分这么多基础类型了,那为什么非对象类型的其他类型值可以调用对象API呢,这里就引出了JS设计核心之一的**原型与原型链** -------------------- ## 什么是原型(prototype) ## **1、** 要解决这个问题,就得清楚会设计原型(prototype)这个属性。 首先带来一个自阮一峰博客的例子 function DOG(name){ this.name = name; } 这里我们把他改成我们能理解的样子(有关this,详细请参阅[this的MDN docs][this_MDN docs]) function 狗(名字){ this.名字 = 名字; } 当我们运行new+“**狗**”,并填入“**名字**”时,我们就得到了一个狗对象的实例 第一只狗 = new 狗(大黄); 第一只狗.名字 //大黄 我们把“狗”称为“第一只狗”的**构造函数**(consturctor),而“第一只狗”称为"狗"对象的**实例** 所谓"构造函数",其实就是一个普通函数,但是内部使用了this变量。对构造函数使用new运算符,就能生成实例,并且this变量会绑定在实例对象上。 **2、** 但是,用构造函数生成实例对象,有一个缺点,那就是无法共享属性和方法。 比如,在“狗”对象的构造函数中,设置一个实例对象的共有属性“毛色”。 function 狗(名字){ this.名字 = 参数名字; this.毛色= "黄色" } 然后我们生成两个“狗”实例 第一只狗 = new 狗(大黄); 第二只狗 = new 狗(二黄); 第一只狗.毛色 //黄色 第二只狗.毛色 //黄色 这两个对象的“毛色”属性是独立的,修改其中一个,不会影响到另一个,每一个实例对象,都有自己的属性和方法的副本,这不仅无法做到数据共享,也是极大的资源浪费。 //这里把第一只狗的毛色修改成黑色 第一只狗.毛色= "黑色" console.log(第二只狗.毛色); //黄色 //这里可以看到第二支狗的毛色依然是黄色 **3、** 根据这一点,才有了如今的prototype属性,prototype属性是一个对象,里面包含了所有需要共享的属性和方法,而不需要共享的属性和方法,则放在构造函数里。 实例对象一旦创建,将自动引用prototype对象的属性和方法。也就是说,实例对象的属性和方法,分成两种,一种是本地的,另一种是引用的。 下面通过设置“狗”.prototype属性来改写之前的例子 function 狗(名字){ this.名字 = 名字; } 狗.prototype = {"毛色" = "黄色"} 第一只狗 = new 狗(大黄); 第二只狗 = new 狗(二黄); console.log(第一只狗.毛色) // 黄色 console.log(第二只狗.毛色) // 黄色 如果现在对狗.prototype进行修改,则第一只狗和第二只狗的毛色会一起发生变化 狗.prototype = {"毛色" = "黑色"} console.log(第一只狗.毛色) // 黑色 console.log(第二只狗.毛色) // 黑色 -------------------- ## 什么是原型链 ## 1、 无论是什么类型的值,在实例化之后都会带有一个"\_ \_ proto\_ *“的属性,该属性指向其继承而来的上一级的prototype,在此把”* \_ proto\_ \_"称为子原型,prototype称为父原型。 下面以实例化的数字“1”为例 var num = 1; // num.__proto__ === Number().prototype; num.__proto__.__proto__ === Number().prototype.__proto__ === Object.prototype num.__proto__.__proto__.__proto__ === Number().prototype.__proto__ === Object.prototype.__proto__ === null 从以上例子可以看出,由于Object.prototype.\_\_ proto \_\_ 的值为null,意味着Object.prototype没有相对的父原型来继承,所以Object.prototype可以认为是最顶级的父原型,所有的子原型都继承于Object.prototype,我们这种子原型引用父原型的关系,称之为**原型链**。 因为Object.prototype是最顶级的父原型,所有类型的值都能调用或者临时调用其存储的方法和属性,所以才有“JS一切皆是对象”的说法,其实这种说法是完全错误的,比较严谨的说法应该是“JS内一切类型的数值都能视为对象”。 -------------------- [Javascript]: http://www.ruanyifeng.com/blog/2011/06/designing_ideas_of_inheritance_mechanism_in_javascript.html [Javascript 1]: http://www.ruanyifeng.com/blog/2010/05/object-oriented_javascript_encapsulation.html [Javascript 2]: http://www.ruanyifeng.com/blog/2010/05/object-oriented_javascript_inheritance.html [Javascript 3]: http://www.ruanyifeng.com/blog/2010/05/object-oriented_javascript_inheritance_continued.html [this_MDN docs]: https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/this
还没有评论,来说两句吧...