JavaScript原型、原型链的个人笔记

一、原型

原型是function对象的一个属性,定义了构造函数制造出来的对象的‘公共祖先’。(js中万物皆对象,原型也是对象)
1.普通对象和函数对象

var test1 = {}/[];
var test2 = new Object();
var test3 = new Test();//test1-3都是普通对象
//Function Object 是通过 New Function()创建的

function Test(){};
var test4 = function(){};
var test5 = new Function('a','console.log(a)');//Test,test4-5都是函数对象
//因为Test,test4-5的根本还是通过Function创建的

2.构造函数
前面章节中讲解过,上面2中function Test( ){ }就是构造函数(大驼峰式命名)

function Car(width,height){//这里Car是构造函数
	this.width = width;
	this.height = height;
	this.say = function (){
		console.log("车宽"+this.width+"m","车高"+this.height+"m");
	}
}
var car1 = new Car(2,1.5);//car1是Car的实例
car1.say();
console.log(car1.constructor);//因为是car1是Car构造的
//所以car1身上的constructor(构造函数属性)指向构造出它的函数

在这里插入图片描述
在这里插入图片描述
3.原型对象
每个函数对象身上都有一个prototype(原型)属性,这个属性指向函数的prototype原型对象(即’公共祖先’)

function Car(){};
Car.prototype.width = 2;
Car.prototype.height = 1.5;
/*
Car.prototype = {
	width = 2;
	height = 1.5;
}//这里就更加清晰, prototype属性指向prototype对象
*/
Car.prototype.say = function (){
	console.log("车宽"+this.width+"m","车高"+this.height+"m");
}
var car2 = new Car();//由Car构造函数构造出来的后代
//可以访问它们的'祖先'prototype(原型)对象的属性
car2.say();
car2.height = 2;//可以给自己添加height属性覆盖'祖先'给自己的属性
car2.say();
console.log(Car.prototype.height);//后代给自己添加属性,不会修改祖先的属性
console.log(car2.constructor);//指向构造它的构造函数Car

在这里插入图片描述
构造函数上的Car.prototype属性指向的prototype对象(普通对象)。
这里再说下说到的constructor属性:默认情况下,所有的原型对象都会自动获得一个 constructor(构造函数)属性,这个属性(是一个指针)指向 prototype 属性所在的函数(Car)
在这里插入图片描述
即:Car.prototype.constructor == Car
然后我们又想到了car2.constructor ==Car,他们之间又有什么联系呢?
因为 Car创建的时候,创建了一个它的实例对象并赋值给它的 prototype

var eg = new Car();
Car.prototype = eg;//原型对象(Person.prototype)是 构造函数(Person)的一个实例

4.特殊情况

function Car(){};
var car2 = new Car();
console.log(typeof(Car.prototype));
console.log(typeof(Object.prototype));
console.log(typeof(Function.prototype));

在这里插入图片描述
前面说了,原型对象是普通对象,为什么这里typeof(Function)会返回function类型呢?
解释:构造函数创建的时候,创建了一个它的实例对象并赋值给它的 prototype,即:

var eg = new Function();//所以eg是函数对象
Function.prototype = eg;

undefined和null没有原型

二、_ proto _

1._ proto _
JavaScript 在创建对象(普通对象和函数对象)时,都有一个__proto__ 内置属性,该属性指向创建它的构造函数的原型对象。即:

function Car(){};
var car3 = new Car();
console.log(Car.prototype);
console.log(car3.__proto__);

在这里插入图片描述
2.隐式创建
和前面章节对象包装类中说的类似

function Student(name,age,sex){
	//1.函数体最前端隐式创建空对象this={}
	this.name = name,
	//2.this = {
	//      __proto__:Student.prototype指向它自己原型
	//		name : name
	//  }将写的属性添加进去
	this.age = age,
	//this = {
	//		name : name,
	//		age : age
	//}
	this.sex = sex
	//...
	//3.return this返回出去
}
var student1 = new Student('jimo',18,'male');//所以student1的__proto__指向创建它的构造函数的原型

三、原型链

1.形成原型链

Grand.prototype.lastName = "Jimo";
function Grand(){};
var grand = new Grand();//grand对象继承了祖先的的lastName属性
console.log(grand.lastName);

Father.prototype = grand;//将对象grand赋给Father的原型
function Father(){
    this.name = "xuxu";
};
var father = new Father();//father就可以拿到lastName属性和它自己的name属性
console.log(father.lastName,father.name);

Son.prototype = father;//同理将对象father赋给Son的原型
function Son(){
     this.hehe = "呵呵";
};
var son = new Son();//son就能拿到lastName、name属性,和自己的hehe属性
console.log(son.lastName,son.name,son.hehe);

在这里插入图片描述
像这样通过原型形成链式结构即为原型链(原型链的终端为Object.prototype.__proto__ == null)
2.设置对象的原型

var obj = {
	this.name = 'jimo'
}
var obj1 = Object.create(obj);//create()创建一个新对象,被创建的对象继承另一个对象的原型
console.log(obj1.name);//obj1的原型为obj

在这里插入图片描述

var obj2 = Object.create(null);//创建一个非常纯净的对象,里面什么都没有
//绝大多数对象最终都会继承自Object.prototype

如果取名和原型链终端的一些属性(方法)重名,然而实现不同的功能,即为方法的重写。

四、call和apply

1.call

function Car(name){
	this.name = name;
}
var obj = {};
Car.call(obj,'BMW');
console.log(obj);//obj借用Car的方法,即Car里this.name的this指向了obj

在这里插入图片描述
2.apply

function Car(name,width,height){
	this.name = name;
	this.width = width;
	this.height = height;
}
var obj = {};
Car.apply(obj,['BMW',2,1.5]);//与call方法类似,只是apply以数组方式传参
console.log(obj);//obj借用Car的方法,即Car里this.name的this指向了obj

在企业应用开发时,call和apply改变this指向

五、new实现

function Person(name,age){
  this.name = name;
  this.age = age;
};
Person.prototype.sayName = function(){
  console.log(this.name);
}
function myNew(origin,...res){
  // 1.以构造器的prototype属性为原型,创建新对象;
  let child = Object.create(origin.prototype);
  // 2.将this和调用参数传给构造器执行
  let result = origin.apply(child,res);
  // 3.如果构造器没有手动返回对象,则返回第一步的对象
  return Object.prototype.toString.call(result).slice(8, -1) === 'Object' ? result : child;
}
//创建实例,将构造函数Parent与形参作为参数传入
const child = myNew(Person,'jimo',18);

接下来测试一下是否与new的功能类似:

child.sayName();
console.log(child);
console.log(child instanceof Person)//true
console.log(child.hasOwnProperty('name'))//true
console.log(child.hasOwnProperty('age'))//true
console.log(child.hasOwnProperty('sayName'))//false

这里只是一些简单实现,如果想深入了解,可以自行百度哦

六、练习巩固

1.请输出下面构造该对象的构造函数的名

function A(){};
function B(){};
function CreateObj(){
	var n = Math.random();
	if(n < 0.5){
		return new A();
	}else{
		return new B();
	}
}
var obj = CreateObj();

2.请问下面三个会输出什么,为什么

function A(){};
function B(a){
	this.a = a;
}
function C(a){
	if(a){
		this.a = a;
	}
}
A.prototype.a = 1;
B.prototype.a = 1;
C.prototype.a = 1;
console.log(new A().a);
console.log(new B().a);
console.log(new C(2).a);

3.下面代码会输出什么

function A(){};
A.prototype.say = function(){};
var a1 = new A();
var a2 = new A();
console.log(a1.say === a2.say);
console.log (A.prototype.constructor );
console.log(A.prototype === Function.prototype);
console.log(A.__proto__ === Function.prototype);
console.log(A.__proto__ === Function.__proto__);
console.log(a1.__proto__ === a2.__proto__);
console.log(a1.__proto__ === A.__proto__);
console.log(Function.__proto__ === Object.__proto__);
console.log(Function.prototype.__proto__ === Object.__prototype.__proto__); 
console.log (Function.prototype.__proto___ === Object.prototype);

答案下一期揭晓

博主开始运营自己的公众号啦,感兴趣的可以关注“飞羽逐星”微信公众号哦,拿起手机就能阅读感兴趣的博客啦!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

飞羽逐星

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值