JavaScript对象有一个指向一个原型对象的链,当试图访问一个对象的属性的时候,他不仅仅会在该对象上面搜寻,还会搜寻该对象的原型,以及对象的原型的原型,依次层层搜索,直到找到名字匹配的属性或者到达原型链的末端

  1. // 让我们假设我们有一个对象 o, 其有自己的属性 a 和 b:
  2. // {a: 1, b: 2}
  3. // o 的 [[Prototype]] 有属性 b 和 c:
  4. // {b: 3, c: 4}
  5. // 最后, o.[[Prototype]].[[Prototype]] 是 null.
  6. // 这就是原型链的末尾,即 null,
  7. // 根据定义,null 没有[[Prototype]].
  8. // 综上,整个原型链如下:
  9. // {a:1, b:2} ---> {b:3, c:4} ---> null
  10. console.log(o.a); // 1
  11. // a是o的自身属性吗?是的,该属性的值为1
  12. console.log(o.b); // 2
  13. // b是o的自身属性吗?是的,该属性的值为2
  14. // 原型上也有一个'b'属性,但是它不会被访问到.这种情况称为"属性遮蔽 (property shadowing)"
  15. console.log(o.c); // 4
  16. // c是o的自身属性吗?不是,那看看原型上有没有
  17. // c是o.[[Prototype]]的属性吗?是的,该属性的值为4
  18. console.log(o.d); // undefined
  19. // d是o的自身属性吗?不是,那看看原型上有没有
  20. // d是o.[[Prototype]]的属性吗?不是,那看看它的原型上有没有
  21. // o.[[Prototype]].[[Prototype]] 为 null,停止搜索
  22. // 没有d属性,返回undefined

继承方法

当继承的函数被调用时,this 指向的是当前继承的对象,而不是继承的函数所在的原型对象。

  1. var o = {
  2. a: 2,
  3. m: function(){
  4. return this.a + 1;
  5. }
  6. };
  7. console.log(o.m()); // 3
  8. // 当调用 o.m 时,'this'指向了o.
  9. var p = Object.create(o);
  10. // p是一个继承自 o 的对象
  11. p.a = 4; // 创建 p 的自身属性 a
  12. console.log(p.m()); // 5
  13. // 调用 p.m 时, 'this'指向 p.
  14. // 又因为 p 继承 o 的 m 函数
  15. // 此时的'this.a' 即 p.a,即 p 的自身属性 'a'

使用不同的方法来创建对象和生成原型链

语法结构创建的对象

  1. var o = {a: 1};
  2. // o 这个对象继承了Object.prototype上面的所有属性
  3. // o 自身没有名为 hasOwnProperty 的属性
  4. // hasOwnProperty 是 Object.prototype 的属性
  5. // 因此 o 继承了 Object.prototype 的 hasOwnProperty
  6. // Object.prototype 的原型为 null
  7. // 原型链如下:
  8. // o ---> Object.prototype ---> null
  9. var a = ["yo", "whadup", "?"];
  10. // 数组都继承于 Array.prototype
  11. // (Array.prototype 中包含 indexOf, forEach等方法)
  12. // 原型链如下:
  13. // a ---> Array.prototype ---> Object.prototype ---> null
  14. function f(){
  15. return 2;
  16. }
  17. // 函数都继承于Function.prototype
  18. // (Function.prototype 中包含 call, bind等方法)
  19. // 原型链如下:
  20. // f ---> Function.prototype ---> Object.prototype ---> null

构造器创建的对象

在 JavaScript 中,构造器其实就是一个普通的函数。当使用 new 操作符 来作用这个函数时,它就可以被称为构造方法(构造函数)。

  1. function Graph() {
  2. this.vertices = [];
  3. this.edges = [];
  4. }
  5. Graph.prototype = {
  6. addVertex: function(v){
  7. this.vertices.push(v);
  8. }
  9. };
  10. var g = new Graph();
  11. // g是生成的对象,他的自身属性有'vertices'和'edges'.
  12. // 在g被实例化时,g.[[Prototype]]指向了Graph.prototype.

Object.create 创建的对象

ECMAScript 5 中引入了一个新方法:Object.create()。可以调用这个方法来创建一个新对象。新对象的原型就是调用 create 方法时传入的第一个参数:

  1. var a = {a: 1};
  2. // a ---> Object.prototype ---> null
  3. var b = Object.create(a);
  4. // b ---> a ---> Object.prototype ---> null
  5. console.log(b.a); // 1 (继承而来)
  6. var c = Object.create(b);
  7. // c ---> b ---> a ---> Object.prototype ---> null
  8. var d = Object.create(null);
  9. // d ---> null
  10. console.log(d.hasOwnProperty); // undefined, 因为d没有继承Object.prototype

class 关键字创建的对象

ECMAScript6 引入了一套新的关键字用来实现 class。使用基于类语言的开发人员会对这些结构感到熟悉,但它们是不同的。JavaScript 仍然基于原型。这些新的关键字包括 class, constructorstaticextendssuper

  1. "use strict";
  2. class Polygon {
  3. constructor(height, width) {
  4. this.height = height;
  5. this.width = width;
  6. console.log(height) //2
  7. }
  8. }
  9. class Square extends Polygon {
  10. constructor(sideLength) {
  11. super(sideLength, sideLength);
  12. }
  13. get area() {
  14. return this.height * this.width;
  15. }
  16. set sideLength(newLength) {
  17. this.height = newLength;
  18. this.width = newLength;
  19. }
  20. }
  21. var square = new Square(2);

性能

  1. function Graph() {
  2. this.vertices = [];
  3. this.edges = [];
  4. }
  5. Graph.prototype = {
  6. addVertex: function(v){
  7. this.vertices.push(v);
  8. }
  9. };
  10. var g = new Graph();
  11. console.log(g.hasOwnProperty('vertices'));
  12. // true
  13. console.log(g.hasOwnProperty('nope'));
  14. // false
  15. console.log(g.hasOwnProperty('addVertex'));
  16. // false
  17. console.log(g.__proto__.hasOwnProperty('addVertex'));
  18. // true

hasOwnProperty 是 JavaScript 中唯一处理属性并且不会遍历原型链的方法。

因此,当你执行:

  1. var o = new Foo();

JavaScript 实际上执行的是(或者大致这样):

  1. var o = new Object();
  2. o._proto_ = Foo.prototype;
  3. Foo.call(0)
  1. o.someProp;

它检查o是否具有someProp属性。

如果没有,它会查找 Object.getPrototypeOf(o).someProp

如果仍旧没有,它会继续查找 Object.getPrototypeOf(Object.getPrototypeOf(o)).someProp

ps:

Object.getPrototypeOf() 方法返回指定对象的原型(内部[[Prototype]]属性的值)。

  1. var proto = {};
  2. var obj = Object.create(proto);
  3. var a= Object.getPrototypeOf(obj)
  4. console.log(a); {}

如果觉得还不错,请访问MDN

JavaScript -- 继承与原型链的更多相关文章

  1. JavaScript继承与原型链

    对于那些熟悉基于类的面向对象语言(Java 或者 C++)的开发者来说,JavaScript 的语法是比较怪异的,这是由于 JavaScript 是一门动态语言,而且它没有类的概念( ES6 新增了c ...

  2. javascript继承之原型链(一)

    function Father() { this.fatherValue = "爸爸"; } Father.prototype.getFatherValue = function ...

  3. JavaScript之继承(原型链)

    JavaScript之继承(原型链) 我们知道继承是oo语言中不可缺少的一部分,对于JavaScript也是如此.一般的继承有两种方式:其一,接口继承,只继承方法的签名:其二,实现继承,继承实际的方法 ...

  4. JavaScript中的继承(原型链)

    一.原型链 ECMAScript中将原型链作为实现继承的主要方法,基本思想是利用原型让一个引用类型继承另一个引用类型的属性和方法. 实例1: function SupType() { this.pro ...

  5. 对Javascript 类、原型链、继承的理解

    一.序言   和其他面向对象的语言(如Java)不同,Javascript语言对类的实现和继承的实现没有标准的定义,而是将这些交给了程序员,让程序员更加灵活地(当然刚开始也更加头疼)去定义类,实现继承 ...

  6. 一篇JavaScript技术栈带你了解继承和原型链

    作者 | Jeskson 来源 | 达达前端小酒馆 1 在学习JavaScript中,我们知道它是一种灵活的语言,具有面向对象,函数式风格的编程模式,面向对象具有两点要记住,三大特性,六大原则. 那么 ...

  7. 关于JavaScript的原型继承与原型链

    在讨论原型继承之前,先回顾一下关于创建自定义类型的方式,这里推荐将构造函数和原型模式组合使用,通过构造函数来定义实例自己的属性,再通过原型来定义公共的方法和属性. 这样一来,每个实例都有自己的实例属性 ...

  8. 图解JavaScript中的原型链

    转自:http://www.jianshu.com/p/a81692ad5b5d typeof obj 和 obj instanceof Type 在JavaScript中,我们经常用typeof o ...

  9. JavaScript进阶之原型链

    对象 function f1(){ }; typeof f1 //"function"函数对象 var o1 = new f1(); typeof o1 //"objec ...

随机推荐

  1. 使用Gulp压缩HTML和CSS

    ---恢复内容开始--- 今天我么继续压缩,但是今天的压缩和之前的不同了!可以说是第二种方法吧! 今天用Gulp来压缩HTML和CSS! 1.首先我们先来安装GUlp:先安装全局gulp 2.然后是开 ...

  2. asp.net中<input type=button>无法调用后台函数

    例如:用<input id="bt1" type="button" runat="server" Onclick="btnL ...

  3. 采用C/C++语言如何实现复数抽象数据类型Complex

    记录一下! 采用C/C++语言如何实现复数抽象数据类型Complex #include <stdio.h> typedef struct Complex { double e1; // 实 ...

  4. learn OpenStack by picture

  5. 【转】dB的计算方法

    原文地址:https://www.espressif.com/zh-hans/media/blog/%E5%A2%9E%E7%9B%8A%E6%AF%94%E5%80%BC-db-%E4%BB%A5% ...

  6. 实现动态代理(Java和spring)

    一.Java实现动态代理 1.创建接口 package com.oyy.mw.biz.i; public interface Cal { public int add(int num1,int num ...

  7. 【Leetcode】【Easy】Plus One

    Given a non-negative number represented as an array of digits, plus one to the number. The digits ar ...

  8. SAP S4CRM 1811 服务订单API介绍

    Jerry在今年2月28日,SAP Customer Management for S/4HANA 1.0正式问世这个具有纪念意义的日子,同时发布了中英文版的博客进行介绍. 英文版发在SAP社区上,至 ...

  9. CSU计算机研究生推免

    考研复习 一开始,我是没有想到能够拿到研究生推免资格的,从今年3月份到整个暑假过完,一共6个月的时间,我一直在准备考研. 具体来说,我是在准备考研数学,整整6个月时间的数学复习,给我一种感觉,把大一大 ...

  10. POJ 3321 DFS序

    Apple Tree Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 30636   Accepted: 9162 Descr ...