JS-prototype

由于ES6之前的JavaScript不支持类(class),所以我们通过其他方式来模拟面向对象编程。

定义类对象(Object)

// constructor,ES6提供有新的定义类的方法
function MyClass(field1,...) {  // 这个类也是一个对象
    // fields
    var privateVal; // private fields
    this.field1 = fields;   // public fields
    ...
    // methods
    this.MyMethod = function(parameters,...) {
        ...
    }
}

var myClass = new MyClass(field1,...);  // 也是一个对象

但是实际上这样做,有一个很大的弊端。那就是对于那些每一个实例对象都共有的属性,每一次生成一个实例,都必须为重复的内容,多占用一些内存。
Javascript规定,每一个构造函数都有一个prototype属性,指向另一个对象。这个对象的所有属性和方法,都会被构造函数的实例继承。
这意味着,我们可以把那些不变的属性和方法,直接定义在prototype对象上。

原型(prototype)继承

function A() {
	this.name="A";
	this.say=function() {
		console.log("I'm " + this.name);
	}
}

function B() {
	this.name="B";
}

function F(){}

F.prototype = A.prototype;	// 从A.prototype继承属性
B.prototype = new F();	// B.prototype继承F对象的属性,这样修改B.prototype的属性不会影响A.prototype
B.prototype.constructor = B;// B.prototype.constructor改为B()
// ES5后可以直接使用封装好的方法来实现上述的原型继承
B.prototype = Object.create(A.prototype);
B.prototype.constructor = B;

多重继承

function M1() {
	this.hello="hello";
}

function M2() {
	this.world="world";
}

function S() {
	M1.call(this);
	M2.call(this);
}

S.prototype = Object.create(M1.prototype);	// 继承M1
Object.assign(S.prototype, M2.prototype);	// 在继承链中加入M2
S.prototype.constructor = S;
/* 原型对象的属性不是实例对象自身的属性。只要修改原型对象,
 * 变动就立刻会体现在所有实例对象上。当实例对象本身没有某个属性或方法的时候,
 * 它会到原型对象去寻找该属性或方法。这就是原型对象的特殊之处。
 * 如果实例对象自身就有某个属性或方法,它就不会再去原型对象寻找这个属性或方法。
 * 原型对象的作用,就是定义所有实例对象共享的属性和方法。
 * 这也是它被称为原型对象的原因,而实例对象可以视作从原型对象衍生出来的子对象。
 */

原型链

JavaScript 规定,所有对象都有自己的原型对象(prototype)。一方面,任何一个对象,都可以充当其他对象的原型;另一方面,由于原型对象也是对象,所以它也有自己的原型。因此,就会形成一个“原型链”(prototype chain):对象到原型,再到原型的原型……

如果一层层地上溯,所有对象的原型最终都可以上溯到Object.prototype,即Object构造函数的prototype属性。也就是说,所有对象都继承了Object.prototype的属性。这就是所有对象都有valueOftoString方法的原因,因为这是从Object.prototype继承的。

那么,Object.prototype对象有没有它的原型呢?回答是Object.prototype的原型是nullnull没有任何属性和方法,也没有自己的原型。因此,原型链的尽头就是 null

读取对象的某个属性时,JavaScript 引擎先寻找对象本身的属性,如果找不到,就到它的原型去找,如果还是找不到,就到原型的原型去找。如果直到最顶层的Object.prototype还是找不到,则返回undefined如果对象自身和它的原型,都定义了一个同名属性,那么优先读取对象自身的属性,这叫做“覆盖”(overriding)。

constructor属性

prototype对象有一个constructor属性,默认指向prototype对象所在的构造函数。由于constructor属性定义在prototype对象上面,意味着可以被所有实例对象继承

function P() {}
var p = new P();
p.contructor === P; // true
p.constructor === P.prototype.constructor;	// true
p.hasOwnPrototype("constructor");	// false, ∵ constructor属性继承自原型

修改原型对象时,一般要同时修改constructor属性的指向。

isinstanceof运算符

  • 作用:

instanceof运算符返回一个布尔值,表示对象是否为某个构造函数的实例。

  • 判断规则

instanceof运算符的左边是实例对象,右边是构造函数。它会检查右边构建函数的原型对象(prototype),是否在左边对象的原型链上。有一种特殊情况,就是左边对象的原型链上,只有null对象。这时,instanceof判断会失真。但是,只要一个对象的原型不是nullinstanceof运算符的判断就不会失真。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值