原型及原型链

JS中的原型和原型链

讲原型的时候,我们应该先要记住以下几个要点,这几个要点是理解原型的关键:

1、所有的引用类型(数组、函数、对象)可以自由扩展属性(除null以外)。

2、所有的引用类型都有一个’_ _ proto_ _'属性(也叫隐式原型,它是一个普通的对象)。

3、所有的函数都有一个’prototype’属性(这也叫显式原型,它也是一个普通的对象)。

4、所有引用类型,它的’_ _ proto_ _'(对象用原型)属性指向它的构造函数的’prototype’属性。

5、当试图得到一个对象的属性时,如果这个对象本身不存在这个属性,那么就会去它的’_ _ proto_ _'属性(也就是它的构造函数的’prototype’属性)中去寻找。

每个函数都有prototype(原型)属性,这个属性是一个指针,指向一个对象,这个对象的用途是包含特定类型的所有实例共享的属性和方法,即这个原型对象是用来给实例共享属性和方法的。而每个实例内部都有一个指向原型对象的指针。

综上_ _proto_ _是一个引用类型(实例)的属性,是个对象,指向它构造器(类)的prototype

prototype构造器(构造函数,函数)的属性,是个原型对象,用来给实例共享属性和方法。

prototype 原型

㈠原型 Prototype

⑴我们所创建的每一个函数,解析器都会向函数中添加一个属性Prototype

    这个属性对应着一个对象,这个对象就是我们所谓的原型对象

⑵如果函数作为普通函数调用prototype没有任何作用

   当函数以构造函数的形式调用时,它所创建的对象中都会有一个隐含的属性

   指向该构造函数的原型对象,我们可以通过_ _prototype_ _来访问

⑷原型对象就相当于一个公共的区域,所有同一类的实例都可以访问到这个原型对象

    我们可以将对象中共有的内容,统一设置到原型对象中。

⑸当我们访问对象的一个属性或方法时,它会先在对象自身中寻找,如果有则直接使用,

   如果没有则会去原型对象中寻找,如果找到则直接使用

我们创建的每一个函数都有一个prototype属性,这个属性是一个指针,指向一个对象,这个对象包含了通过调用该构造函数所创建的对象共享的属性和方法

原型指的就是一个对象,是构造函数内部有一个名为 prototype 的属性作用:用来给实例共享属性和方法,实例“继承,在原型上定义的属性,使实例也拥有了这个属性。“继承”这个行为是在 new 操作符内部实现的。实例的_ _proto_ _属性也指向它。

原型对象中有个constructor属性,指向实例的构造函数

原型对象中还有个_ _proto_ _属性,指向其父构造函数的prototype。

 

 

 prototype和构造函数间的关系

既然构造函数通过 prototype 来访问到原型,那么原型也应该能够通过某种途径访问到构造函数,这就是 constructor:

 

 

 

 

 

 

 

 原型链:

 

 

 

构造函数创建实例的缺点:会为每个对象的方法,开辟存储空间,浪费了内存,处理方法原型。

prototype和__proto__的constructor都是表示这两对象是由哪个构造函数创建出来的。

如果修改原型对象,给原型对象赋值的是一个对象,则必须手动的利用constructor指回原来的对象。

什么是原型? 它是一个对象

每个函数都有prototype(原型)属性,这个属性是一个指针,指向一个对象,这个对象的用途是包含特定类型的所有实例共享的属性和方法,即这个原型对象是用来给实例共享属性和方法的。

而每个实例内部都有一个指向原型对象的指针。

原型的作用?共享方法

 

原型链:实例的__proto__指向它构造函数的prototype,构造函数的prototype.__proto__指向它自己父类的prototype对象

(当实例对象使用某方法时,会按照原型链的方法一级一级往上找直至找到为止)

原型

我们先来看一个原型的例子。

//这是一个构造函数
function Foo(name,age){
this.name=name;
this.age=age;
}
/*根据要点3,所有的函数都有一个prototype属性,这个属性是一个对象
再根据要点1,所有的对象可以自由扩展属性
于是就有了以下写法*/
Foo.prototype={
// prototype对象里面又有其他的属性
showName:function(){
console.log("I'm "+this.name);//this是什么要看执行的时候谁调用了这个函数
},
showAge:function(){
console.log("And I'm "+this.age);//this是什么要看执行的时候谁调用了这个函数
}
}
var fn=new Foo('小明',19)
/*当试图得到一个对象的属性时,如果这个对象本身不存在这个属性,那么就会去它
构造函数的'prototype'属性中去找*/
fn.showName(); //I'm 小明
fn.showAge(); //And I'm 19

这就是原型,很好理解。那为什么要使用原型呢?

试想如果我们要通过Foo()来创建很多很多个对象,如果我们是这样子写的话:

function Foo(name,age){
this.name=name;
this.age=age;
this.showName=function(){
console.log("I'm "+this.name);
}
this.showAge=function(){
console.log("And I'm "+this.age);
}
}

那么我们创建出来的每一个对象,里面都有showName和showAge方法,这样就会占用很多的资源。
而通过原型来实现的话,只需要在构造函数里面给属性赋值,而把方法写在Foo.prototype属性(这个属性是唯一的)里面。这样每个对象都可以使用prototype属性里面的showName、showAge方法,并且节省了不少的资源。

请给Array本地对象增加一个原型方法,它用于删除数组条目中重复的条目(可能有多个),返回值是一个包含被删除的重复条目的新数组。

 

Array.prototype.distinct = function() {

 var ret = [];

 for (var i = 0; i < this.length; i++) {

    for (var j = i+1; j < this.length;) {

        if (this[i] === this[j]) {

            ret.push(this.splice(j, 1)[0]);

        } else {

            j++;

        }

    }

 }

 return ret;

}

//for test

alert(['a','b','c','d','b','a','e'].distinct());

 

参考:https://blog.csdn.net/qq_36996271/article/details/82527256

posted @ 2021-04-24 10:33  浣熊sky  阅读(114)  评论(0编辑  收藏  举报