原型,原型链

125 阅读5分钟

原型

原型是什么

原型是 function 对象的一个属性,它定义了构造函数制造出的对象的公共祖先。 通过该构造函数产生的对象,可以集成该原型的属性和方法 原型也是对象

 
        function Person() {

        }
         Person.prototype = {}; 
        //  1:prototype是function 的一个属性
        //  2:prototype是一个对象

         Person.prototype.run= function(){
           console.log("person 会 run  ")
         }

        function student() {}
        student.prototype = {} 

利用原型的特点 和概念,可以提取共有属性

原型的增删改查

和操作对象一样 Person.prototype.属性 = 属性值;

构造函数名.prototype.要增加在原型上的属性名 = ‘值’

delete Person.prototype.属性

delete 构造函数名.prototype.要删除的原型上的属性名

直接再赋值 即可修改

person1.lastName = "li";

构造函数名.prototype.要修改的原型上的属性名 = ‘值’

访问属性方法 就近原则

   function Person() {

    }
    Person.prototype = {};
   
    Person.prototype.lastName = "zhang"
    let person1 = new Person();
    person1.lastName = "wang";
    console.log( person1.lastName)  ----->wang

原型上方法中this的指向

Person.prototype = {

	name = 'a',

	sayName : function(){

			console.log(this.name);

		} 

	}

	function Person(){ 

	 	this.name = 'b';

	} 

	var person = new Person();

 	sayName 里面的this指向是,谁调用的这个方法,this指向谁;

	所以最终结果person.sayName() 的值为b

	而Person.prototype.sayName() 的值为a 

对象如何查看对象的构造函数

----constructor

var a = {}
a.constructor
    ---->  ƒ Object() { [native code] }
    
    
function Person(){}
var p1 = new Person();
p1.constructor
---------->ƒ Person(){}
var a = 1;

a.constructor
------>ƒ Number() { [native code] }
var  a  ="str"

a.constructor
------>  ƒ String() { [native code] }
function  a(){}

a.constructor
------>ƒ Function() { [native code] }

a 是一个函数,函数本质上也是一个对象,它是通过 内置的Function 函数构造的,
它的constructor属性指向它的构造函数Function
function  a(){}
a.constructor
----->ƒ Function() { [native code] }
Function.constructor
-------->ƒ Function() { [native code] }  内置对象Function的构造函数是它自己
a.prototype.constructor
ƒ a(){}
function  a(){}
a.prototype = {}

a.prototype.constructor
----->ƒ Object() { [native code] }

a.prototype.constructor ={name: "str"}


a.prototype
  展开对象:
  ---->  constructor: {name: "str"}
  ----> __proto__: Object
  constructor,我们可以手动改变它的指向哈哈哈
  
  验证:
 var  a1=new  a();
 a1.constructor
----->{name: "str"}

constructor是对象身上的属性,用来查看它的构造函数是哪个的

结论: prototype 是 函数身上的属性 是一个对象,函数身上是没有constructor 属性

pertotype 与constructor的关系

pertotype 是一个对象

这个对象身上有一个内置的属性,constructor,

constructor 中文翻译叫 构造器,

constructor 指向的是 该对象的构造函数,即它是谁造出来的

《constructor的定义是要指向原型属性对应的构造函数的》

__proto__

是啥, 啥用

先看下__proto__在哪儿,是个什么东西

function A(){}

var a = new A()

console.log(a)
输出A {}
展开  __proto__: Object
可以看到有一个内置的属性 __proto__:指向一个对象

发现 它是 (实例对象)/对象的一个属性

看下面两张图,来看看这个内置的属性 proto:指向的对象是什么

我们给原型加属性,最后发现给原型加的东西都可以在__proto__ 指向的对象中找到,于是得出结论,它指向的是构造函数的原型。

来看解释吧,

之前说构造函数原理的时候说,第一步会生成一个空的this = {},

其实在new的时候 隐式新建的this对象并不是空的

function  A(){

      var this = {
          __proto__:A.prototype
      }
    }
    var a = new  A();

其实在new的时候 隐式新建的this对象并不是空的,而是里面有一个 __proto__属性,指向的是当前函数的原型

___proto___有什么用呢

当你访问 这个对象的属性时,如果你没有这个属性,系统就会通过__proto__ 指向的索引,去找你访问的属性

相当于一个连接的作用

比如 当访问 a.name 的时候,a对象身上没有name 属性,就会去找 ___proto___指向的那个对象(原型) 身上有没有name属性

为什么说 对象访问属性的时候先访问自己,没有还可以访问原型身上的属性呢,就是因为有___proto__

___proto___指向可手动更改

图一

图一 可看得出:___proto___指向可手动更改可手动去改变

图 二

图二 是修改了属性值,所以 输出的是 456

图 三

图三 是换血了啊,

___proto__指向的对象的引用是A.prototype.name = "123";

即便A.prototyp 换了对象, ___proto_\的引用不变

是先new的,再A的prototype 换了,所以 ___proto__指向的对象的引用不变

比如: var arr = [1,2]

var arr1 = arr ;

arr = [1,3];

此时 arr1 仍然是[1,2]

图四

调整下顺序 A的prototype 换了指向后,再new

如下图

原型链

        function Grand() {}
        Grand.prototype.lastName = "li";
        var grand = new Grand();

        function Father() {}
        Father.prototype = grand;
        var father = new Father();

        function Son() {}

        Son.prototype = father;
        var son = new Son();
        son.lastName;------>"li"
        
        

把各个原型连在一起,就形成了原型链,连接点: ___proto__

son身上没有lastName属性,于是就通过__proto__一层一层往上找,形成的这个链就是原型链 绝大多数对象的最终都会继承自Object.prototype

但不是所有的对象都可以继承,特例:Object.creat()原型;

例如:object.creat(null) ,该对象没有prototype原型;

![]

原型链上 属性的 增删改查

查:

就是一直往下找,找到为止,找不到就返回undefined

能给原型链上的任何一个原型增加它的属性吗?

仅限自己能够增加自己原型链上的属性

仅限自己能够修改自己原型链上的引用值得属性,原始值类型的属性无法修改

修改自己原型链上的引用值的属性

修改原始值类型的属性

删除

能给原型链上的任何一个原型删除它的属性吗?

仅限自己能够删除自己原型链上的属性

一个额外的知识点

    123.toString();

会报错

是因为:

这句代码中把 . 当作浮点了,而不是方法调用的那个点,所以会报错

如果想要调用,可以写如下代码

   var  num = 123;
    num.toString();
   [ new Number(123).toString()] ------- 隐式调用
   
   
   想改变返回的结果,可以重写:
 Number.prototype.toString =  function(){
 //重写返回的自定义内容
return "今天重写了 Number身上的toString()方法 "
 }
        
num.toString()
      输出----》【 "今天重写了 Number身上的toString()方法 "
   Number.prototype.__proto__ = Object.prototype;
 Object.prototype.toString.call(123)
        输出 ---->
        "[object Number]"

所以 为了输出更有意义的东西,我们有时会需要重写

call apply