谈谈Js中的原型

原型是作为一个前端开发必需掌握的基础知识,顺便给大家推荐一本书《js高级程序设计》,它对js这门语言的介绍非常详细,这本书不论是对初级前端还是中级前端,都值得反复研读,它可以让你对js这门语言有更深层次的理解。话不多说,下面给大家说说我对原型的理解。

原型

在js中,几乎万物皆对象。首先用一个例子来区别一般对象和与作为函数的对象(也是对象)。

var str = new String('mario');
console.dir(str);

一般对象继承__proto__的是对象(str继承的是String对象),而函数的对象继承__proto__的是函数(String()继承的是一个特殊的匿名函数。虽然函数也是对象),但只有函数才有原型prototype属性,供它实例的对象继承,也就是说str.__proto__ === String.prototype(其中String是构造函数)。
先给个结论让大家带着疑问往下看。
上图中:字符串对象的长度是5,初始值是“mario”,继承于String对象;这个String对象包含了我们熟知的大部分方法和属性如:
charAt(),charCodeAt()……

再看String对象的属性和方法也包含一个constructor和__proto__属性,其中__proto__又指向Object对象,constructor指向的是 构造函数function String(){};

咱接着上边继续往下看,__proto__指向的Object对象中没有__proto__属性,说明这个Object对象已经是继承的终点,所有的对象最终都会继承于它。

而 函数String() 的__proto__指向的是 function(){}(一开始提到的一个特殊的匿名函数,出现了!)

我们看到匿名函数,创建它的构造函数是fuction Function(){};不要小看这个构造函数,它是特殊的匿名函数function(){}以自己为原型和继承自己的属性创造的(就像女娲按照自己的样子和能力,创造了第一个人类,其他的人类的原型都是这个人,这个人我们简称始祖吧,只有简单的属性和方法)

所有的函数都继承于这个特殊匿名函数,都有个原型,供它的实例对象继承,而这个原型又继承于终极的Object对象。

  • 结论:

1.JS在创建对象(不论是普通对象还是函数对象)的时候,都有一个叫做__proto__ 的内置属性,用于指向创建它的构造函数的原型对象。而每个函数对象都有一个prototype 属性(函数对象特有的属性),这个属性指向函数的原型对象。
2.JS中对象继承__proto__的是对象,函数继承__proto__的是函数(函数也是对象),但是只有函数才有原型prototype属性供它实例的对象继承。

这就是为什么str.__proto__ === String.prototype的原因。(普通对象可以通过__proto__访问原型对象,而构造函数创建的对象通过__proto__访问原型对象。函数通过prototype访问原型对象)

原型链

这是由原型衍生的一个概念。简单来说,在js中,凡是对象就有原型,原型又是对象,因此凡是定义的一个对象,那么就可以找到它的原型,原型还有原型,那么如此下去就构成了一个对象的序列,称该结构为原型链。下图为一个完整原型链。

原型式继承

每一个构造函数都有prototype属性,通过构造函数创建出来的对象都继承自该原型属性。所以可以通过更改构造函数的原型属性来实现继承。

属性搜索原则

所谓属性搜索原则也就是属性的查找顺序,在访问对象成员的时候,会遵循如下原则

  • 首先在当前对象中查找,如果找到,停止查找并使用。没有找到则继续下一步
  • 在对象的原型中查找,如果找到,停止查找并使用。没有找到则继续下一步
  • 在该对象的原型的原型查找,如果找到,停止查找并使用。没有找到则继续下一步
  • 继续往上查找,直到查找到Object. prototype还没找到,那么是属性就返回undefined,是方法就报错 xxx is not a function
    (要究其原因,得聊到js的作用域和执行环境,我会单独发一篇博客专门来讲解)
    如果我们在实例中添加了一个属性,而该属性与实例原型中的一个属性同名,那实例中的属性会屏蔽掉原型中的同名属性,但不会修改那个属性。如下图:

原型与in操作符

in操作符两种使用方式:
1.单独在for-in循环中使用。
2.在通过对象能够访问给定属性时返回true,无论该属性存在于实例中还是原型中。

第二条使用规则,可以让我们加上hasOwnProperty()方法来确定属性存在于实例中还是原型中(hasOwnProperty()只在属性存在于实例中才返回true)。

小结

原型是理解js面向对象的基础,至此,原型已介绍完毕。