javascript prototype

最近在学习javascript,javascript是原型继承,原型继承和普通的类、对象这种继承模型相比更容易让人迷惑。这个文章记录一下我的javascript原型继承的解惑过程。
为了方便叙述,我是用a–>b来表示a继承了b(下面也称作原型链)。
在理解原型继承时,一定要强化一个观点:在javascript里,一切皆是对象。

javascript中的原型继承

function F1(){}
function F2(){}
function F3(){}
F2.prototype=Object.create(F1.prototype);
F3.prototype=Object.create(F2.prototype);
var f3 = new F3();

javascript里的原型继承是这个样子的,在上述的代码里可以有继承关系:
f3–>F3.prototype–>F2.prototype–>F1.prototype–>…

上述链上的节点都是对象,当需要访问f3的某个属性时,就从左向右在这条链上寻找,知道找到或者节点为空。
这里要注意一点节点上的是对象,而并不是F1、F2、F3的方法(即使方法也是对象)。

正常的原型继承

上述javascript里的原型继承是畸形的,下面会给出一个正常的原型继承,首先说明几点:
1.万物皆对象,javascript里没有类的概念,所以继承是对象继承对象。
2.原型继承链,其实就是一个链表的结构,有个引用指向它继承的对象就可以了。javascript里对象有一个属性_proto_就是这个作用。需要注意的是,这个对象并不是标准规定的,但多数情况下都有可以访问到,所以不要在开发时使用_proto_

var v1 = {}
var v2 = {}
var v3 = {}
v3.__proto__=v2;
v2.__proto__=v1;

在这个例子中的继承关系是:
v3–>v2–>v1–>…
所以一个对象,它的继承关系,就是_proto_的引用链。

new 构造方法

首先,构造方法就是一个普通的方法。只是一个方法前面是new时,它就成了F构造方法,作为构造方法被调用和作为普通方法被调用有些差别。
new F(arguments…),调用构造方法,会做下面三个事情:

  • 生成一个空的对象,让后让该对象的proto属性指向F.prototype。
  • 让该对象作为上下文(this)调用F方法。
  • 返回该对象。

下面例子模拟一个new操作符:

function New(f) {
    var n = { '__proto__': f.prototype };
    return function() {
        f.apply(n, arguments);
        return n;
    };
}

function Point(x, y) {
    this.x = x;
    this.y = y;
}

Point.prototype = {
    print: function() { console.log(this.x, this.y); }
};

var p1 = new Point(10, 20);
p1.print(); // 10 20
console.log(p1 instanceof Point); // true

var p2 = New(Point)(10, 20);
p2.print(); // 10 20
console.log(p2 instanceof Point); // true

Object.create()

The Object.create() method creates a new object with the specified prototype object and properties.

在第一个例子中使用了这个方法,该方法的作用是返回一个对象,返回的对象继承自第一个参数。

下面这个例子模仿Object.create()的功能:

Object.create = function (parent) {
  return { '__proto__': parent };
};

var Point = {
  x: 0,
  y: 0,
  print: function () { console.log(this.x, this.y); }
};

var p = Object.create(Point);
p.x = 10;
p.y = 20;
p.print(); // 10 20

Object.getPrototypeOf()

The Object.getPrototypeOf() method returns the prototype (i.e. the value of the internal [[Prototype]] property) of the specified object.

可以理解为返回_proto_

instanceof

instanceof 运算符用来测试一个对象在其原型链中是否存在一个构造函数的 prototype 属性。

// 定义构造函数
function C(){} 
function D(){} 

var o = new C();

// true,因为 Object.getPrototypeOf(o) === C.prototype
o instanceof C; 

// false,因为 D.prototype不在o的原型链上
o instanceof D; 

o instanceof Object; // true,因为Object.prototype.isPrototypeOf(o)返回true
C.prototype instanceof Object // true,同上

C.prototype = {};
var o2 = new C();

o2 instanceof C; // true

o instanceof C; // false,C.prototype指向了一个空对象,这个空对象不在o的原型链上.

D.prototype = new C(); // 继承
var o3 = new D();
o3 instanceof D; // true
o3 instanceof C; // true

理解一下为什么最后一行是true。o3 instanceof C;就是判断o3的原型链中是否包含C.prototype。经过上面的代码后o3的原型链是这样的。

o3–>D.prototype(=new C())–>C.prototype

总结

  • 1.继承关系根据__proto__链上的对象查找。在new完对象以后,可能会改变链中对象的引用关系,判断时要弄清楚当前运行链中的引用关系。
  • 2.调用构造方法时,把__proto__的值赋成方法的prototype属性。
  • 3.原型链上都是对象,在javascript里多数会是Function.prototype,要搞明白对象和方法的关系。

参考

Javascript – How Prototypal Inheritance really works
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/instanceof
Javascript继承机制的设计思想

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值