8. 原型 与 原型链,constructor属性

目录

一、原型

1. 原型概念:

2. 原型示例:

3. __proto__表示隐式原型,prototype表示显式原型

二、原型链

1. 原型链示例

2. 完整的原型链结构

三、constructor属性


constructor属性(__proto__原型对象中包含constructor属性,实例当中也同样会继承这个属性): 实例对象person -》 __proto__  -》constructor(Person)
prototype属性(
constructor.prototype原型对象):constructor -》 prototype

     

一、原型

1. 原型概念:

每个函数和类都有一个显式原型prototype,里面存放一些公用的属性和方法,这些方法和属性,其每一个实例都能访问到

而且每一个实例的对象都有一个隐式的原型__proto__,对象的隐式原型都指向构造这个对象的函数或类的显式原型

使用原型对象的好处:是可以让所有对象实例共享它所包含的属性和方法

2. 原型示例

定义Student类 ,实例化该类并传入'聪聪',99,得到一个实例对象stu。

该实例对象中有一个__proto__属性,即为该对象的隐式原型。

stu.play():  在对象stu寻找play方法,=>  若在该对象中找不到,=>  则去其隐式原型__proto__中去寻找 

3. __proto__表示隐式原型,prototype表示显式原型

实例对象的隐式原型 指向 构建该实例对象的类的显式原型,即

         

4. 构造函数,实例对象和原型对象是怎么挂载的?

构造函数和实例对象不直接相连,实例对象的隐式原型__proto__指向构造函数的显示原型prototype。即都指向实例对象。

5. 获取原型的3种方法?

  function R() {
  }
  var one = new R();
  console.log(Object.getPrototypeOf(one));	//方法1:官方推荐,规范写法
  console.log(one.__proto__);				//方法2:不推荐
  console.log(one.constructor.prototype)	//方法3:不推荐

二、原型链

1. 原型链示例

Person类 -》 继承Person的Teacher类  -》 创建Teacher类的实例对象teacher

(1)teacher.teach(); 调用teach方法

        过程:1) teacher先在自身查找,如果没有teach方法,就去隐式原型__proto__查找 (teacher的隐式原型__proto__ 指向  Teacher类的显式原型prototype)

                   2)Teacher类的显式原型prototype中有teach方法,直接调用

(2)teacher.drink(); 调用drink方法

       过程:1) teacher先在自身查找,如果没有drink方法,再去其隐式原型__proto__查找 (teacher的隐式原型__proto__ 指向  Teacher类的显式原型prototype)

                 2)Teacher类的显式原型prototype中没有drink方法,再去Teacher类显式原型的隐式原型__proto__中查找(Teacher类显式原型的隐式原型 指向Person类的显式原型 

                 3)  Person类的显式原型prototype中有drink方法,调用

2. 完整的原型链结构

到Object对象终止

三、原型和原型链常考面试题

(1)构造函数的原型

因为是一个函数,所以原型为Function。

构造函数实例对象的隐式原型 指向 构造函数的显示原型

let f = new Function(); //构造函数Function 的实例对象为f;

console.log(Function.prototype) //指向“内置函数” ƒ () { [native code] }
console.log(f.__proto__) //指向“内置函数” ƒ () { [native code] }
console.log(f.__proto__===Function.prototype) //true
console.log(Object.prototype.toString.call(f.__proto__)) // [object Function]

(2)Object的原型

一切对象都有一个根源 Object.prototype,根源之上再没有其它根源:

let obj = new Object(); //Object的实例对象obj。等价于 let obj = {}

console.log(obj.__proto__ === Object.prototype)  //true。
console.log(Object.prototype) // Object。 指向"根源对象"(原型链最顶层)
console.log(obj.__proto__ ) // Object。指向"根源对象"(原型链最顶层)
console.log(Object.prototype.__proto__) //null 。

 Object.getPrototypeOf(obj): 返回指定对象obj的原型

(3)原型和原型链的面试题1

//有关原型与原型链的面试题目
{
	function Fn(){
		this.x = 100;
		this.y = 200;
		this.getX = function () {
			console.log(this.x);
		}
	}
	Fn.prototype.getX = function () {
		console.log(this.x);
	};
	Fn.prototype.getY = function () {
		console.log(this.y);
	};
	var f1 = new Fn;
	var f2 = new Fn;
	console.log(f1.getX === f2.getX);	//false
	console.log(f1.getY === f2.getY);	//true
	console.log(f1.__proto__.getY === Fn.prototype.getY);	//true
	console.log(f1.__proto__.getX === f2.getX);		//false
	console.log(f1.__proto__.getX === Fn.prototype.getX);	//true
	console.log(f1.constructor);	//Fn
	console.log(Fn.prototype.__proto__.constructor);	//Object !!!
	f1.getX();	//100	this=>f1
	f1.__proto__.getX();	//undefined 	this=>f1.__proto__(Fn.prototype)
	f2.getY();	//200	this=>f2
	Fn.prototype.getY();	//undefined	this=>f2.__proto__(Fn.prototype)
}
// false,true,true,false,true,Fn,Object,100,undefined,200,undefined

let Peppa = new Pig() 为例 :

 (4)原型和原型链的面试题2

// 原型、原型链
{
	function fun(){
		this.a = 0;
		this.b = function(){
			console.log(this.a);
		}
	}
	fun.prototype = {
		b: function(){
			this.a = 20;
			console.log(this.a);
		},
		c: function(){
			this.a = 30;
			console.log(this.a);
		}
	}
	var my_fun = new fun();
	my_fun.b();	// 打印0。 私有方法	this=>my_fun 打印0
	console.log(my_fun.a); // 打印0。
	my_fun.c();	//打印30。公有方法	this=>my_fun this.a = 30(将私有属性a修改为30)
	console.log(my_fun.a); // 打印30.
	var my_fun2 = new fun();
	console.log(my_fun2.a); // 打印0。
	my_fun2.__proto__.c();	//打印30. this=>my_fun2.__proto__ 当前实例通过原型链在类的共有属性上增加了一个a:30
	console.log(my_fun2.a); //打印0
	console.log(my_fun2.__proto__.a); //打印30
}
// 0,0,30,30,0,30,0,30

  (5)原型和原型链的面试题3

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.  构造函数Foo还未调用
let obj = new Foo(); 
obj.a(); //2.  构造函数Foo中,this指向obj,指向this.a
Foo.a(); //1.  构造函数Foo已调用,Foo.a 覆盖外层的Foo.a

// 结果:4  2  1

解析:

Foo.a() 的输出值为 4。此时并没有调用 Foo 构造函数。
obj.a() 的输出值为 2。虽然原型上也有 a 方法。但是实例对象 obj 上也有 a 方法,所以会先在自身找,找不到时才去原型链上找。
Foo.a() 的输出值为1。调用了构造函数 Foo 之后,Foo 内部的 this.a 方法覆盖了外层的 Foo.a

(6)原型和原型链的面试题4

 写出以下实例对象的所有原型链。

function Person(name){
 this.name = name;
};
var jack = new Person("jack");

解析:

实例对象的原型链:

jack.__proto__ === Person.prototype;
Person.prototype.__proto__ === Object.prototype;
jack.__proto__.__proto__ === Object.prototype;

构造函数的原型链:

Person.__proto__ === Function.prototype;
Function.prototype === Function.__proto__;
Function.prototype.__proto__ === Object.prototype;
Function.__proto__.__proto__ === Object.prototype;
Person.__proto__.__proto__ === Object.prototype;

四、constructor属性

1. 每个实例对象都有隐式原型__proto__,该原型的constructor属性,指向创建这个对象的构造函数

例如:对象person的constructor属性,指向构造函数Person

     

   

2.每个函数都有显式prototype属性,该原型的constructor属性会指向这个函数(其 实例对象的__proto__ 指向 其prototype,故指向的是同一个constructor)。

如果我们重写(重新定义)这个Person.prototype属性,那么constructor属性的指向就会发生改变了。

 

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值