[前端语法]js原型链有关的继承问题

深夜反而思维更活跃一些

(1)js中的原型链

js中存在一个名为原型链的机制,其特点如下

加入一个方法A,A方法一个属性为prototype,这个属性会指向某个对象,也成为A类对象的原型对象.

当我们根据A这个方法生成一个对象a,那么a的原型(proto)属性即为这个对象

a可以调用一些原型的属性和方法,另外,这也是一些方法查找的原理

(2)js相关的五种继承

继承一共有五种,这五种继承其实都是"属性追加"和"原型链"两个特殊功能的集合体,借用这两个特性实现继承的效果,下面讲解一下有关的思路和勘误

  • 原型链继承

原型链继承指的就是,给创造对象的方法指定一个原型对象

//创建父类方法并且创造一个父类对象
function Parent(){
     this.name="kevin"
}

let p=new Parent

//子类
function Child(){

}

//在创建方法这里指定继承的原型
Child.prototype=p

//创建两个对象
let c1=new Child()
let c2=new Child()


//则有
console.log(c1.__proto__)//p
console.log(c2.__proto__)//p

 这种继承比较好理解,但是有个缺点就是图里面这种情况

console.log(c1.name)  //"kevin"
console.log(c2.name)  //"kevin"

 这种情况下继承的原型是共有的,属性也是一致的,因为子类对象没有这种属性,所以会根据原型链网上寻找这种属性.

  • 构造函数继承

构造函数继承在原理上很类似于其他oop语言的继承方式,即在构造子类对象的时候,优先构造父类对象.

//创建父类方法并且创造一个父类对象
function Parent(name){
     this.name=name
}


function Child(name,age){
     Parent.call(this,name)
     this.age=age
}


//创建两个对象
let c1=new Child("张三",12)

console.log(c1.name) //"张三"

 解释一下这段代码中出现的call语法,call语法是一种传递上下文的方法,在这里对于Parent构造方法使用了call,并且传入了参数this以及name,这个this就是Child的上下文对象

这个时候调用的Parent这个函数,里面的this指向的其实就算一个child对象了

这种继承方法无法像原型链或者es6新增的那种继承一样,只能算是一种"属性追加",这一点和后面的寄生继承一样

  • 组合构造继承

把以上的两种方式给总和起来,一方面,使用构造函数的方法来给对象增加属性.

另一方面 ,使用原型链,给父类构造方法增加一个原型对象,这样可以达成这样的效果

//创建父类方法并且创造一个父类对象
function Parent(name){
     this.name=name
}

Parent.prototype=A      //对象A中有个属性address

function Child(name,age){
     Parent.call(this,name)
     this.age=age
}


//创建两个对象
let c1=new Child("张三",12)
let c2=new Child("李四",12)

//这个是不一样的
console.log(c1.name) //"张三"
console.log(c2.name) //"李四"

//这个是一样的
console.log(c1.address) //"一样的"
console.log(c2.address) //"一样的"
  • 寄生继承

寄生继承和前面的借用构造函数继承一样,本质上不是利用父子类之间的关系,而是利用一些方法进行追加.区别在于,借用构造函数的追加方法是把上下文对象传入别的构造方法中进行追加

而寄生继承则是在一个方法内部,对传进来的方法,先生成对象,然后直接追加属性

function createObj(Obj){
   let o=Object.create(Obj)
   //直接对根据方法生成的对象o进行追加
   return o
}
  • 组合寄生继承(综合上面的方法)

举一个例子,这些东西的应用还是挺灵活的

使用构造函数的方法追加一些数据,然后使用寄生继承的方法增加原型链

//创建父类方法并且创造一个父类对象
function Parent(name){
     this.name=name
}

//子类的方法中使用了借用构造函数继承
function Child(name){
     Parent.call(this,name)
}

//创建一个,原型对象为o的类
function create(o){
     function F(){}
     F.prototype=o
     return new F()
}

function Prototype(child, parent) {
    var p = object(parent.prototype);
    p.constructor = child;
    child.prototype = p;
}

//给Child新建了一个原型对象,这个原型对象就是Parent的原型对象
Prototype(Child, Parent);

补充:棍鱼Prototype这个方法,可以这样子解释

首先,我们使用组合式继承,已经对Child函数扩展了属性,这种情况下,我们就没必要指定原型为Parent对象,Parent的原型有一个公共方法

我们在使用了一个空白对象F作为中间介质,避免了创建无用的Parent

区别画图展示

简单做个总结:

原型链是最贴近继承含义的,因为这东西会根据原型链向上找属性,属于纵向的

而另外两种,则是在原本的基础上扩展/追加属性,属于横向的,是一种伪继承 

 

(3)一道和原型有关的例题(来自leetcode)

[leetcode]前端

 这题对于基础要求...其实很高的,因为一般些js都自由散漫惯了..........真的

这题的输入是一个对象,一个生成方法,判断对象是否由这个方法或者其他方法生成

(1)方案1,也是我使用的一种,比较原型对象

首先先排除特殊情况,也就是对象为null或者方法为null,这种要返回false

var checkIfInstanceOf = function(obj, classFunction) {
      if(obj==null || classFunction==null) return false;//第一种情况,对象和类均为空的时候
      let a=Object.getPrototypeOf(obj); //先找到obj的原型对象
      //然后开始遍历原型链
      while(a!==null){   
          if(a === classFunction.prototype){
            return true;
          }
          a=Object.getPrototypeOf(a);
      }
      return false;
}

(补充内容:除了可以用属性proto来获取原型,还可以直接使用函数Object.getPrototype(&&)来获取)

另外这个例题也带来了一个衍生的问题:

[如何判断一个对象属于哪个类,怎么实现?]

(1)判断基本类型可以使用函数typeof

但是这个函数有一个历史性的缺陷,  typeof(null)===object......这确实有问题,但是已经没法改了

(2)利用原型链来判断 instanceof,实现原理和上面的题目是一样的

剩下还有别的一些方法

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: JavaScript原型链是一种继承机制,它使得每个对象都能从另一个对象继承属性。在 JavaScript 中,每个对象都有一个原型对象,并且可以从原型对象继承属性。 每个对象的原型对象都有一个自己的原型对象,以此推。这就形成了一条原型链,从对象到原型对象再到其原型对象,直到最终到达 null。当你在对象上访问一个属性时,JavaScript 引擎会沿着原型链向上搜索,直到找到一个具有该属性的对象为止。 例如,假设我们有一个构造函数 `Person` 和一个实例 `person1`,它们看起来像这样: ``` function Person(name) { this.name = name; } Person.prototype.sayHi = function() { console.log(`Hi, my name is ${this.name}`); }; const person1 = new Person('Alice'); ``` 在这个例子中,`person1` 的原型对象是 `Person.prototype`,而 `Person.prototype` 的原型对象是 `Object.prototype`。所以,当我们在 `person1` 上调用 `sayHi` 方法时,JavaScript 引擎会在 `person1`、`Person.prototype` 和 `Object.prototype` 中依次搜索该方法,最终找到它并调用。 原型链使得我们能够实现继承,同时又不需要使用传统的继承语法 ### 回答2: JavaScript原型链是一种特殊的继承机制,它是基于对象的,与传统的基于继承不同。 在JavaScript中,每一个对象都有一个原型对象,而原型对象也是一个对象,并且它也有自己的原型对象,这样就形成了一条链式结构,被称为原型链。当我们访问一个对象的属性或方法时,如果对象本身没有这个属性或方法,它会沿着原型链向上查找,直到找到为止。 这个查找过程是通过对象的__proto__属性来实现的,__proto__属性指向该对象的原型对象。当我们访问对象的属性时,如果对象和它的原型对象中都没有这个属性,那么会继续查找原型对象的原型对象,直到找到属性或者到达原型链的顶端,即Object.prototype。如果还没有找到,那么返回undefined。 JavaScript原型链的实质是通过对象之间的关联关系来实现继承。当创建一个对象时,JavaScript引擎会自动为这个对象添加一个隐藏的属性__proto__,并将它指向该对象的构造函数的原型对象。这样,通过对象与原型对象之间的关系,实现继承的特性。 原型链的应用主要体现在面向对象编程中的继承。通过定义构造函数和原型对象,我们可以实现对象的继承关系,并且可以方便地从原型对象中继承属性和方法,提高代码的复用性和可维护性。 总之,JavaScript原型链是一种通过对象关联来实现继承的机制,在面向对象编程中起到了重要的作用。它通过沿着原型链查找的方式,实现了属性和方法的继承,并提供了一种灵活、简洁的继承方式。 ### 回答3: JavaScript中的原型链是一种用于继承和属性查找的机制。每个JavaScript对象都有一个原型,它可以是另一个对象或null。 当我们访问一个对象的属性时,JavaScript引擎首先会在该对象自身查找该属性,如果找不到,它将继续在原型链上进行查找。原型链的顶层是Object.prototype,内置的JavaScript对象(如Array、String)都是它的子对象。 当我们创建一个对象时,JavaScript引擎会通过一个\_\_proto\_\_属性将该对象关联到它的构造函数的原型上。构造函数通过prototype属性来指定原型对象,在实例化对象时会自动创建一个存放共享方法和属性的原型对象。 通过原型链,对象可以继承自己的构造函数原型对象上的属性和方法。这意味着我们可以在原型对象上定义共享方法和属性,而不是每次创建新的对象时都重复定义这些方法和属性,从而节省内存空间。 当我们通过对象实例访问一个属性时,JavaScript引擎会首先在对象自身查找该属性,如果找不到,它会继续在原型链上查找,直到找到该属性或者到达原型链的顶层。如果该属性在原型链上的多个位置都有定义,那么只会取最先找到的属性值。 原型链JavaScript实现继承的基础。通过让一个对象的原型指向另一个对象的实例,我们可以实现原型继承。子对象可以继承父对象原型链上的属性和方法。 总结来说,JavaScript原型链是一种用于实现继承和属性查找的机制。它通过将对象的原型与其构造函数的原型对象关联起来,从而实现属性继承和共享方法的定义。原型链JavaScript中面向对象编程的基础之一。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值