首先我们先来看两个问题:
1,构造函数和普通函数到底有何区别?
2,函数为什么可以打印出名字、形参长度,那么它是对象吗?
1,构造函数和普通函数有何区别:
function Test(){} // 构造函数?
function test(){} // 普通函数?
以上2行代码,相信很多人一眼就可以看出,Test是构造函数,test是普通函数。
那么依据是什么呢?
你肯定会说,首字母大写当然就是构造函数了。
那么请看下图:
可以看到,函数怎么执行和它的名字并没有直接的关系。
那么我们知道了:
1,从结构上来说,构造函数和普通函数没有任何区别。
2,构造函数能构造出对象的前提,必须得加 new 执行。有了 new 之后,就能产生构造函数的功能。没 new 就是正常函数执行。
所以,构造函数和普通函数的命名,才需要按照首字母的大小写来区分。
首字母大写就是告诉你,我是一个构造函数,请用 new 来执行。
因为如果不加 new,它们的功能都是一样的。
2,函数是对象吗?
从上图可以很明显的看到:函数也可以当作对象来用。
那么接下来,就让我们看看 js 里面的难点,原型:
原型:
1,原型是 function 对象上面的一个属性。
2,原型是个对象。(个别例外)
3,通过构造函数产生出来的对象,可以继承该原型的属性和方法。
函数在定义时,系统就会自动创建一个对象作为该函数的原型。函数 prototype 属性的值,就指向该原型。同时该原型 constructor 属性的值也指向该函数。如下图:
那么为什么通过 new 之后,就可以继承属性和方法呢,当我们 new 的时候,到底发生了什么?
1,当我们在通过 new 执行一个函数的时候,JS 引擎会在该函数内部的最顶端,隐式的加上 var this = { }。
2,然后依次执行函数内部代码。
3,最后,在函数内部的最下方,隐式的 return this。
function Person (name, age){
// JS引擎会自动的加上:var this = { }
this.name = name
this.age = age
this.say = function () {
console.log('我会说话')
}
// 最后则会:return this
}
Person.prototype.num = 666
var zhangsan = new Person('张三', 18)
zhangsan.name // 张三
zhangsan.age // 18
zhangsan.say() // 我会说话
zhangsan.num // 666
如果只是这样,那么如何继承原型上面的属性和方法呢?
那是因为在函数内部的 this 并不仅仅是一个空对象, 实际上是:
var this = Object.create( 原型 )
var obj = Object.create( 原型 )
这句话的意思是:创建一个对象 obj,并且指定它的原型是 xxx
例如:
var demo = { name : 'aaa' }
var obj = Object.create(demo)
等同于:
var obj = {
__proto__: demo
}
也可以理解为:
var this = { __ proto__ : 原型 }
如下图:
搞清楚了 new 做的事情,以及为什么可以继承原型上的方法之后,那么原型链也就更好理解了:
原型之间形成的链接结构,也称为原型链。(__proto__ 形成的链式结构)
function Animal(){
this.name = '我属于动物'
}
Animal.prototype.eat = function () {
console.log('我会吃东西')
}
var animal = new Animal()
function Dog(){
this.say = function () {
console.log('汪汪叫')
}
}
Dog.prototype = animal
var dog = new Dog()
dog.say()
dog.eat()
dog.name
如下图:
所以它的原理其实非常的简单,就三个字:往上找。
首先,从自己身上找, 如果自己身上有,那就直接拿来用。
如果没有,它会顺着 __proto__ 这根线,继续去它爸爸身上找,如果它爸爸身上有,那自然就好。
如果还没有,它还会再去它爷爷身上找。
如果还没有,在往上找,一直找到最后,能找到 Object.prototype 上,这也是它最终的一个归宿。
因为 Object 其实是所有人间接的祖宗,它是最上面的。
一直找到 Object 身上,如果还没有,那就是 undefined。
说白了,就是一个一个往上找,自己没有就找它爸爸,还没有,就找它爷爷,一直找到 Object 身上,还没有,就是 undefined。