原型(prototype)、原型链(_proto_)、类

引用数据类型分类

  • 函数数据类型:
  • 普通函数
  • 内置类(如 ArrayDate)
  • 自己创建的类(只要是new创建出来的都是类)
  • 对象数据类型:
  • 普通对象、数组、正则、Math、arguments...
  • 实例(除了基本类型的字面量创建的值)
  • prototype的值
  • 函数

原型和原型链的定义

  1. 所有的都天生自带一个属性:prototype(原型),这个属性的值是一个对象,浏览器会默认给它开辟一个堆内存。
  2. 在浏览器给prototype开辟的堆内存中有一个天生自带的属性constructor,这个属性存储的值是当前函数本身,prototype里的属性和方法对于实例是公有的方法,对于原型自己是私有方法。
    3.每一个都有一个__proto__的属性,这个属性指向当前实例的prototype,(如果不能确定它是谁的实例,都是Object的实例)
    原型和原型链机制

    在这里ary既是Array的实例,
    因为它能通过_proto_找到Arrayprototype,同样根据原型链的查找机制,Array_proto_指向了Obejctprototype,所以ary
    也是Obejct的实例。也就是说,如何判断某个实例是不是属于某个类,就判断这个实例的原型链上是不是有这个类。
    原型链是一种基于_proto_向上查找的机制,当我们操作实例的某个属性或者方法的时候,首先找自己空间中私有的属性或者方法 如果找到了则结束查找,使用自己私有的即可,没找到则基于_proto_找所属类的prototype,如果找到就用这个公有的,如果没找到就基于原型上的_proto_继续向上查找,一直找到Obejct的原型为止,如果再没有,操作的原型或者方法不存在。
    例如:
//34.原型链和原型链的查找机制
function Fn() {
    var n = 100;
    this.AA = function () {
        console.log(`AA[私有]`);
    };
    this.BB = function () {
        console.log(`BB[私有]`);
    };
}
Fn.prototype.AA = function () {
    console.log(`AA[公]`);
};

var f1 = new Fn;
var f2 = new Fn;

console.log(f1.n);

原型修改

如果我们是在原型上增加或者修改属性或者方法这不会修改原型的constructor

function Fn() {
  ...
}
fun.prototype.a = function () {
       ...
}
fun.prototype.b = function () {
       ...
}

原型重定向

在实际项目基于面向对象开发的时候(构造原型设计模式),我们根据需要,很多时候会重定向类的原型(让类的原型指向自己开辟的堆内存)
如果自己进行原型的重定向,需要注意以下问题:

  • 自己开辟的堆内存中没有constructor属性,导致类的原型构造函数缺失
  • 当原型重定向后,如果原来的原型堆内存没有被重定向之前创建的实例所指向(重定向之前的实例指向原有原型),那么浏览器默认开辟的那个原型堆内存会被释放掉,如果之前已经存储了一些方法或者属性,这些东西都会丢失(所以:内置类的原型不允许重定向到自己开辟的堆内存,因为内置类原型上自带很多属性方法,重定向后都没了,这样是不被允许的)


    内置类原型不能重定向

    内置类原型不能重定向

    当我们需要给类的原型批量设置属性和方法的时候,一般都是让原型重定向到自己创建的对象中。

function Fn() {
    ...
}
Fn.prototype = {
    constructor: Fn,  //如果不写这个,默认根据原型链查找会指向Object
    aa: function () {

    }
}
//41.课件7&练习题讲解[15]-构造函数和原型链的运行机制
1.function Fn() {
2.    this.x = 100;
3.    this.y = 200;
4.    this.getX = function () {
5.        console.log(this.x);
6.    }
7.}
8.Fn.prototype.getX = function () {
9.    console.log(this.x);
10.};
11.Fn.prototype.getY = function () {
12.    console.log(this.y);
13.};
14.var f1 = new Fn;
15.var f2 = new Fn;
16.console.log(f1.getX === f2.getX);
17.console.log(f1.getY === f2.getY);
18.console.log(f1.__proto__.getY === Fn.prototype.getY);
19.console.log(f1.__proto__.getX === f2.getX);
20.console.log(f1.getX === Fn.prototype.getX);
21.console.log(f1.constructor);
22.console.log(Fn.prototype.__proto__.constructor);
23.f1.getX();
24.f1.__proto__.getX();
25.f2.getY();
26.Fn.prototype.getY();
图解

答案
//44.课件10&练习题讲解[18]-关于原型重定向问题.flv
function fun() {
    this.a = 0;
    this.b = function () {
        alert(this.a);
    }
}

fun.prototype = {
    b: function () {
        this.a = 20;
        alert(this.a);
    },
    c: function () {
        this.a = 30;
        alert(this.a)
    }
};
var my_fun = new fun();
my_fun.b();
my_fun.c();
图解

没有在_proto_设置的是私有属性

私有公有属性是相对于实例或者原型来说的
//45.课件11&练习题讲解[19]-关于原型重定向问题综合练习
function Fn() {
    var n = 10;
    this.m = 20;
    this.aa = function () {console.log(this.m);}
}
Fn.prototype.bb = function () {console.log(this.n);};
var f1=new Fn;
Fn.prototype={
    aa:function(){console.log(this.m+10);}
};
var f2=new Fn;
console.log(f1.constructor);
console.log(f2.constructor);
f1.bb();
f1.aa();
// f2.bb();
f2.aa();
f2.__proto__.aa();
答案:
console.log(f1.constructor);//Fn
console.log(f2.constructor);//Object
f1.bb();//undefined
f1.aa();//20
f2.bb();//报错:f2.bb is not a function
f2.aa();//20
f2.__proto__.aa();//NaN
图解

你可能感兴趣的:(原型(prototype)、原型链(_proto_)、类)