问题引出:我们已经知道通过定义构造函数,每次实列对象生成时,就会生成相应的属性和方法,我们不经疑惑,属性值不同,会造成属性不相等,那么每次根据实例生成的方法相同吗?
代码演示:
//自定义构造函数
function fn(usename) {
this.usename = usename;
this.play = function() {
console.log("我喜欢跑步");
}
}
//通过new关键字实例化
let zs = new fn("张三");
let ls = new fn("李四");
//把两个实例的play 进行比较
console.log(zs.play == ls.play);
结果:
结果是不相同的,究其原因就是,通过new 关键字实例时,每次new都会在内存中开辟小块内存来存储当前实例
但每次生成实例时都要重复执行相同的方法,一般时无所谓,但当大量实例生成时,生成的重复方法会造成大量资源占用,
解决方法就是引用 prototype(原型对象)生成公共方法
打印下fn
就会发现prototype是构造函数fn的一个属性,所以就有了如下图示
//生成公共方法
fn.prototype.play = function {
console.log("我喜欢跑步");
}
//把两个实例的公共方法play 进行比较
console.log(zs.play === ls.play);
结果
//调用play方法,看下实例能不能调用
zs.play();
结果
能调用,打印下zs,看看zs中有没有play
打印之后没有play个方法,但zs却能调用play方法,思考为啥能调用,于是我们发现在zs的__proto__(对象原型)中出现了paly方法
于是我们有理由怀疑prototype与__proto__的关系,于是将二者进行比较
console.log(zs.__proto__ == fn.prototype);
结果
于是我们得出结论 zs.__proto__ == fn.prototype,故得到下列关系图
在观察prototype与_proto__后发现他们两都具有同一个属性constructor
console.dir(fn);
console.log(zs.__proto__);
但我们不经疑问constructor是属于哪个构造函数的,根据上图明白 constructor 是构造函数fn(),于是我们能进行类比constructor相当与人身体上DNA,记录着最初的信息fn()
故能得到如下图示
故至此原型对象与·对象原型完毕接下来原型链
我们都知道原型链是来指导方法查找规则的那么是怎么指导的
我们思考一个问题在js基础阶段我们是如何将数字类型转换为字符串
function fn(usename, useage) {
this.usename = usename;
this.useage = useage;
}
//通过new关键字实例化
let zs = new fn("张三", 45);
//查看zs.useages数据类型
console.log(typeof(zs.useage));
结果:
那么转换为字符串?,在js 基础阶段老师告诉我们一个方法使用 toString()方法
let a = zs.useage.toString();
//查看zs.useages数据类型
console.log(typeof(a));
查看数据类型
但这时我们疑惑我们公共方法没有设置 toString(),我们也没在自定义函数对象中设置该方法,那么这方法是哪里来的?
我们看在__proto__下面还有个__proto__点开他,
发现了toString方法,但我们就疑惑这个方法是哪个对象身上的,于是我们想到了前文说的constructor,因为这个属性保存了属性的来自哪个对象的信息
得到 toString是Object身上的方法,我们在找一遍之后发现Object没有__proto__于是得出以下原型链
并得到了原型链的最终指向 Object