prototype和__proto__

73 阅读3分钟

函数的原型

每个函数都有自己的原型,需要注意的是:Array和Object是本来就有了的,不需要去声明或定义

  • 数组的内置构造函数原型
// 1 通过数组求Array内置构造函数的原型
// const arr = [1,2,28,5] //不用通过内置构造函数创建数组,也能求得Array的prototype
const arr = new Array(1,5,9,7)
console.log(arr.__proto__) // Array[]
console.log(arr.__proto__ === Array.prototype) //true
  • 对象的内置构造函数原型
// 2 通过对象求Object内置构造函数的原型
const obj = new Object({
    a:111,
    b:222
})
console.log(obj.__proto__) //Object{}
console.log(obj.__proto__ === Object.prototype) //true
  • 给数组内置构造函数添加方法
// 3 给内置构造函数添加方法
Array.prototype.abc = function () {
    console.log(111)
}
// 调用
arr.abc () //111
  • 通过内置构造函数求一个数组最大值
Array.prototype.getMax = function () {
let max = this[0]
for (var i = 1; i < this.length; i++) {
  if (max < this[i]) {
    max = this[i]
  }
}
  return max
    }
var max1 = arr.getMax ()
console.log(max1) //6

万物皆对象

js中,万物都可以称为对象。 狭义:如:{key1:value1,key2:value2} 广义:某一类事务的实例(某一类的真实个体)

  • 所有的数组都是Array中的真实个体

  • 所有的对象都是Object中的真实个体

  • 所有的函数都是Function中的真实个体

原型链

原型prototype都是对象形式的,求内置构造函数的原型,语法:内置构造函数.prototype 通过内置函数获得的对象,都可以通过__proto__获得内置构造函数的原型,语法:通过内置函数获得的对象.proto

  • 过程
function Person (num) {
      this.age = num
    }
    Person.prototype.fn = function () {
      console.log(222)
    }
    const p = new Person(111)

    // 问题1: p 的 __proto__ 指向谁?
    // 分析1:p的内置构造函数是Person。p.__proto__ === Person.prototype
    console.log(p.__proto__ === Person.prototype)

    // 问题2: Person 的 __proto__ 指向谁?
    // 分析2:Person本质上是一个函数,是Function的实例化对象。Person__proto__ === Function.prototype
    console.log(Person.__proto__ === Function.prototype)

    // 问题3: Person.prototype 的 __proto__ 指向谁?
    // 分析3:Person是一个内置构造函数,Person.prototype是一个对象,对象是Object的实例化对象
    console.log(Person.prototype.__proto__ === Object.prototype)

    // 问题4: Function 的 __proto__ 指向谁?
    // 分析4:Function是Function的实例化对象
    console.log(Function.__proto__ === Function.prototype)

    // 问题5: Function.prototype 的 __proto__ 指向了谁?
    // 分析5:Function.prototype是一个对象
    console.log(Function.prototype.__proto__ === Object.prototype)

    // 问题6: Object 的 __proto__ 指向了谁?
    // 分析6:Object是一个内置构造函数,本质上还是一个函数Function。因此,Object.__proto__ === Function.prototype
    console.log(Object.__proto__ === Function.prototype)

    // 问题7: Object.prototype 的 __proto__ 指向了谁?
    // 分析7:Object本质上是一个函数,Object.prototype是一个对象,但是重点: Object.prototype 是 JS 顶层的对象
    console.log(Object.prototype.__proto__ === Object.prototype) //false,因为到了对象这一步已经是顶层了,再找她的对象就找不到了,就为null
    console.log(Object.prototype.__proto__) //null

判断数据类型

  • 判断基本数据类型 弊端:只能判断基本数据类型,不能判断数组和对象
console.log(typeof(111)) //number
console.log(typeof(arr)) //object
console.log(typeof(obj)) //object
  • constructor(可以得到内置构造函数函数本身) 弊端:弊端1:当改变了constructor属性就识别不了;弊端2:判断不了基本数据类型
console.log(arr.__proto__) //获得了她内置构造函数Array的原型对象
console.log(arr.__proto__.constructor) //获得了arr内置构造函数Array的原型对象一个属性constructor,属性值就为Array
console.log(arr.constructor === Array) //能够判断出了arr的数据类型,返回值为true
arr.constructor = {b: 222} //当改变constructor的属性时,
console.log(arr.constructor) //依然是一个数组
console.log(arr.constructor === Array) // 但是返回了false
console.log(undefined.constructor) //报错,基本数据不能判断
  • instanceof (可以判断改变后的constructor的属性值) 弊端:依然识别不了基本数据类型
arr.constructor = {b: 222} // 改变了constructor的属性值
console.log(arr instanceof Array) //true
console.log(555 instanceof Array) //false
console.log(null instanceof Object) //false
  • Object.prototype.toString.call(啥都可以检测)
console.log(Object.prototype.toString.call(arr)) //Array
console.log(Object.prototype.toString.call(obj)) //Object
console.log(Object.prototype.toString.call(123)) //Number