面试题【Day06】

发布于 2021-09-07 11:43 ,所属分类:2021面试经验技巧分享

本篇绪论

1,原型、原型链

1,原型、原型链

创建对象的几种方法:

  • 1,字面量
letobj={}
letobj1=newObject()
  • 2, 构造函数
letPerson=function(name){
this.name=name
}
letobj3=newPerson('xiaowang')
  • 3, Object.create
letobj4=Object.create({})
Object.create是用原型链的方式连接的

所有对象都有一个__proto__(隐式原型)属性,属性值是一个普通的对象,所有的函数都有一个prototype(原型)属性,属性值也是一个普通的对象。

letarr=[]
arr.__proto__===Array.prototype//true

letobj={}
obj.__proto__===Object.prototype//true
对象的__proto__属性指向它构造函数的prototype

当访问一个对象的某个属性时,会先在这个对象本身属性上查找,如果找不到,则会去他的__proto__上找,即它的构造函数的prototype,如果还没找到,就会去构造函数的prototype的__proto__中查找,这样一层一层向上查找就会形成一个链式结构,这称之为原型链

functionPerson(name){
this.name=name
}
letp=newPerson('xiaowang')
console.log(p.name)//xiaowang
console.log(p.age)//undefined

一直向上查找,直到查找到null还没有找到,则返回 undefined

Object.prototype.proto === null

原型
  • 所有的引用类型(数组、对象、函数)都可以自由扩展属性(除null外)
  • 所有的引用类型都有一个__proto__属性(隐式原型,它是一个普通的对象)
  • 所有的函数都有一个prototype(原型)属性,它也是一个普通的对象
  • 所有的引用类型,它的__proto__属性都指向它的构造函数的prototype属性
  • 当试图得到一个对象的属性的时候,如果这个对象本身不存在这个属性,那么就会去它的__proto__属性(也就是它的构造函数的prototypr属性)中去寻找 我们来看个原型的例子
//这是一个构造函数
functionPerson(name,age){
this.name=name
this.age=age
}
//所有的函数都具有一个prototype属性,这个属性是一个对象,所有的对象都可以自由扩展属性
Person.prototype={
sayName(){
console.log(this.name)//this是什么要看执行的时候谁调用了这个函数
}
}
constp1=newPerson('xiaowang',18)
p1.sayName()//xiaowang

以上就是原型, 那为什么使用原型呢?试想,如果我们要通过Person()创建很多很多个对象:

functionPerson(name,age){
this.name=name
this.age=age
this.sayName=function(){
console.log(this.name)
}
}

那么我们创建出来的每一个对象,里面都有一个sayName方法,这样就会占用很多的资源。

而通过原型来实现的话,只需要在构造函数里给属性赋值,而把方法写在Person.prototype属性里面,这样每个对象都可以使用prototype属性里面的sayName方法,并且节约了不少的资源。


原型链

当试图得到一个对象的属性时,如果这个对象本身不存在这个属性,那么就会去它构造函数的prototype属性中去寻找。又因为prototype属性是一个对象,所以它也是一个__proto__属性

functionPerson(name,age){
this.name=name
this.age=age
}
Object.prototype.toString=function(){
console.log(this.name+this.age)//this是什么要看执行的时候谁调用了这个函数
}
letp1=newPerson('xiaowang',18)
p1.toString()//xiaowang18
console.log(p1.toString===Person.prototype.__proto__.toString)//true
console.log(p1.__proto__===Person.prototype)//true
console.log(Person.prototype.__proto__===Object.prototype)//true
console.log(Object.prototype.__proto__===null)//true

以上代码,p1的构造函数是Person(),所以p1.proto === Person.prototype

因为Person.prototype是一个普通的对象,它的构造函数是Object,所以:Person.prototype.proto === Object.prototype

通过上面的代码,我们知道这个toString()方法是在Object.prototype里面的,当调用这个对象本身并不存在的方法时候,就会一层一层的往上查找,一直到null为止。

所以当p1调用toString()时,JS发现p1中没有这个方法,于是就会去Person.prototype中去找,发现还是没有这个方法,就会去Object.prototype中去找,找到了,就调用Object.prototype中的toString()方法。

这就是原型链,p1能够调用Object.prototype中的方法正是因为存在原型链的机制。

tips:

在使用原型的时候,一般推荐将需要拓展的方法写在构造函数的prototype属性中,避免写在__proto__属性里。


相关资源