js原型对象

JavaScript 通过构造函数生成新对象,因此构造函数可以视为对象的模板。实例对象的属性和方法,可以定义在构造函数内部。

function Cat (name, color) {
  this.name = name;
  this.color = color;
}

var cat1 = new Cat('大毛', '白色');

cat1.name // '大毛'
cat1.color // '白色'

上面代码中,Cat函数是一个构造函数,函数内部定义了name属性和color属性,所有实例对象(上例是cat1)都会生成这两个属性,即这两个属性会定义在实例对象上面。
通过构造函数为实例对象定义属性,虽然很方便,但是有一个缺点。同一个构造函数的多个实例之间,无法共享属性,从而造成对系统资源的浪费。

function Cat(name, color) {
  this.name = name;
  this.color = color;
  this.meow = function () {
    console.log('喵喵');
  };
}
var cat1 = new Cat('大毛', '白色');
var cat2 = new Cat('二毛', '黑色');
cat1.meow === cat2.meow

prototype 属性的作用

JavaScript 规定,每个函数都有一个prototype属性,指向一个对象
如果实例对象自身就有某个属性或方法,它就不会再去原型对象寻找这个属性或方法,优先找自身的属性。
JavaScript 规定,所有对象都有自己的原型对象(prototype)。一方面,任何一个对象,都可以充当其他对象的原型;另一方面,由于原型对象也是对象,所以它也有自己的原型。因此,就会形成一个“原型链”(prototype chain):对象到原型,再到原型的原型……(原型链的尽头就是null)

注意,一级级向上,在整个原型链上寻找某个属性,对性能是有影响的。所寻找的属性在越上层的原型对象,对性能的影响越大。如果寻找某个不存在的属性,将会遍历整个原型链。

举例来说,如果让构造函数的prototype属性指向一个数组,就意味着实例对象可以调用数组方法。

var MyArray = function () {};
MyArray.prototype = new Array();
MyArray.prototype.constructor = MyArray;
var mine = new MyArray();
mine.push(1, 2, 3);
mine.length // 3
mine instanceof Array // true

构造函数

constructor属性的作用是,可以得知某个实例对象,到底是哪一个构造函数产生的,实际上是返回自身的实例对象由于constructor属性定义在prototype对象上面,意味着可以被所有实例对象继承
上面代码中,x是构造函数Constr的实例,可以从x.constructor间接调用构造函数。这使得在实例方法中,调用自身的构造函数成为可能。

function Constr() {}
var x = new Constr();
var y = new x.constructor();
y instanceof Constr // true

instanceof

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

var d = new Date();
d instanceof Date // true
d instanceof Object // true

上面代码中,d同时是Date和Object的实例,因此对这两个构造函数都返回true

注意,instanceof运算符只能用于对象,不适用原始类型的值。

此外,对于undefined和null,instanceOf运算符总是返回false。

undefined instanceof Object // false
null instanceof Object // false

构造函数的继承

让一个构造函数继承另一个构造函数,是非常常见的需求。这可以分成两步实现。第一步是在子类的构造函数中,调用父类的构造函数。

function Sub(value) {
  Super.call(this);
  this.prop = value;
}

上面代码中,Sub是子类的构造函数,this是子类的实例。在实例上调用父类的构造函数Super,就会让子类实例具有父类实例的属性。
第二步,是让子类的原型指向父类的原型,这样子类就可以继承父类原型。

Sub.prototype = Object.create(Super.prototype);
Sub.prototype.constructor = Sub;
Sub.prototype.method = '...';

上面代码中,Sub.prototype是子类的原型,要将它赋值为Object.create(Super.prototype),而不是直接等于Super.prototype。否则后面两行对Sub.prototype的操作,会连父类的原型Super.prototype一起修改掉。

另外一种写法是Sub.prototype等于一个父类实例。

Sub.prototype = new Super();

上面这种写法也有继承的效果,但是子类会具有父类实例的方法。有时,这可能不是我们需要的,所以不推荐使用这种写法。

举例

function Foo(){}; //构造函数
var f1 = new Foo; //实例化
console.log(f1.__proto === Foo.prototype);//true 实例对象f1的__proto__属性也指向原型对象Foo.prototype

实例对象f1本身并没有constructor属性,但它可以继承原型对象Foo.prototype的constructor属性

function Foo(){};
var f1 = new Foo;
console.log(Foo.prototype.constructor === Foo);//true
console.log(f1.constructor === Foo);//true
console.log(f1.hasOwnProperty('constructor'));//false

继承

function M1() {
  this.hello = 'hello';
}
function M2() {
  this.world = 'world';
}
function S() {
  M1.call(this);
  M2.call(this);
}
M1.prototype.aa=11
var s = new S();
s.hello // 'hello'
s.world // 'world'
s.aa // undefined

// 继承 M1
S.prototype = Object.create(M1.prototype);
// 继承链上加入 M2
Object.assign(S.prototype, M2.prototype);
// 指定构造函数为自身
S.prototype.constructor = S; 
var ss = new S();
s.hello // 'hello'
s.world // 'world'
s.aa // 11

参考连接
https://wangdoc.com/javascript/oop/prototype.html
https://blog.csdn.net/yiifaa/article/details/72809704
https://www.cnblogs.com/xiaohuochai/p/5721552.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值