面试题【Day06】

2021-08-30  本文已影响0人  小王子__

本篇绪论

1,原型、原型链

1,原型、原型链

创建对象的几种方法:

let obj = {}
let obj1 = new Object()
let Person = function(name) {
  this.name = name
}
let obj3 = new Person('xiaowang')
let obj4 = Object.create({})
Object.create是用原型链的方式连接的

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

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

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

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

function Person(name) {
  this.name = name
}
let p = new Person('xiaowang')
console.log(p.name)  // xiaowang
console.log(p.age)  // undefined
在P1中查找某个属性,执行步骤图

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

Object.prototype.proto === null

原型
// 这是一个构造函数
function Person(name, age) { 
  this.name = name
  this.age = age
}
// 所有的函数都具有一个prototype属性,这个属性是一个对象,所有的对象都可以自由扩展属性
Person.prototype = {
  sayName () {
    console.log(this.name) // this是什么要看执行的时候谁调用了这个函数
  }
}
const p1 = new Person('xiaowang', 18)
p1.sayName() // xiaowang

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

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

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

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


原型链

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

function Person(name, age) {
  this.name = name
  this.age = age
}
Object.prototype.toString = function () {
  console.log(this.name + this.age) // this是什么要看执行的时候谁调用了这个函数
}
let p1 = new Person('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属性里。

上一篇下一篇

猜你喜欢

热点阅读