携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第33天,点击查看活动详情
1. 原型三角关系
原型应该是js设计中最为变态,比this指向还变态的一个东西,但是由于原型的存在拓展了js的类,js的继承,js的属性方法设计等。因此我们还是要忍痛割爱去弄懂它。想要弄懂原型,还得从三角恋开始。
根据上图关系,我们很容易得出结论(三角关系十分十分十分重要,一定要记住)
-
实例对象.__proto__ = 函数
-
函数.prototype = 函数原型
-
函数原型.constructor = 函数
//构造函数 function People (name) { this.name = name } //实例对象 let p = new People("xiaoming") //测试三角关系 console.log(p.__proto__===People.prototype) console.log(People.prototype.constructor === People) console.log(p.__proto__.__proto__)//Object.prototype console.log(p.__proto__.__proto__.__proto__)//null console.log(People.__proto__)//Function.prototype console.log(People.__proto__.__proto__)//Object.prototype
2. 原型链
原型链:原型链就是对象和函数的属性可以按照原型链的顺序,一层一层的找下去。它们都是从自己o开始找,如果没找到就按 o.__proto__的原型链一直找到NULL为止。
这份图是比较完整的原型链组成图,马勒戈巴子画这个累死我了。图中的红色和绿色是两类原型链,其中红色代表的是函数的原型链,而绿色是普通对象的原型链。它们两个最后都指向了NULL,用黄色箭头表示。
函数原型链测试
此处还未讲new的构造原理和原型链变化,所以先不测试
对象原型链测试
Function.test1 = function() {
console.log("Function.test1")
}
Function.prototype.test1 = function() {
console.log("Function.prototype.test1")
}
Object.test1 = function() {
console.log("Object.test1")
}
Object.prototype.test1 = function() {
console.log("Object.prototype.test1")
}
let o = {
name:"dzp"
}
o.test1()//Object.prototype.test1
最后的输出是Object.prototype test1。按照原型链很容易明白,对象的原型链从绿色箭头开始寻找,先找自己o对象本身是否有test1函数,没有则按照原型链箭头来到了Object原型。发现有test1函数,成功输出。
3.new的原理和原型链
new的原理是十分十分重要,在前端面试中经常会被问,甚至要求手写new的过程。接下来,我将为大家细细讲解
function People (name) {
this.name = name
}
People.prototype.info = function(){
console.log("info")
}
//new的模拟
function myNew (name) {
let o = {}
People.call(o,name)
o.__proto__ = People.prototype
return o
}
//测试
let p = myNew("dzp")
console.log(p.name)//dzp
p.info();//info
可以看到,new的核心就三行代码。我来依依解答下
-
首先创建一个空的对象o
-
调用函数People,并使用apply或者call改变People的this,让this动态绑定到o上。此时对象o就已经添加了属性name
o = { name:"dzp" } -
此时有人说,这不是已经成功了?name的确绑定到了对象o上,但是这个o可以访问People原型链上的属性和函数?答案肯定是不能。因此我们执行最后一步,将对象o的__proto__链接到People的原型上
new在原型链上表现
经过上面new的过程,我们可以用原型链描述整个new的原理,对象o将自己的__proto__指向了People的原型,此时红色的原型链就形成了。
原型链测试
function People (name) {
this.name = name
}
Function.test1 = function() {
console.log("Function.test1")
}
Function.prototype.test1 = function() {
console.log("Function.prototype.test1")
}
Object.test1 = function() {
console.log("Object.test1")
}
Object.prototype.test1 = function() {
console.log("Object.prototype.test1")
}
let p = new People("dzp")
p.test1()//Object.prototype.test1
按照上面红色原型链分析,很容易得到答案。
4.Object.create的原理
Object.create的原理和this都是面试官经常会问的,接下来我将讲解Object.create的原理并使用原型链模拟其内部过程。
//模拟Object.create原理
Object.create = function(o) {
function f() {}
f.prototype = o
return new f()
}
let obj = {
name:'dzp'
}
let o = Object.create(obj)
console.log(o)//{}
console.log(o.name)//dzp
经过测试我们发现,对象o自己本身是空的,但是仍然可以访问对象obj的属性,不用想,肯定是对象obj成为了o的原型链一部分。
原型链模拟
我们看到返回的最终对象是一个空的,但是它自己通过__proto__链接了原型链到对象o上,因此它可以访问对象o的属性和函数
5.练习
记住上面的原型图,按步骤分析就十分的简单。
5.1
var A = function() {};
A.prototype.n = 1;
var b = new A();
A.prototype = {
n: 2,
m: 3
}
var c = new A();
console.log(b.n);//1
console.log(b.m);//undefined
console.log(c.n);//2
console.log(c.m);//3
5.2
var F = function() {};
Object.prototype.a = function() {
console.log('a');
};
Function.prototype.b = function() {
console.log('b');
}
var f = new F();
f.a();//a
f.b();//null
F.a();//a
F.b();//b
总结
以上是我对原型链,this,Object.create的理解,个人如果理解不到位,请评论区多多批评。大家共同进步。