![748972d9a4aa49f359b69e8e0dd73667.png](https://i-blog.csdnimg.cn/blog_migrate/53dc5d544d775fa7ab04a1418d1a23a7.jpeg)
前言
不知道大家有没有这样的感觉,当我们系统的学习了一遍JavaScript后,想要去针对性的提高JavaScript能力时,会显得没有方向感。
并不是因为自己的能力不够,而是有很多内容分布的比较散列,我们需要花费很多精力去整理出来。
假如我们正在准备面试了,这种感受可能会更加明显,作为三大基础中最重要的JavaScript我该准备哪些内容呢?
各位看官别急,我这就给你稍微整理一下。
![c7e31814a3516d2128b0fb4b85f7bfe2.png](https://i-blog.csdnimg.cn/blog_migrate/3ecd3d43773dc761961e9a87478ce6e9.jpeg)
当我们有了这张脑图后,你以为光看看知识点,就可以轻松提升JavaScript技能了么?
当然不行,在具备理论知识后,我们还需要有与实际结合的能力,通过代码实例来加强对知识点的理解。
所谓,实践是检验真理的唯一标准,在编程领域也是同样遵守的,别看你对很多知识点的概念对答如流,但是给你段代码,你读不懂那也是不行的,此可谓“纸上谈兵”。
instanceof运算符
那么什么样的知识点讲解会更深入人心呢?我们来举个例子,谈谈你对instanceof操作符的理解。
这时你可能会说出一些专业的官方解释,instanceof运算符的用法是这样。
target instanceof constructor
你会解释说:构造函数 constructor() 的 prototype 属性是否出现在 target 对象的原型链中。
当我需要你用一句更接地气的话来解释时,该怎么说好呢?
我们一般可以这样说:判断一个实例target是否属于constructor对应的类型。这就好理解多了,其实就是判断实例和构造函数的关系。
常规操作
那我们来看下它的基本使用。
// 判断 foo 是否是 Foo 类的实例
function Foo(){}
var foo = new Foo();
console.log(foo instanceof Foo); // true
你是不是在想这也太eazy了吧,这不是常规操作吗?
好好好,看官息怒,那我们来个难度大一点的,增加对继承的用法。
// 判断foo是否是Foo类的实例, 并且是否是其父类型的实例
function Poo(){}
function Foo(){}
Foo.prototype = new Poo(); // JavaScript 原型继承
var foo = new Foo();
console.log(foo instanceof Foo); // true
console.log(foo instanceof Poo); // true
这里我们增加了JavaScript原型继承,来增强对instanceof运算符的理解。
相信如果对instanceof有熟练掌握的同学,应该也难不倒他,foo可以很肯定的说是Foo类型的实例,而Foo又是继承于Poo,那么foo当然也可以说是Poo类型的实例了,因此会输出两个true。
王者操作
如果到这里,你以为instanceof运算符就只有这么点内容,那你就太小看它了。
我们再来点王者段位的考验。
console.log(Object instanceof Object); // true
console.log(Function instanceof Function); // true
console.log(Function instanceof Object); // true
console.log(Object instanceof Function); // true
console.log(Number instanceof Number); // false
console.log(String instanceof String); // false
console.log(Foo instanceof Function); // true
console.log(Foo instanceof Foo); // false
我相信大部分人看到上面的代码,都会一头雾水吧,心里还可能发出感叹:WTF?我零乱了。
看官别急,待我慢慢讲述。
按照官方的解释,instanceof运算符的计算过程会涉及到原型链的概念。关于原型链的具体讲解,可以看看我写的另一篇文章。
而在原型链的寻找过程中,就有两个很重要的属性prototype和__pro__。
prototype是挂在构造函数上的属性,而__pro__是挂在实例上的属性,实例的__pro__属性指向的就是构造函数的prototype属性。
function Foo() {}
var foo = new Foo();
console.log(foo.__proto__ === Foo.prototype); // true
有了这个知识点作为补充后,对于理解instanceof运算符就方便很多了。
它的实际计算过程可以用以下的代码来解释。
/**
* instanceof 运算符实现原理
* @param L 表示左表达式
* @param R 表示右表达式
* @returns {boolean}
*/
function instance_of(L, R) {
var O = R.prototype; // 取 R 的显示原型
L = L.__proto__; // 取 L 的隐式原型
while (true) {
if (L === null)
return false;
if (O === L) // 这里是重点:当 O 严格等于 L 时,返回“true”
return true;
L = L.__proto__; // 如果不相等则重新取 L 的隐式原型
}
}
对于上面这段代码我们可以这么理解。
- 获取右表达式R的prototype属性为O,左表达式的__proto__隐式原型为L。
- 首先判断左表达式__proto__隐式原型L是否为空,如果为空,则直接返回“false”。实际上只有Object.prototype.__proto__属性为null,即到了原型链的最顶层。
- 然后判断O与L是否严格相等,需要注意的是只有在严格相等的时候,才返回“true”。
- 如果不相等,则递归L的__proto__属性,直到L为null或者O===L,得到最终结果。
当我们掌握到这里后,就可以小试牛刀看看一开始的那些问题的答案是怎么得到的了。
Object instanceof Object
我们基于上面instanceof运算符的原理,区分运算符左右两侧值,得到以下的计算过程。
// 将左、右侧值进行赋值
ObjectL = Object, ObjectR = Object;
// 根据原理获取对应值
L = ObjectL.__proto__ = Function.prototype;
R = ObjectR.prototype; // 执行第一次判断 L != R;
// 继续寻找
L.__pro__ L = L.__proto__ = Function.prototype.__proto__ = Object.prototype;
// 执行第二次判断 L === R;
因此得到结果为true。
Function instanceof Function
同样我们可以得到以下的计算过程。
// 将左、右侧值进行赋值
FunctionL = Function, FunctionR = Function;
// 根据原理获取对应值
L = FunctionL.__proto__ = Function.prototype;
R = FunctionR.prototype = Function.prototype;
// 执行第一次判断成功,返回“true” L === R;
因此得到的结果为true。
Foo instanceof Foo
针对Foo()构造函数,会存在 3 次链路寻找过程,详细过程如下。
// 将左、右侧值进行赋值
FooL = Foo, FooR = Foo;
// 根据原理获取对应值
L = FooL.__proto__ = Function.prototype;
R = FooR.prototype = Foo.prototype; // 第一次判断失败,返回“false” L !== R;
// 继续寻找
L.__proto__ L = L.__proto__ = Function.prototype.__proto__ = Object.prototype;
// 第二次判断失败,返回“false” L !== R;
// 继续寻找
L.__proto__ L = L.__proto__ = Object.prototype.__proto__ = null;
// L 为 null, 返回“false” L === null;
因此得到的结果为false。
相信通过这三个例子的讲解,大家已经能够完全掌握了instanceof运算符的用法了吧,如果以后再遇到与instanceof运算符有关的问题,大家都能够处理的游刃有余了。
重磅消息
上面这种循序渐进式的讲解,再配合多个实例的练习,是不是可以很容易掌握到知识点的精髓呢?
而instanceof运算符只是偌大的JavaScript海洋中的冰山一角,试想一下如果有一本书能够将这些重点的知识汇集在一起,并通过丰富的实例来进行讲解,那对于JavaScript的学习该是多么幸福的一件事情呀。
由我个人编写,经由人民邮电出版社出版的书籍《JavaScript重难点实例解析》已经问世啦。
在这本书里,详细汇总了JavaScript中的各种重难点,并针对各个知识点进行丰富的代码实例验证,真正达到“授人以鱼不如授人以渔”的目的。
如果在阅读的过程中遇到什么问题,更是可以直接与我进行私信交流噢~
![31642968ad70654d050e0e18a1fc81c1.png](https://i-blog.csdnimg.cn/blog_migrate/5e649e09cbf1d3cdb1ea74df87da4838.jpeg)