原型与原型链

  • Post author:
  • Post category:其他




引入-原型

  1. 请看,我们现在为Cat对象添加一个不变的属性type(种类),再添加一个方法eat(吃)。
  2. 表面上好像没什么问题,但是实际上这样做,有一个很大的弊端。那就是对于每一个实例对象,type属性和eat()方法都是一模一样的内容,每一次生成一个实例,都必须为重复的内容,多占用一些内存。这样既不环保,也缺乏效率。
function Cat(name,color) {
            this.name = name
            this.color = color
            this.type = '猫科'
            this.eat = function () {
                console.log('吃老鼠')
            }
        }
        var cat1 = new Cat('小红','红色')
        var cat2 = new Cat('小黑','黑色')

        console.log(cat1.type)
        cat1.eat()
        
        console.log(cat2.type)
        cat2.eat()
  1. 能不能让type属性和eat()方法在内存中只生成一次,然后所有实例都指向那个内存地址呢?回答是可以的。这就引出了—–原型。



原型(prototype)与原型链



为什么要用原型(prototype)

Javascript规定,每一个构造函数都有一个prototype属性,指向另一个对象。这个对象的所有属性和方法,都会被构造函数的实例继承。 这意味着,我们可以把那些不变的属性和方法,直接定义在prototype对象上。

function Cat(name,color) {
            this.name = name
            this.color = color
        }

        Cat.prototype.type = '猫科'
        Cat.prototype.eat = function () {
            console.log('吃老鼠')
        }

        var cat1 = new Cat('小红','红色')
        var cat2 = new Cat('小黑','黑色')

        console.log(cat1.type)
        cat1.eat()

这时所有实例的type属性和eat()方法,其实都是同一个内存地址,指向prototype对象,因此就提高了运行效率。

 console.log(cat1.eat==cat2.eat) //true



函数的prototype属性

  • 每个函数都有一个prototype属性,它默认指向一个Object空对象(即称为:原型对象)
  • 原型对象中有一个属性constructor,它指向函数对象
  • 可以给原型对象添加属性或方法(一般都是方法)
  • 作用:函数的所有实例对象自动拥有原型中的属性(方法)
// 每个函数都有一个prototype属性,它默认指向一个Object空对象(即称为:原型对象)
        console.log(Date.prototype,typeof Date.prototype) 
        function Fun () {

        }
         console.log(Fun.prototype) //默认指向一个Object空对象(没有我们的属性)

        //  原型对象中有一个属性constructor,它指向函数对象
        console.log(Date.prototype.constructor===Date) //true
        console.log(Fun.prototype.constructor===Fun) //true

        // 给原型对象添加属性或方法(一般都是方法)===>实例对象可以访问
        Fun.prototype.test = function () {
            console.log('test()')
        }
        var fun = new Fun()
        fun.test() //输出test()



prototype与__proto__

  1. 每个函数function都有一个prototype,即显示原型(属性)
  2. 每个实例对象都有一个__proto__,可称为隐式原型(属性)
  3. 对象的隐式原型的值为其对应构造函数的显示原型的值
  4. 总结:

    函数的prototype属性:在定义函数时自动添加的,默认值是一个空的Object对象

    对象的__proto__属性:创建的对象时自动添加的,默认值为构造函数的prototype属性值

    程序员能直接操作显示原型,但不能直接操作隐式原型(ES6之前)
function Fn () {

         }
        //  1.每个函数function都有一个prototype,即显示原型属性,默认指向一个空的Object对象
        console.log(Fn.prototype) 
        // 2.每个实例对象都有一个__proto__,可称为隐式原型
        var fn = new Fn()
        console.log(fn.__proto__)
        // 3.对象的隐式原型的值为其对应构造函数的显示原型的值
        console.log(Fn.prototype===fn.__proto__) //true
        // 给原型添加方法
        Fn.prototype.test = function () {
            console.log('test()')
        }
        // 通过实例对象调用构造函数原型的方法
        fn.test() //输出test()



原型链

访问一个对象的属性时,现在自身属性中查找,找到返回,如果没有,再沿着__proto__这条链向上查找,找到返回,如果最终没找到,返回undefined

别名:隐式原型链

作用:查找对象的属性或方法

function Fn () {
            this.test1 = function () {
                console.log('test1()')
            }
        }
        Fn.prototype.test2 = function () {
            console.log('test2()')
        }

        var fn = new Fn()
        fn.test1()
        fn.test2()
        /*
        1.函数的显示原型指向的对象默认是空Object实例对象(但Object不满足)
        */
       console.log(Fn.prototype instanceof Object) //true
       console.log(Object.prototype instanceof Object)  //false
       console.log(Function.prototype instanceof Object)  //true
       /*
       2.所有函数都是Function的实例(包含Function)
       */
        console.log(Function.__proto__ === Function.prototype)
        /*
        3.Object的原型对象是原型链的尽头
        */
       console.log(Object.prototype.__proto__) //null 



原型链-属性问题

  1. 读取对象的属性值时,会自动到原型链中查找
  2. 设置对象的属性值时,不会查找原型链,如果当前对象中没有此属性,直接添加此属性并设置其
  3. 方法一般定义在原型中,属性一般通过构造函数定义在对象本身上
function Fn () {

         }
         Fn.prototype.a = 'xxx'
         var fn1 = new Fn()
         console.log(fn1.a,fn1) 
         
         var fn2 = new Fn()
         fn2.a = 'yyy'
         console.log(fn1.a,fn2.a,fn2)

         function Person(name,age) {
             this.name = name
             this.age = age
         }
         Person.prototype.setName = function(name) {
             this.name = name
         }
         var p1 = new Person('Tom',12)
         p1.setName('Bob')
         console.log(p1)

         var p2 = new Person('Jack',12)
         p2.setName('Cat')
         console.log(p2)
         console.log(p1.__proto__ === p2.__proto__) //true



版权声明:本文为summer_567原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。