引言
要学的东西真的越来越多,从入门开始一个个变量声明再到现在能独立完成一个项目,总觉得很多基础没有掌握好,回过头来慢慢看一些东西觉得有必要记录一下,特别是JavaScript的原型链这块。
首先,什么是__proto__、prototype,简单来说__proto__是Object的属性,prototype是Function的属性,而实际上所有所有的JavaScript内的变量也好,方法也好,一切的一切都是对象,但是为了能把这两者区分开来,特意分成了对象和函数,但实际上函数的本质也是一个对象。
先抛出一个问题,所有对象都可以使用的toString()方法我们并没有声明过,但为什么我们可以使用这个方法?这个方法存在于哪里?
属性理解
便于理解,构建一个对象和函数
function Fun(){};
let Obj = new Fun();
console.log(Obj);
查看打印
通过new来创建一个构建函数,这里的Obj是一个对象,可以理解成通过Fun函数构建了一个实例对象Obj。
打印两者的__proto__及prototype
console.log(Obj.__proto__===Fun.prototype);
查看
发现两者是一样的,可以得出一个结论:由Fun构造的Obj的__proto__属性指向Fun的prototype属性,而Fun的prototype属性也就是Obj的__proto__属性到底是什么呢
console.log(Fun.prototype);
查看
看到constructor的时候一下子就想到了es6语法里的class ,而Fun.prototype在被调用时的constructor方法指向函数Fun(),所以可以理解成当用new构建了一个Fun的实例对象时,同时构建了一个Fun.prototype,这里把Fun.prototype称为实例原型。
所以Obj的__proto__属性实际上指向的就是构建它的函数的实例对象,我们可以对这个实例对象进行方法注册。
function Fun(){};
let Obj = new Fun();
Fun.prototype.sayHello = function(){
console.log('hello');
};
Obj.sayHello();
查看
好的,那么我们就可以知道Obj的方法是由它的构建函数的实例原型所注册的,而且发现这个实例原型也是一个对象,那么就继续找这个实例原型的构造函数的实例原型,也就是Obj.proto.proto。
console.log(Obj.__proto__.__proto__);
查看
终于是发现了这个toString方法,到此为止,发现这个对象没有__proto__属性,那么就可以理解为这个实例原型为最初构建的实例原型,它本身就存在于JavaScript语法中。
原型链
这一层层找对象的实例原型的关系,也就被称为原型链。
对比class的继承关系,对象的原型链也是一样的,任何对象的toString方法也是由实例原型的方法继承而来的。
问题
不过随之带来的问题也是很大的,因为我们可以对这个原型实例的toString方法进行改写。
Object.prototype.toString = function(){
console.log('没改变而且没有返回值')
};
let s = Object();
let a = s.toString();
console.log(a);
查看
百度了一下别人的可以通过设置Object.create(null)防止感染
https://www.bbsmax.com/A/MyJxL26MJn/
还得好好研究一下