无法加载

JS原型链

FavoriteLoading收藏

1、prototype原型对象

js规定,每个构造函数都有一个prototype,其实prototype就是一个对象,这个对象的属性和方法都会被构造函数所拥有。

我们可以把那些不变的方法定义在prototype对象上,其实所有对象的实例就可以共享这些方法。

话不多说,上代码。

  <script>
    function Person(name,age){
      this.name=name
      this.age=age
      this.hobby=function(){
        console.log("唱歌")
      }
    }
    var xm=new Person('小明','10')
    var xh=new Person('小红','12')
    console.log(xm.hobby===xh.hobby)  //输出false    
    xm.hobby()//唱歌
    xh.hobby()//唱歌
  </script>

es6之前是把方法写在构造函数里面,每个对象都会去开辟一个函数的内存空间,所以xm.hobby===xh.hobby比较会返回false,如果有多个对象,这样做会存在浪费内存空间,下面建议用prototype对象

  <script>
    function Person(name,age){
      this.name=name
      this.age=age
    }
    Person.prototype.hobby=function(){
        console.log("唱歌")
      }
    var xm=new Person('小明','10')
    var xh=new Person('小红','12')
    console.log(xm.hobby===xh.hobby)  //输出true
    xm.hobby()//唱歌
    xh.hobby()//唱歌
  </script>

此时hobby为同一个方法,所以xm.hobby===xh.hobby返回true

一般来说,公共属性定义在构造函数里面,公共方法定义在原型对象身上

2、_proto_对象原型

其实在每个对象中会有一个_proto_属性指向我们的构造函数的原型对象prototype

<script>
    function Person(name,age){
      this.name=name
      this.age=age
    }
    Person.prototype.hobby=function(){
        console.log("唱歌")
      }
    var xm=new Person('小明','10')
    var xh=new Person('小红','12')
    console.log(xm._proto_===Person.prototype)  //输出true
  </script>

hobby()方法的查找规则:首先看看xm对象身上是否有hobby方法,如果有就执行它,如果没有,因为有_proto_的存在,就会去构造函数原型对象prototype身上去查找。

在JavaScript的原型链体系中,最重要的莫过于 __proto__ 属性,只有通过它才能将原型链串联起来。 我们先实例化一个字符串,然后在输出字符串的值,具体代码如下:

Function.prototype.a='a'; 
Object.prototype.b='b'; 
function Person(){} 
var p = new Person; 
console.log('p.a',p.a); 
console.log('p.b',p.b);

上面的代码需要输出实例p的a属性和b属性的值,所以我们需要先了解实例p的属性查找过程,属性的查找是根据 __proto__ 属性沿着原型链来完成的,因此我们需要先梳理出实例p的原型链。

//实例p的原型链 
P.__proto__ = Person.prototype; 
//Person原型对象的原型 
Person.prototype.__proto__ = Object.prototype;

因此实例输出p的属性时,最终会找到Object.prototype中去,根据一开始定义的值可以得到以下的结果:

p.a undefined 
p.b b

3、原型constructor构造函数

 <script>
    function Person(name,age){
      this.name=name
      this.age=age
    }
    Person.prototype={//如果我们修改了原来的原型对象,给原型对象赋值的是一个对象,则必须手动的利用constructor指回原来的构造函数。
      constructor:Star,
      hobby1:function(){
          console.log("唱歌")
        }
      hobby2:function(){
          console.log("跳舞")
        }
    }
    var xm=new Person('小明','10')
    var xh=new Person('小红','12')
    console.log(xm.prototype.constructor)
    console.log(Star.prototype.constructor)  
  </script>

4、原型链

对象的每个实例都具有一个 __proto__ 属性,指向的是构造函数的原型对象,而原型对象同样存在一个 __proto__ 属性指向上一级构造函数的原型对象,就这样层层往上,直到最上层某个原型对象为 null。

在JavaScript中几乎所有的对象都具有 __proto__ 属性,由 __proto__ 属性链接而成的链路构成了 JavaScript的原型链,原型链的顶端Object.prototype,他的 __proto__ 属性为null。

我们通过一个实例来看看一个简单的原型链过程,首先定义一个构造函数,并生成一个实例。

function Person(){} 
var person = new Person();

然后person实例沿着原型链第一次追溯, __proto__ 属性指向Person()构造函数的原型对象

console.log(person.__proto__ === Person.prototype);

person实例沿着原型链第二次追溯,Person原型对象的 __proto__ 属性指向Object类型的原型对象。

console.log(person.__proto__.__proto__ === Person.prototype.__proto__);

person实例沿着原型链第三次追溯,Object类型的原型对象的 __proto__ 属性为null

console.log(person.__proto__.__proto__.__proto__ === Object.prototype.__proto__=== null);

5、原型链的特点

原型链的特点主要有以下两个:

1. 由于原型链的存在,属性查找的过程不在是只查找自身的原型对象,而是会沿着整个原型链一直向上,知道追溯到Object.prototype,如果Object.prototype上也找不到该属性,则返 回’undefined’,如果期间在实例本身或者某个原型对象上找到了该属性,则会直接返回结果,因此 会存在属性覆盖的问题,

由于特点1的存在,我们在生成在定义对象的实例时,也可以调用到某些未在在定义构造函数上的函数,例如toString()函数。

function Person(){} 
var p = new Person(); 
p.toString(); //Object Object 实际调用的是Object.prototype.toString()函数

2. 由于属性查找会经历整个原型链,因此查找的链路越长,对性能的影响越大。

6、属性区分

对象属性的寻找往往会涉及这个原型链,那么该怎么区分属性是实例自身还是从原型链中继承的呢? Object()构造函数的原型对象中提供了一个hasOwnProperty()函数,用于判断属性是否为自身拥有的。

function Person(name){ 
//实例属性name 
this.name = name; 
}
//原型对象上的属性age 
Person.prototype.age = 12; 
var person = new Person('cao teacher'); 
console.log(person.hasOwnProperty('name')); console.log(person.hasOwnProperty('age'));

7、内置构造函数

JavaScript中有一些特定的内置构造函数,如String()函数,Number()构造函数,Array()构造函数, Object()构造函数等。 它们本身的 __proto__ 属性都统一指向Function.prototype

console.log(String.__proto__ === Function.prototype); 
console.log(Number.__proto__ === Function.prototype); 
console.log(Array.__proto__ === Function.prototype); 
console.log(Object.__proto__ === Function.prototype); 
console.log(Date.__proto__ === Function.prototype); 
console.log(Function.__proto__ === Function.prototype);

留下评论

微信:15182814906

QQ:1548902957

邮箱:1548902957@qq.com