画一个js原型链

示例代码:

// 构造函数
function Fn(){
            
}
// 实例化对象
let p = new Fn();
let obj - new Object();

要点:

  1. 每个函数(function)都有一个prototype(即:显式原型),它在函数被定义的时候产生。

  2. 每个实例对象都有一个__proto__,(即:隐式原型),它在对象被创建时产生。

  3. 原型对象中有一个constructor属性,它指向相对应的函数对象。

    //验证
    console.log(Fn===Fn.prototype.constructor)	//true
    
  4. 对象的隐式原型的值为其对应的构造函数的显式原型的值。

    //验证
    console.log(f.__proto__===Fn.prototype)	//true
    
  5. 所有的函数的__proto__都一样。

    //验证
    console.log(Function.__proto__ === Fn.__proto__)	//true
    console.log(Object.__proto__===Function.__proto__)	//true
    
  6. Function()是一个构造函数,并且它的实例化对象也是自己。

    //验证
    console.log(Function.prototype === Function.__proto__)	//true
    

原型链的作用:
当访问一个对象的属性时,先在自身的属性中查找,若找到,则可以访问自身的这个属性。若没有找到,再沿着__proto__这条链向上查找,若找到,则可以访问原型对象中的该属性。若都没能找到,则返回undefined。

原型链图解:
在这里插入图片描述
解决图中obj处的问号:

obj = f.__proto__ ;

通过这行代码建立了Object()构造函数与第二层的连接,原本他们是没有关联的。

一个简单的应用:(es5 写法)

//构造函数( 父)
function Super(name,age) {
    this.name=name;
    this.age=age;
    this.paly1 = function () {
    console.log('保护地球1')
}
}
//  给构造函数添加方法
Super.prototype.paly2 = function () {
    console.log('保护地球2')
}
//构造函数( 子)
function Student(name, age) {
    Super.call(this,name,age)
    this.eat = function () {
        console.log('吃蛋糕')
    }
}
let p = new Student('匿名', 21)
console.log(p)  // Student {name: "匿名", age: 21, eat: ƒ}
console.log(p.name);    // 匿名
console.log(p.play1())  // 报错  只能访问属性,访问不了方法
console.log(p.play2())  // 报错  只能访问属性,访问不了方法  

分析:我们知道,Student继承了Super的属性,第20行创建的实例对象p,只能调用Super的属性却无法调用Super的方法,要想调用Super的方法,在es5中得采用原型链,如下:

//构造函数
function Super(name,age) {
    this.name=name;
    this.age=age;
    this.paly1=function () {
        console.log('保护地球1');
    }
}
//  给构造函数添加方法
Super.prototype.paly2 = function () {
    console.log('保护地球2')
}
//构造函数
function Student(name, age) {
    Super.call(this,name,age)
    this.eat = function () {
        console.log('吃蛋糕')
    }
}
//  充分运用?处的处理方法
// 原型对象发生了改变
let p = new Student('匿名',21)
p.__proto__ = new Super();  //最最简单的继承
        
// p.__proto__.constructor  //指向Super,而它本身是Student的实例对象,让它指回来
p.__proto__.constructor = Student;
console.log(p)  // Student {name: "匿名", age: 21, eat: ƒ}
console.log(p.name);    // 匿名
console.log(p.paly1()); // 保护地球1
console.log(p.paly2()); // 保护地球2

分析:我们看到第29行和30行未报错,因为我们通过原型链的知识,将实例对象p的原型作为Super的实例对象,实现了最简单的继承,但这时p.__proto__.constructor已经指向Super了,但它本身是Student的实例对象,所以得让它指回来,这样才不会乱,毕竟我们的本意只想Student能继承Super的方法,而不是破坏原型链。

图解:

在这里插入图片描述
上述原型链的知识,实现了原生js的继承,会稍显麻烦,所以es6通过class创建类并用extendssuper(arg1,arg2)实现继承解决了我们运用起来很麻烦的问题:

class Super {
    constructor(name,age) {
        this.name=name;
        this.age = age;
    }
    play1 () {
        console.log('保护地球1')
    }
    play2 () {
        console.log('保护地球2')
    }
}
class Student extends Super {
    constructor(name,age) {
    	//   super //超级  可以实现继承  // super 必须放在this前面
        super(name,age)
    }
    eat () {
        console.log('吃蛋糕')
    }
}
let s = new Student('汪苏泷',30)
console.log(s.name)     //汪苏泷
console.log(s.play1())  //保护地球1

推荐一篇讲原型链的博客,我觉得写得挺好的,可以参考:
https://blog.csdn.net/cc18868876837/article/details/81211729

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值