美文网首页
再看原型链

再看原型链

作者: GrowthCoder | 来源:发表于2018-09-27 19:26 被阅读0次

开场白

输出?

var A= function(){}
    A.prototype.n=1
    var b=new A()
    A.prototype={
        n:2,
        m:3
    }
var c=new A()
console.log(b.n, b.m, c.n, c.m)
console.log(A.prototype.__proto__)

prototype

每个构造函数都有一个prototype属性,指向自己的原型对象;

什么是原型?每个对象创建的时候,都会与之关联另一个对象,这个就是原型对象,会从原型“对象”继承属性和方法。


__proto__

每个实例对象(object)都有一个私有属性__proto__指向它的原型对象(prototype)。该原型对象也有一个自己的原型对象,层层向上直到一个对象的原型对象为null

function Person(name) {
  this.name = name
}

Person.prototype.getName = function () {
  return this.name
}

var person = new Person();
person.name = 'gaoting';
console.log(person.name) // gaoting
console.log(Person.prototype) 
console.log(person.__proto__) 
console.log(person.__proto__ === Person.prototype) // true
WX20180926-161836.png

constructor

每个原型对象,都有一个constructor属性,用来指向自己关联的函数,默认指向关联的构造函数。
constructor 引用同样被委托给了 Person.prototype,而 Person.prototype.constructor 默认指向 Person

3.png

Person.prototype 的 .constructor 属性只是 Person函数在声明时的默认属性。
如果 你创建了一个新对象并替换了函数默认的 .prototype 对象引用,那么新对象并不会自动获 得 .constructor 属性。

function Person(name) {
  this.name = name
}

Person.prototype.getName = function () {
  return this.name
}

var person = new Person();
person.name = 'gao';
console.log(person.constructor === Person, Person.prototype.constructor === Person)
//test constructor
Person.prototype = {
  age: 18,
  company: 'yck'
}

var gao = new Person()
console.log(gao.constructor === Person) // false
// 获取对象原型
console.log(Object.getPrototypeOf(gao)) // { age: 18, company: 'yck' }

gao 并没有 .constructor 属性,所以它会委托 [[Prototype]] 链上的 Person. prototype。但是这个对象也没有 .constructor 属性(不过默认的 Person.prototype 对象有这 个属性!),所以它会继续委托,这次会委托给委托链顶端的 Object.prototype。这个对象 有 .constructor 属性,指向内置的 Object(..) 函数。

以上为构造函数、实例、实例原型之间的关系


基于原型链的继承

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

4.png
function Person(name) {
  this.name = name
}

Person.prototype.getName = function () {
  return this.name
}

function Man (sex) {
  this.sex = sex
}
Man.prototype = new Person()
var man = new Man('male')
man.name = 'qi'
console.log(man.getName())
console.log(man instanceof Man, man instanceof Person) // true true

问题一

即在通过原型链实现继承时,不能使用对象字面量创建原型方法。因为这样做原型指向了另一个对象

问题二

在通过原型来实现继承时,原型实际上会变成另一个类型的实例。于是,原先的实例属性也就顺理成章地变成了现在的原型属性了

function SuperType(){
    this.colors = ["red", "blue", "green"];
}
function SubType(){
}
//继承了 SuperType
SubType.prototype = new SuperType(); // SuperType的原型对象将拥有colors属性,之后的实例对colors的修改,将直接作用到原型上
var instance1 = new SubType(); 
instance1.colors.push("black");
console.log(instance1.colors); //"red,blue,green,black"
var instance2 = new SubType(); 
console.log(instance2.colors); //"red,blue,green,black"

错误做法

//和你想要的机制不一样! 
Bar.prototype = Foo.prototype;

只会让Bar.prototype直接引用Foo.prototype对象,当执行类似Bar.prototype.getName的时候,会直接修改Foo.prototype对象本身。这不是想要的结果。

// 基本上满足你的需求,但是可能会产生一些副作用 :( 
Bar.prototype = new Foo();

借用构造函数

为了解决原型中包含引用类型值的问题,可以使用借用构造函数,在子类型构造函数的内部调用超类型构造函数。

function SuperType () {
  this.colors = ['red', 'blue', 'green']
}
SuperType.prototype.getColors = function(){
    return this.colors.join(',')
}
function SubType () {
  //继承了 SuperType,在新构造函数中调用SuperType初始化对象的代码,每个实例保存colors副本
  SuperType.call(this)
}

var ins = new SubType()
ins.colors.push('black')
var ins2 = new SubType()
console.log(ins2) // ['red', 'blue', 'green']
ins2.getColors() // 报错

缺点,更为致命,无法访问超类型SubType.prototype中定义的函数,仅仅获取了超类型构造函数中定义的属性,没有用到继承的思想。


组合继承

将原型链和组合继承技术组合,通过原型链实现对原型属性和方法的继承,通过借用构造函数,让实例拥有自己的属性。

function SuperType (name) {
  this.name = name
  this.colors = ['red', 'blue', 'green']
}

function SubType (name, age = 18) {
  SuperType.call(this, name)
  this.age = age
}
SubType.prototype = new SuperType()
SubType.prototype.getAge = function () {
  return this.age
}
var ins = new SubType('seven', 22)
ins.colors.push('black')
var ins2 = new SubType('six', 11)
console.log(ins2)

原型式继承

Object.create()

function Foo(name) { 
    this.name = name;
}
Foo.prototype.myName = function() { 
    return this.name;
};
function Bar(name,label) { 
    Foo.call( this, name ); 
    this.label = label;
}
// 我们创建了一个新的 Bar.prototype 对象并关联到 Foo.prototype 

Bar.prototype = Object.create( Foo.prototype );

Bar.prototype.myLabel = function() {
 return this.label;
};
var a = new Bar( "a", "obj a" );
a.myName(); // "a"
a.myLabel(); // "obj a"

参考链接

JavaScript深入之从原型到原型链

相关文章

  • 再看原型链

    开场白 输出? prototype 每个构造函数都有一个prototype属性,指向自己的原型对象; 什么是原型?...

  • JavaScript 原型、原型链与原型继承

    原型,原型链与原型继承 用自己的方式理解原型,原型链和原型继承 javascript——原型与原型链 JavaSc...

  • 原型、原型链

    (什么是原型、原型链?有什么作用) JavaScirpt深入之从原型到原型链 图解 Javascript 原型链 ...

  • 原型链&查找规则&作用域链

    原型链(隐式原型链) 属性的查找规则(原型链的查找规则) 作用域链

  • 关于原型原型链的理解

    什么是原型? 什么是原型链? 为什么需要原型,和原型链?

  • 原型链实现继承

    原型链 原型链示意图 使用原型链实现继承 这是怎么回事呢? 原型链在哪? 听我细细道来~ 首先 Teacher 实...

  • 继承

    原型链直接继承 原型链直接继承prototype 原型链继承_prototype属性 继承_构造函数绑定

  • js中的实现继承的几种方式

    大纲:原型链借用构造函数组合继承原型式继承寄生式继承寄生组合式继承 1、原型链: 什么是原型链? 原型链的基本思想...

  • 【原型和原型链】什么是原型和原型链

    【原型和原型链】什么是原型和原型链https://blog.csdn.net/xiaoermingn/articl...

  • js原型链

    目录 1.对象的原型和原型链1.1什么是原型1.2查看原型1.3对象的原型链 2.使用构造函数2.1 函数的原型链...

网友评论

      本文标题:再看原型链

      本文链接:https://www.haomeiwen.com/subject/oglyoftx.html