作为自己学习时的笔记,不做过多解释:
几点笔记:

  • 函数是对象,对象是通过函数创建出来的
  • 原型分为两种:

    • 显示原型:prototype ,是每个函数function/函数对象独有的属性
    • 隐式原型:__proto__ ,是每个对象都有的属性
  • 原型和原型链:

    • 原型:可以把函数看作一个类,那么原型就是所有类都有的属性,在这里存储可以公共使用的统一的方法
    • 原型链:每个对象都有__proto__ ,这个属性指向该对象的 prototype ,然后这个 prototype 原型对象也会有自己的__proto__ 最终层层向上会找到最顶级对象 Object 的 prototype ,这个过程联系起来被称为原型链。【原型链最终的指向--> Object.prototype.__proto__ === null】
  • js 里面有两个最顶层的概念:

    • 最顶层的构造器: Function
    • 最顶层的对象:Object

首先需要先了解“构造函数”

function Person(name, gender){    //声明一个构造函数
      this.name = name
      this.gender = gender
      this.say = function(){
        console.log(`我是${name},是一个${gender}生...`);
      }
}
const personFun = new Person('张嘀嗒', '男')   
personFun.say()  //  我是张嘀嗒,是一个男生...

每个构造函数的实例对象(personFun)都能通过 constructor 来找到构造函数(Person)本身

console.log('通过constructor找到实例的构造函数',personFun.constructor === Person);//true

此时我们可以使用函数对象的 prototype 属性来给构造函数预定义属性,prototype 可以理解为就是构造函数的原型对象

 function Car(){
      Car.prototype.name = '奔驰'
      Car.prototype.color = '白色'
      Car.prototype.say = function(){
        console.log(`我的牌子是${this.name},颜色是${this.color}`);
      }
}
const carFun = new Car()
carFun.say()  // 我的牌子是奔驰,颜色是白色

我们用更简洁直观的方式讲解函数的 prototype 属性:

  • 原型对象就是一个普通对象,用法也是和普通对象一样
  • 构造函数的原型对象里面的方法是共有的方法,所有对应的 new 出来的实例对象都能调用原型对象里面的方法
  • prototype 里面保存着可以被实例共享的方法,此外里面还会有一个 constructor 的属性指向该原型对象的构造函数
    用法示例:
function Dog(){}
    Dog.prototype = {
      name: '旺财',
      color: '黑白灰',
      say(){
        console.log(`原型对象:我的名字是${this.name},颜色是${this.color}`);
      }
}
const dogFun = new Dog()
dogFun.say()    // 原型对象:我的名字是旺财,颜色是黑白灰
  • 在一般情况下,所有的原型对象 prototype 都有一个自带的 constructor 属性,

    • constructor 是一个指针,指向该 prototype 属性所在的函数 [Person, Car, Dog]
    • 也就是说 Person.prototype.constructor == Person
    • 此时,我们可以看到在最上面构造函数那里,构造函数的实例对象也有 constructor 属性
    • 由此可以引申出--> Person.prototype.constructor === personFun.constructor === Person
    • 关于为什么实例对象会直接有 constructor 属性,而且为什么和原型对象的指向是一样的,可以理解为在创建示例对象的时候执行了如下示例(帮助理解,不能运行):
      --->const personFun = new Person()
      --->Person.prototype = personFun

js 在新建对象的时候(包括函数对象和普通对象),都会内置一个 proto 的内置属性用于指向 创建该对象的构造函数的原型对象,所以:

console.log('__proto__指向该对象的构造函数的原型对象', personFun.__proto__ === Person.prototype);  // true
console.log('__proto__指向该对象的构造函数的原型对象2', personFun.__proto__.constructor === Person.prototype.constructor === Person);  // true

所以得出以下结论:

 * __proto__是什么?
 * 因为 personFun.__proto__ === personFun.prototype === Person
 * 所以 __proto__ 指向 构造函数的原型对象 prototype,可称为隐式原型
 * 
 * 一点区别:
 * 对象数据都有 __proto__属性指向该对象的构造函数的原型对象
 * 函数对象既有 __proto__ 指向该实例对象的改造函数的原型对象,还有 prototype 属性(原型对象本身)直接指向原型对象

代码:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <script>
    //构造函数
    function Person(name, gender){
      this.name = name
      this.gender = gender
      this.say = function(){
        console.log(`我是${name},是一个${gender}生...`);
      }
    }
    const personFun = new Person('张嘀嗒', '男')   
    personFun.say()  //  我是张嘀嗒,是一个男生...
    //每个构造函数的实例对象都能通过 constructor 来找到构造函数本身
    console.log('通过constructor找到实例的构造函数',personFun.constructor === Person);

    //利用函数对象的 prototype 属性给构造函数预定义属性,prototype ---> 原型对象
    function Car(){
      Car.prototype.name = '奔驰'
      Car.prototype.color = '白色'
      Car.prototype.say = function(){
        console.log(`我的牌子是${this.name},颜色是${this.color}`);
      }
    }
    const carFun = new Car()
    carFun.say()  // 我的牌子是奔驰,颜色是白色

    /**
     * 用更简洁直观的方式讲解函数的 prototype 属性 ---> 原型对象就是一个普通对象,用法也是和普通对象一样
     * 构造函数的原型对象里面的方法是共有的方法,所有对应的 new 出来的实例对象都能调用原型对象里面的方法
     * prototype 里面保存着可以被实例共享的方法,此外里面还会有一个 constructor 的属性指向该原型对象的构造函数
     * */
    function Dog(){}
    Dog.prototype = {
      name: '旺财',
      color: '黑白灰',
      say(){
        console.log(`原型对象:我的名字是${this.name},颜色是${this.color}`);
      }
    }
    const dogFun = new Dog()
    dogFun.say()    // 原型对象:我的名字是旺财,颜色是黑白灰

    /**
     * 在一般情况下,所有的原型对象 prototype 都有一个自带的 constructor 属性,
     * constructor 是一个指针,指向该 prototype 属性所在的函数 [Person, Car, Dog]
     * 也就是说 Person.prototype.constructor == Person
     * 此时,我们可以看到在最上面构造函数那里,构造函数的实例对象也有 constructor 属性
     * 由此可以引申出--> Person.prototype.constructor === personFun.constructor === Person
     * 关于为什么实例对象会直接有 constructor 属性,而且为什么和原型对象的指向是一样的,可以理解为在创建示例对象的时候执行了如下示例(帮助理解,不能运行):
     * --->const personFun = new Person()
     * --->Person.prototype = personFun
     * */

    //js 在新建对象的时候(包括函数对象和普通对象),都会内置一个 __proto__ 的内置属性用于指向 创建该对象的构造函数的原型对象,所以:
    console.log('__proto__指向该对象的构造函数的原型对象', personFun.__proto__ === Person.prototype);  // true
    console.log('__proto__指向该对象的构造函数的原型对象2', personFun.__proto__.constructor === Person.prototype.constructor === Person);  // true
    
    /**
     * 所以得出以下结论:
     * __proto__是什么?
     * 因为 personFun.__proto__ === personFun.prototype === Person
     * 所以 __proto__ 指向 构造函数的原型对象 prototype,可称为隐式原型
     * 
     * 一点区别:
     * 对象数据都有 __proto__属性指向该对象的构造函数的原型对象
     * 函数对象既有 __proto__ 指向该实例对象的改造函数的原型对象,还有 prototype 属性(原型对象本身)直接指向原型对象
     * 
    */
    let num = Number.constructor === Function
    console.log(num);

  </script>
</body>
</html>

图示:

图解:


张嘀嗒
9 声望2 粉丝

一个前端小白,更新学习笔记~~