前端三大山之一:原型链

参照了思否Sunshine_Lin的文章:https://segmentfault.com/a/1190000041095282

prototype和__proto__

  • prototype: 显式原型
  • __ proto__: 隐式原型 【注意proto前后分别是两条 _ 】

一般构造函数的prototype和其原型的__proto__指向的是同一个地方,叫做原型对象

构造函数

  通俗的来讲,构造函数就是可以用来new的函数,箭头函数不能当做构造函数

 

function Person(name,age){
  // 这就是构造函数 name,age 是传的参数 this.myname 是Person的属性,把参数值赋予属性
  this.myname = name
  this.myage = age
}
Person.prototype.sayName = function(){
  console.log('在下'+this.myname,'今年'+this.myage+'岁')
}
const p1 = new Person('明世隐',10)// 这是 Person 的实例
const p2 = new Person('李白',20) // 这是 Person 的实例
console.log(p1)//Person { myname: '明世隐', myage: 10 }
console.log(p2) // Person { myname: '李白', myage: 20 }
console.log(p1.myname) // 明世隐
console.log(p2.myname)//李白
p1.sayName()//在下明世隐 今年10岁
p2.sayName()//在下李白 今年20岁
console.log(p1.__proto__)// Person{sayName:[function]}
console.log(Person.prototype) // Person{sayName:[function]}
console.log(p1.__proto__ === Person.prototype) // true
// 总结:构造函数的proptotype 与实例的 __proto__指向的是同一个地方 叫做原型对象

 

 

函数

 

 构造函数也是一个函数,定义函数有以下几个方法

// 构造函数说到底也是一个函数,比如平时定义函数
function fn1(name,age){
  console.log(`在下${name},今${age}`)
}
const fn2 = function(name,age){
  console.log(`在下${name},今${age}`)
}
const fn3 = (name,age)=>{
  console.log(`在下${name},今${age}`)
}
// 除此之外,这三个函数都可以用 new Function 来声明,所以 Function 也是一个构造函数 上面的写法等同于
const fn4 = new Function('name','age','console.log(`在下${name},今${age}`)')
fn3('卤蛋',2)//在下卤蛋,今2
fn4('卤蛋',3)//在下卤蛋,今3
// 所以 fn1\fn2\fn3\fn4都是 Function 构造函数的实例
console.log(fn1.__proto__ === Function.prototype)// true 其他函数一样的就不多打印了

 

 

 

对象

 

// 一般创建对象有以下几种方式:
// 构造函数创建对象,创建出来的都是此Function构造函数的实例
function Hero(name,age){
  this.name = name
  this.age = age
}
const hero1 = new Hero('诸葛亮',13)
// 字面量创建对象 本质就是 new Object() 创建对象
const hero2= {name:'澜',age:12}
// new Object 创建对象
const hero3 = new Object()
hero3.name = '澜'
hero3.age = 12
// Object.create 创建对象,创建出来的是空原型对象
const hero4 = Object.create({})
hero4.name = '后羿'
hero4.age = 34
// 所以 hero2,hero3都是object构造函数的实例
console.log(hero2.__proto__ === Object.prototype)// true
console.log(hero3.__proto__ === Object.prototype)// true
 

 

【图不是原创的,所以跟我自己写的例子不一致,反正我没怎么看懂,就先放着吧】

 

 

 

 

Function和Object

  • 函数Function构造函数的实例
  • 对象Object构造函数的实例

function Object() 和 function Function() 其实都是函数,所以他们都是Function构造函数的实例。【要注意名称,可以顾名思义,比如原型对象,本质是对象】

console.log(Function.prototype === Function.__proto__)// true
console.log(Function.prototype === Object.__proto__) // true

constructor

作者原话:constructor和prototype是成对的,你指向我,我指向你。举个例子,如果你是我老婆,那我肯定是你的老公。

function fn(){}
console.log(fn.prototype)// fn {}
console.log(fn.prototype.constructor)//[Function: fn]
console.log(fn === fn.prototype.constructor)//true

原型链

// 什么是原型链?通俗的说,__proto__的路径就是原型链
console.log(Person.prototype)//指向原型对象 Person { sayName: [Function] } 是一个对象 ,对象是Object构造函数的实例,所以如下
console.log(Person.prototype.__proto__ === Object.prototype) // true
console.log(Person.__proto__)//[Function],Person 的原型是Function,Person的实例是对象
console.log(Person.__proto__ === Function.prototype) // true ,Person 是Functtion构造函数的实例,Person.prototype 是Object构造函数的实例
console.log(p1.__proto__.__proto__ === Object.prototype) //true
//总结:Person.__proto__指向Person的原型(向上,指向上一层),Person.prototype指向Person的实例的原型(向下,指向下一层),而Person 是一个构造函数,function构造函数是Function 的实例,个人为了方便记忆瞎总结出来的,不一定对。

原型链终点

上面咱们看到,三条原型链结尾都是Object.prototype,那是不是说明了Object.prototype就是原型链的终点呢?其实不是的,Object.prototype其实也有__proto__,指向null,那才是原型链的终点

完整图如下

 

 

 

 

 

 

 

原型继承

创建了一个构造函数之后,通过new 实例化对象,每一个实例都是独立的互相不影响。【要自己敲过代码后才能更好的理解】

// 先创建一个构造函数
function Hero(name,age){
  this.name = name
  this.age = age
}
//实例只有调用了setPosition才会执行该方法,增加一个新属性position,和更改原有的属性age,但是对于另外一个实例hero11的属性值不会有影响,也不会更改hero11的属性age 
//【注意实例的名称,hero1和hero11,因为做练习的时候同一个文件里已经有hero2了,为避免重复就用了hero11】
Hero.prototype.setPosition = function(){ //往原型对象添加方法 this.position = '刺客' this.age = 18 console.log(`${this.name},今年${this.age},定位:${this.position},要做的是${this.doWhat},其他信息${this.otherMsg}`) } Hero.prototype.doWhat = '打野' console.log(Hero.prototype) // Hero { setPosition: [Function], doWhat: '打野' } let hero1 = new Hero('兰陵王',33) let hero11 = new Hero('阿轲',23) hero1.age = 20 console.log(hero1.doWhat)// 打野 原型对象里面的属性 直接打印实例是不会展示出来的,但是通过调用 hero1.doWhat 可以拿到 console.log(hero11.doWhat)// 打野 hero1.setPosition() // 兰陵王,今年18,定位:刺客,要做的是打野 console.log(hero1)//Hero { name: '兰陵王', age: 18, position: '刺客' } console.log(hero11)//Hero { name: '阿轲', age: 23 } 这里没有position 是因为它没有调用 setPosition(),position是在setPosition方法里面新增的一个属性,只有调用才会生效 // 实例如何更改自己的属性都不会影响原型对象或者其他的实例 hero1.doWhat = '抓单' hero1.otherMsg = '没有了' console.log(hero1.doWhat)//抓单 console.log(hero11.doWhat)//打野 hero1.setPosition()//兰陵王,今年18,定位:刺客,要做的是抓单,其他信息没有了 console.log(hero1)//Hero { name: '兰陵王', age: 18, position: '刺客', doWhat: '抓单' } console.log(hero11)// Hero { name: '阿轲', age: 23 } hero11.setPosition()//阿轲,今年18,定位:刺客,要做的是打野,其他信息undefined console.log(Hero.prototype)//Hero { setPosition: [Function], doWhat: '打野' }

instanceof

使用方法: a instanceof b    判断b的prototype是否在a的原型链上

function ADC(name){
    this.name = name
}
const adc = new ADC('李元芳')
//ADC 是一个构造函数,既然是函数,那它就是Function构造函数的实例
//ADC.prototype 是构造函数ADC的原型对象,既然是对象,那它就是Object构造函数的实例
//adc的原型链:adc = new ADC() ——[.__proto__] ——>ADC.prorotype ——[.__proto__]——> Object.prototype
// ADC的原型链:ADC = new Function() ———[.__proto__] ——> Function.prorotype ——[.proto__] ——>Object.prototype
console.log(ADC instanceof Function) // true
console.log(ADC instanceof Object) //true
console.log(adc instanceof ADC) // true
console.log(adc instanceof Object)// true
console.log(adc instanceof Function)//false

一些练习题

//*********没搞懂 */
function B(a){
  this.a = a
}
B.prototype.a = 1
const b = new B()
console.log(b.a)//undefined  为什么是undefined
// 猜测:原本B原型上是有a:1的,因为B.prototype.a = 1,但是b 是B的实例化对象,B实例化之后会把传入的参数赋值给原来a的值,但是这里实例化没传值,所以this.a = undefined,所以实例化的b里面的a=undefined,而原型B里的a=1
console.log(B.prototype)// B { a: 1 }
//*********
//123是数字,其本质是 new Number(),数字本身没有toString方法
console.log(123['toString'].length + 123)

123是数字,数字本质是new Number(),数字本身没有toString方法,则沿着__proto__function Number()prototype上找,找到toString方法,toString方法的length是1,1 + 123 = 124,至于为什么length是1,可以看95%的人都回答不上来的问题:函数的length是多少?

 

posted on 2022-06-28 14:38  会喷火的大魔王  阅读(334)  评论(0)    收藏  举报