Javascript原型理解(面试篇)
本文是学习JS原型相关知识后的总结与笔记:学习文章参考《一文吃透所有JS原型相关知识点》
在面试中会被经常问到JS原型以及原型链的知识,以前只知道大概就是原型是JS中对象或者函数特有的一种属性,它上面可以挂载一些变量和方法,以供实例化对象访问,如果该实例化对象本身没有需要访问的属性,那么就会接着往上到父类中查找,如果还没有就再接着往上找,直到找到或者为null,这就形成了原型链。
这么说出来可能稍微能明白一点,但是具体的比如__proto__
,prototype
,constructor
他们具体代表什么,又或者之间都有什么关系,理解的还是模模糊糊。所以在通过学习之后大概知道一些。记录下来。
首先抛出疑惑:对象都一样吗?答案肯定不一样。比如
![](https://img.haomeiwen.com/i17538702/ae96ed55c4b7c1cd.png)
都是对象为啥他们的
__proto__
不一样呢?接着往下看:
函数对象和普通对象
在JS中有这么一句话,万物皆对象,但是对象却是不相同的,我们将对象分为函数对象和普通对象,函数对象就是指Javascript中用函数来模拟的类实现 其中Object和Function就是函数对象。
函数对象
typeof Object // function
typeof Function //function
function fun1(){}; typeof fun1 // function
let fun2 = function(){}; typeof fun2 // function
let fun3 = new Function(); typeof fun3 //function
普通对象
var obj = {}; typeof obj // object
var obj1 = new Object(); typeof obj1 //object
function fun(){};
var obj2 = new fun(); typeof obj2 //object
var obj3 = new new Function(){}; typeof obj3 // object
从万物皆对象的角度来看函数对象与普通对象,所有Function的实例都是函数对象,其他的都是普通对象,其中包括new Function的实例。
__proto__
首先明确两点:
- 1.
__proto__
和constructor
是对象独有的。 - 2.
prototype
是函数独有的。
但是在JavaScript中,函数也是对象,所以函数也拥有__proto__
和constructor
属性
在学习JS的过程中有时候得站在万物皆对象的角度去思考问题,有时候又得将对象跟函数明确的分开来看问题,所以在思考的时候注意切换角度。
首先先看__proto__
是个什么东西:
![](https://img.haomeiwen.com/i17538702/5f0e85bfa2d68021.png)
根据上面说的对象和函数都有__proto__
属性,我们可以使用obj.__proto__
去对__proto__
属性进行读取操作,也可以使用obj.__proto__ = newObj
来对其进行写入操作。
实际上在ECMAScript规范中是不允许这样去操作的,ECMAScript在发展过程中是这样对它进行使用的:
Object.getPrototypeOf(obj) //替代obj.__proto__;
Object.setPrototypeOf(obj,newObj) // 替代obj.__proto__ = newObj;
__proto__
属性既不能被for in
遍历出来,也不能被Object.keys(obj)
查找出来。
访问对象的obj.__proto__
属性,默认查找的是Object.prototype
对象上__proto__
属性的get/set方法。
![](https://img.haomeiwen.com/i17538702/b165056f076f0cda.png)
综上我们可以得知:__proto__
是对象独有的,因为函数也是对象,因此函数也是有__proto__
属性的,__proto__
是一个对象指向另外一个对象,也就是他的原型对象,可以理解为父类对象,作用是当你访问一个对象属性的时候,如果该对象内部不存在这个属性,那么就去他的__proto__
所指向的对象上去查找,如果父类对象依旧不存在这个属性,那么就在其父类的__proto__
属性所指的对象上去查找,直到找到null,这个查找过程也就构成了原型链。
prototype
简单的理解就是prototype
是一个对象,并且是给其他对象提供共享属性的对象。
所有的对象都可以作为另外一个对象的prototype来使用。
我们所说的函数对象是拥有prototype
属性的,而普通对象是没有prototype
属性的。
![](https://img.haomeiwen.com/i17538702/ab098141997358c4.png)
每个实例对象( object )都有一个私有属性(称之为__proto__
)指向它的构造函数的原型对象(prototype )。该原型对象也有一个自己的原型对象(__proto__
) ,层层向上直到一个对象的原型对象为 null。根据定义,null 没有原型,并作为这个原型链中的最后一个环节。
上面这段话是MDN原话,用代码来演示如下:
function Person(){}
var person = new Person()
//person 有一个私有属性__proto__,指向它的构造函数 Person的原型,也就是Person.prototype
//因此person.__proto__ == Person.prototype 为true;
console.log(person.__proto__ == Person.prototype); // true
现在来看__proto__
和prototype
的关系,感觉就清晰了很多。
constructor
constructor
属性也是对象独有的,它是一个对象指向一个函数,而这个函数就是该对象的构造函数。
每一个对象都有其对应的构造函数,本身或者继承而来,但是constructor
属性只有prototype对象才有,每个函数在创建的时候,Javascript会同时创建一个该函数对应的prototype
对象,函数创建的对象也就是实例化对象.__proto__ === 函数.prototype
,该函数.prototype.constructor === 函数本身
,通过函数创建的对象,即使自己没有constructor
属性,他也能通过 __proto__
向上寻找,找到对应的constructor,所以任何对象最终都可以找到其对应的构造函数。
function Person(){}
var person = new Person()
console.log(person.__proto__.constructor == Person.prototype.constructor); //true
console.log(person.__proto__.constructor == Person); //true
console.log(Person.prototype.constructor == Person); //true
现在关于 __proto__
prototype
constructor
这些大概都清楚了一点。接下来有两张图我觉得非常好,在看文字的同时,结合图来看,之后在看图的同时反过来看文字描述,会更加深刻理解原型的知识。
看着图来理解__proto__
,prototype
,constructor
应该会更好理解一些。
面试过程中很多时候会被问到原型这块的知识,这块其实已经到了JS核心知识了,作为一个前端开发,对于JS中的知识还是要知道,掌握一些的,因此专门花时间来从微信收藏文章列表中找到大神的文章《一文吃透所有JS原型相关知识点》,这篇文章是我自己学习原型知识的一些笔记加学习思路,很多地方不知道怎么写,还是基础不够深以及涉猎不够广,所以文中很多地方都出自于《一文吃透所有JS原型相关知识点》,以及里面的图片也都是出自于该文章,很值得学习的一篇关于原型的文章。
有一道经典的原型这块的面试题,我曾经面试也遇到过:
function Foo(){
getName = function(){
alert(1)
}
return this
}
Foo.getName = function(){
alert(2);
}
Foo.prototype.getName = function(){
alert(3)
}
var getName = function(){
alert(4);
}
function getName(){
alert(5);
}
//请写出以下输出结果
Foo.getName();
getName();
Foo().getName();
getName();
new Foo.getName();
new Foo().getName();
new new Foo().getName();
-------分割线---------------------------------------------------------------------------------------------------------------------------
2020-03-31 22:56
这一个月又结束了,感觉自己就像在和时间赛跑一样,一般我不喜欢在晚上写技术类文章,我喜欢在晚上写一些生活类的文章,因为晚上尤其是10点后脑袋整个晕乎乎的,不想思考理思路,但是眼瞅着三月底了,再过一会就进入四月了,今年本来情况就特殊,还是需要加油呀。这也是三月最后一篇文章,顺便总结一些三月都干了些什么吧。
- 购买了自己的第一台阿里云服务器,以及注册了属于自己的域名(备案成功),准备使用nodejs+vue做一个简单的小博客。(准备工作,知识储备)
- 学习nodejs express + mongodb可以写接口,搭建服务器。
- 学习观察者模式,发布订阅模式。
- 学习vue2.0响应式核心源码。
四月计划:
- 学习vue 以及 vue全家桶
- 学习一些设计模式
- 上线博客第一版。