原型和原型链

原型对象

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

为什么需要原型

在JS没有引入‘类’这个概念之前,当我们创建好对象时往往会采用构造器的方式进行创建,如果属性比较多,在产生对象时会耗费大量的内存资源。通过直接对原型对象的修改就很好的解决了这个问题。

使用构造器创建对象

function Person(name, age) {
	this.name = name;
	this.age = age;
	this.say = function () {
		console.log('hi~');
	}
}

let zhangwei = new Person('张伟', 18);

当把一个函数作为构造函数 使用new创建对象的时候,那么这个对象就会存在一个默认的不可见的属性,来指向了构造函数的原型对象。这个不可见的属性我们一般用[[prototype]]来表示,只是这个属性没有办法直接访问到。

new干了什么?

  • 创建对象,在堆内存中开辟一个空间
  • this指向这个对象
  • 对象的__proto__属性和构造器的prototype属性同时指向构造器的原型对象
  • 执行构造函数
  • 返回this

原型链

原型对象链

  1. 新对象都有一个属性叫__proto__,通过这个属性可以找到对象的原型对象
  2. 构造函数都有一个属性 叫prototype,通过这个属性可以找到构造器的原型对象
  3. 构造函数的原型对象上有一个属性 叫constructor 指向构造函数
  4. 所有的原型对象都是Object函数对象构造出来的(除Object本身的原型对象之外)

原型函数链

  1. 所有的函数都是Function函数对象构造的
  2. Function顶层没有人构造 自己构造了自己
  3. Person是一个函数 Person是一个对象

原型链

  person.__proto__  ---> Person,prototype
  person.__proto__.__proto__   --->  object.prototype
  person.__proto__.__proto__ .__proto__  --->  null
  Person.__proto__  ---> Function.prototype
  Person.__proto__.__proto__  ---> object.prototype
  Person.__proto__.__proto__.__proto__  ---> null
  Function.__proto__  --->  Function.prototype
  Function.__proto__.__proto__   --->  object.prototype
  Function.__proto__.__proto__ .__proto__  --->  null
  • 构造函数、原型和实例的关系
    • 构造函数都有一个属性prototype,这个属性是一个对象,是Object的实例;
    • 原型对象prototype里有一个constructor属性,该属性指向原型对象所属的构造函数;
    • 实例对象都有一个__proto__属性,该属性指向构造函数的原型对象
    • obj.proto===Object.prototype
  • prototype与_proto_的关系
    • prototype是构造函数的属性;
    • __proto__是实例对象的属性;
    • 两者都指向同一个对象;

原型链作为继承的基本思想是利用原型让一个引用类型继承另一个引用类型的属性和方法
每个构造函数都有一个原型对象prototype,原型对象都包含一个指向构造函数的指针constructor,而实例都包含一个指向原型对象的内部指针 [[prototype]]。
如果让原型对象等于另一个类型的实例,那么原型对象将包含一个指向另一个原型的指针,相应地,另一个原型中也包含着一个指向另一个构造函数的指针。
通过实现原型链,本质上扩展了原型搜索机制,当以读取模式访问一个实例属性时,首先会在实例中搜索该属性。如果没有找到该属性,则会继续搜索实例的原型。在通过原型链实现继承的情况下,搜索过程就得以沿着原型链继续向上。
总结

  1. 所有的原型对象都是由Object函数对象创建的
  2. Function函数对象由自己Function,Function.proto == Function.prototype
  3. 所有的函数都是由Function函数对象创建
  4. 构造函数创建的对象,对象的proto指向构造函数的prototype
  5. 不是构造函数创建的对象,对象的proto指向Object函数对象的prototype
  6. 对象访问某个属性,如果自己身上有这个属性 优先访问自己的 如果没有再访问原型链上的 沿着原型链依次往上层链找
// 练习题1
function SuperType(name) {
	this.name = name;
	this.colors = ["red", "blue", "green"];
}
SuperType.prototype.sayName = function() {
	console.log(this.name);
};

function SubType(name, age) {
	SuperType.call(this, name);
	this.age = age;
}
SubType.prototype = new SuperType();
SubType.prototype.sayAge = function() {
	console.log(this.age);
};

var instance1 = new SubType("Nicholas", 29);
instance1.colors.push("black");
console.log(instance1.colors); 
instance1.sayName(); 
instance1.sayAge(); 

var instance2 = new SubType("Greg", 27);
console.log(instance2.colors); 
instance2.sayName(); 
instance2.sayAge();

// 练习题2
function Foo() {
	Foo.a = function() {
		console.log(1);
	}
	this.a = function() {
		console.log(2);
	}
}
Foo.prototype.a = function() {
	console.log(3);
}
Foo.a = function() {
	console.log(4);
}
Foo.a(); // 4
var obj = new Foo();
obj.a(); // 2
Foo.a(); //1

// 练习题3
function One() {}

function Two() {}

function Three() {}
Two.prototype = new One();
Three.prototype = new Two(); 
var three = new Three();

console.log(three.__proto__ === Three.prototype);
console.log(three.__proto__.__proto__ === Two.prototype);
console.log(three.__proto__.__proto__.__proto__ === One.prototype);
console.log(three.__proto__.__proto__.__proto__.__proto__ === Object.prototype);

// 练习题4 
function Person() {
	this.name = 'qwer';
}
var person1 = new Person();

Person.prototype.w = '这是w属性';
Function.prototype.q = '这是q属性';
Object.prototype.e = '这是e属性';

console.log(person1.w); 
console.log(person1.q); 
console.log(person1.e); 

console.log(Person.w);
console.log(Person.q); 
console.log(Person.e);

console.log(Function.q);
console.log(Function.e); 

console.log(Object.q);
console.log(Object.e);

内置函数原型链

通过Number String Boolean Array Function内置函数作为构造器来创建对象,新对象的原型链的__proto__指向这个函数的原型对象,而函数的__proto__指向Function的原型对象,原型链的尽头都是null

var n = 12;
console.log(n.__proto__ === Number.prototype); // true
console.log(Number.prototype.__proto__ === Object.prototype);
console.log(n.__proto__.__proto__ === Object.prototype);
console.log(n.__proto__.__proto__.__proto__ === null);

var str = '123';
console.log(str.__proto__ === String.prototype);
console.log(str.__proto__.__proto__ === Object.prototype);
console.log(str.__proto__.__proto__.__proto__ === null);

var bl = true;
console.log(bl.__proto__ === Boolean.prototype);
console.log(bl.__proto__.__proto__ === Object.prototype);
console.log(bl.__proto__.__proto__.__proto__ === null);

var arr = [];
console.log(arr.__proto__ === Array.prototype);
console.log(arr.__proto__.__proto__ === Object.prototype);
console.log(arr.__proto__.__proto__.__proto__ === null);

var fn = function () {};
console.log(fn.__proto__ === Function.prototype);
console.log(fn.__proto__.__proto__ === Object.prototype);
console.log(fn.__proto__.__proto__.__proto__ === null);

var fnshili = new fn();
console.log(fnshili.__proto__ === fn.prototype);
console.log(fnshili.__proto__.__proto__ === Object.prototype);
console.log(fnshili.__proto__.__proto__.__proto__ === null);
console.log(Number.__proto__ === Function.prototype);
console.log(Boolean.__proto__ === Function.prototype);
console.log(String.__proto__ === Function.prototype);
console.log(Array.__proto__ === Function.prototype);
console.log(Date.__proto__ === Function.prototype);

console.log(Number.__proto__.__proto__ === Object.prototype);
console.log(Boolean.__proto__.__proto__ === Object.prototype);
console.log(String.__proto__.__proto__ === Object.prototype);
console.log(Array.__proto__.__proto__ === Object.prototype);
console.log(Date.__proto__.__proto__ === Object.prototype);
posted @ 2022-08-23 13:35  KongQingzhi  阅读(56)  评论(0)    收藏  举报