js基础:原型和原型链新手入门
本文研究一下Javascript的核心基础——原型链和继承。
对于使用过基于类的语言(如Java或C#)的人来说,Javascript的继承有点难以搞懂,因为它本身没有class这种东西。(ES6中引入了class关键字,看上去也像传统的OOP语言,但是那只是语法糖,底层还是基于原型)。
原型链
MDN上对于原型链的解释:
这段话可能难以理解,我们来举个例子:
const list = []; // 定义数组
list.__proto__ === Array.prototype; // true
list.__proto__.__proto__ === Object.prototype; // true
list.__proto__.__proto__.__proto__===null; // true
// 继承关系为
// list -> Array.prototype -> Object.prototype -> null
结合MDN的解释,我们来解释一下上述例子:
list是Array的实例对象,使用了字面量的方式创建了对象实例。
// list的构造函数是Array,所以list.__proto__指向构造函数Array的原型对象。
list.__proto__ === Array.prototype; // true
// Array.prototype也是对象,也有自己的原型对象,原型是Object.prototype
// 下面是数学运算(等量代换)
// list.__proto__ = Array.prototype
// Array.prototype.__proto__ = Object.prototype
list.__proto__.__proto__ === Object.prototype; // true
// 目前我们来到了Object.prototype,根据规范,Object.prototype的原型对象为null
// list.__proto__ = Array.prototype
// Array.prototype.__proto__ = Object.prototype
// Object.prototype.__proto__ = null;
list.__proto__.__proto__.__proto__ === null; // true
原型链查找
const list = [];
list.toString();
属性查找过程如下:
查找list.toString()方法,没找到继续查找list.__proto__,也就是Array.prototype,找到了调用Array.prototype.toString
原型链结论
对象实例.__proto__ = 对象构造函数.prototype几乎所有对象的原型都是Object.prototypenull是对象,但是null没有原型属性/方法查找采用优先返回机制。
函数
经过原型链的简单介绍,相信大家对原型和原型链有了一个比较直观的了解了,现在要说到的是函数。
上面的结论在Javascript中是有问题的。我们来聊一聊函数。
先看看简单一点的例子,大家知道,Object是对象的构造函数,构造函数也是函数,所有的函数的原型都是Function.prototype,所以Object.__proto__是等于Function.prototype的。
事实证明,也是如此。
那么Function.__proto__为什么不等于Object.prototype呢?Function不是对象吗?
上面我们说到所有函数的原型是Function.prototype,所以Function这个构造函数的原型__proto__等于Function.prototype。
基于以上原理,还有以下相等关系:
- Object.__proto__ === Function.prototypeArray.__proto__ === Function.prototype
引申的问题
我们知道Function.__proto__是指向Function.prototype,那个Function.prototype这个Function哪里来的?Function自己创造自己?那不是会死循环吗?
函数结论
函数的原型都是Function.protype,构造函数也是函数,所以构造函数的原型也是Function.prototype
来自灵魂的拷问1
下面是一道有点难度的JS基础题,可以感受一下:
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().a);
输出是
1
undefined
1
解释
为什么输出1?
为什么输出undefined?
为什么输出1?
来自灵魂的拷问2
function F() {
this.a = 1;
}
F.prototype.b = 2;
var f = new F();
console.log(f.hasOwnProperty('a'));
console.log(f.hasOwnProperty('b'));
输出是
true
false
解释
为什么输出true`?为什么输出false?
结尾
本文研究了原型和原型链之间的关系以及常见对象的原型和原型链,对于特殊对象Function也研究了一下,如果能搞懂后面两个问题,那本文对你来说没什么问题了。