原型:
每个对象都可以有一个原型_proto_,这个原型还可以有它自己的原型,以此类推,形成一个原型链。查找特定属性的时候,我们先去这个对象里去找,如果没有的话就去它的原型对象里面去,如果还是没有的话再去向原型对象的原型对象里去寻找...... 这个操作被委托在整个原型链上,这个就是我们说的原型链了。
原型指针:
- prototype: prototype属性,它是函数所独有的,它是从一个函数指向一个对象。它的含义是函数的原型对象,也就是这个函数(其实所有函数都可以作为构造函数)所创建的实例的原型对象; 这个属性是一个指针,指向一个对象,这个对象的用途就是包含所有实例共享的属性和方法(我们把这个对象叫做原型对象);
- __proto__: __proto__ 是原型链查询中实际用到的,它总是指向 prototype,换句话说就是指向构造函数的原型对象,它是对象独有的。注意,因为JS中,包括函数,万物皆对象,所有也有这个属性;
- constructor: 每个函数都有一个原型对象,该原型对象有一个constructor属性,指向创建对象的函数本身。此外,我们还可以使用constructor属性,所有的实例对象都可以访问constructor属性,constructor属性是创建实例对象的函数的引用。我们可以使用constructor属性验证实例的原型类型(与操作符instanceof非常类似)。由于constructor属性仅仅是原始构造函数的引用,因此我们可以使用该属性创建新的对象。
从一个函数里创建一个对象o,它自身拥有属性a和b的: let f = function() { this.a = 1; this.b = 2; } let o = new f(); // {a: 1, b: 2} // 在f函数的原型上定义属性 f.prototype.b = 3; f.prototype.c = 4; console.log(o); console.log(o.a, o.b, o.c, o.d);
- a是o的自身属性,该属性值为 1;
- b是o的自身属性,该属性值为 2,原型上b属性会发生"属性遮蔽",不会被访问到;
- c不是o的自身属性,就看它的原型链上有没有,c是o.[[Prototype]]的属性,值为 4;
- d不是o的自身属性,原型链上也没有这个属性,返回 undefined;
原型链的继承:
继承的父类:
function Person(name) { this.name = name; this.read() = function() { console.log(this.name); } } Person.prototype.age = 10;
原型链继承:
function Student() {} Student.prototype = new Person() var student1 = new Student(); var student2 = new Student(); console.log(student1.name, student2.name); student1.name.push('tiger'); // 原型上的属性是共享的,一个实例修改了原型属性,另一个实例的原型属性也会发生变化 console.log(student1.name, student2.name);
让构造的原型等于父类的实例。
特点:实例可继承的属性有:实例的构造函数的属性,父类构造函数属性,父类原型的属性。(新实例不会继承父类实例的属性!)
缺点:1、新实例无法向父类构造函数传参。2、继承单一。3、所有新实例都会共享父类实例的属性。