原型+原型链

59 阅读3分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 6 天,点击查看活动详情 原型是一种属性与方法的共享机制,原型对象的作用,是用来存放实例中共有的那部份属性、方法,可以大大减少内存消耗。原型是js实现继承的一种方式,掌握原型相关的知识是之后对js更底层的知识进行探究的基础,本篇将会对原型与原型链机制进行深入探讨。

原型

梳理清楚__proto__prototypeconstructor的概念与关系就基本上完成了原型知识的掌握

  • js分为函数对象和普通对象,每个对象都有__proto__属性,但是只有函数对象才有prototype,称为原型,函数的prototype是对象类型,又称为原型对象
  • 引用类型,隐式原型 __proto__ 的属性值指向它的构造函数的显式原型 prototype 属性值。
  • 每个原型都有一个constructor属性指向关联的构造函数
function Person(name,age){
    this.name=name;
    this.age=age;
}
Person.prototype.sayhi=function(){
    console.log(this.name+'say hi')
}
//实例化时,p2就会共享到prototype上的sayhi方法

var p2=new Person('jack',18);
p2.sayhi()//jack say hi
console.log(p2.__proto__ == Person.prototype) // true
console.log(Person.prototype.constructor == Person) // true

原型链

function Person(name) {
  this.name = name
  return this // 其实这行可以不写,默认返回 this 对象
}

var nick = new Person("nick")
nick.toString // ƒ toString() { [native code] }

构造函数中并没有toString()方法,但实例nick却完成了对toString()方法的调用,这就是原型链的效果。是object原型上的方法。

  • 当你试图得到一个对象的某个属性时,如果这个对象本身没有这个属性,那么它会去它的隐式原型__proto__(也就是它的构造函数的显式原型 prototype`)中寻找。
  • 如果构造函数上也没有这个属性就会继续向上到Object原型对象prototype身上去查找,如果最终没有找到会报错
  • 最后一个 null,设计上是为了避免死循环而设置的, Object.prototype 的隐式原型指向 null。 补充题目
var A = function() {};
A.prototype.n = 1;
var b = new A();
A.prototype = {// 执行该语句时开辟了新的堆存放新对象然后将A.prototype的指针改向这个对象
  n: 2,
  m: 3
}
var c = new A();
console.log(b.n);
console.log(b.m);
console.log(c.n);
console.log(c.m);
1
undefined
2
3

构造函数

在了解了原型的定义和原型链规则之后,我们来看一下构造函数在创建实例的过程中执行了哪些步骤

// 仍然是上面的例子
function Person(name) {
  this.name = name
  this.sing = function () { console.log('我爱唱歌'); }
  return this // 其实这行可以不写,默认返回 this 对象
}
let nick = new Person("nick")
let lisa = new Person("lisa")
nick.sing();//我爱唱歌 
lisa.sing();//我爱唱歌 
console.log(lisa.sing === nike.sing);//false
  1. 创建一个空对象 nick {}
  2. 为 nick 准备原型链连接 nick.proto = Person.prototype
  3. 重新绑定this,使构造函数的this指向新对象
  4. 为新对象属性赋值 nike.name,赋函数sing()
  5. 返回this return this,此时的新对象就拥有了构造函数的方法和属性了

以上可见如果在构造函数中定义的方法,在实例化的时候会在每一个实例山都进行绑定同样的方法,所以lisa.sing === nike.sing为flase,这种继承方法的方式会极大的浪费资源。 原型与构造函数都是js中提供的继承的方式,之后会在新的文章中对继承的类型以及实现方式做整体的总结