JS的执行上下文
在学习JS的数据结构与算法的时候,学到二叉搜索树的先序遍历代码时,看得一脸懵逼,弹幕说这是栈什么的,根本不知道什么意思,为什么函数自己就往回走了
//4、先序遍历 BinarySerachTree.prototype.preOrderTraversal = function () { this.preOrderTraversalNode(this.root) } BinarySerachTree.prototype.preOrderTraversalNode = function (node) { if (node != null) { callBack(node.key) //左走 this.preOrderTraversalNode(node.left) //右走 this.preOrderTraversalNode(node.right) } }
标橙是我懵逼的两段代码。按我的理解,当走到树最左端最小值的时候,由于node.left是空所以传值应该是null,函数自动停止才对。
如果没有右走代码,上面的逻辑确实没错。但是添加了右走代码,函数就会自己往回走,我很纳闷这是为什么?
查看公众号文章,大概明白一些逻辑:
https://mp.weixin.qq.com/s/TAZax-B-llfVXgZyKYJ_VQ?
https://www.cnblogs.com/bax-life/p/7499513.html
首先要理解什么是执行上下文(Execution Context)?
当 JavaScript 代码在运行的时候, 它所在的执行环境通常认为是以下其中之一:
-
Global code – 默认环境,你的代码首次执行的地方。
-
Function code – 当代码执行进入到函数体当中。
-
Eval code – 在 eval 函数内部执行的文本。
有且只能有1个全局上下文, 并且可以被程序中其他的上下文访问到。
可以有很多个函数上下文, 每个函数调用都创造一个新的上下文, 并创建出一个局部作用域,任何在作用域内部声明的东西都不能被当前函数作用域外部访问到。(闭包)
执行上下文栈(Execution Context Stack)
在浏览器中的 JavaScript 解释器是单线程的。这实际上意味着,在浏览器中一次只会发生一件事,其他行为或者事件在所谓的执行栈中排队等待。
浏览器第一次加载脚本, 它将默认进入全局执行上下文中。
如果在全局环境中调用了一个函数, 你的程序序列流会进入被调用的函数的当中,创建一个新的 执行上下文 并且将这个上下文压入执行栈之中。
如果你在当前函数里面又调用了另外一个函数, 也会发生同样的事情:
代码的执行流进入内部函数,这将创建一个新的执行上下文,它被压入现有栈的顶部。浏览器永远会执行当前栈中顶部的执行上下文 一旦函数在当前执行上下文执行完毕,它会被从栈的顶部弹出,然后将控制权移交给当前栈的下一个上下文当中。
(function foo(i) { if (i === 3) { return; } else { foo(++i); } }(0));
这段代码调用自己自身3次, 每次将 i 的值增加 1。
每次函数 foo 被调用的时候, 就会创建一个新的执行上下文。
一旦上下文执行完毕之后, 它就会从栈中弹出并且返回控制权到下一个上下文当中,直到全局上下文又再次被访问。
所以:以先序遍历来说,其执行过程也如此
//4、先序遍历 BinarySerachTree.prototype.preOrderTraversal = function () { this.preOrderTraversalNode(this.root) } BinarySerachTree.prototype.preOrderTraversalNode = function (node) { if (node != null) { callBack(node.key) //左走,一旦执行完毕,也就是node.left==null,则弹出,往回走 //然后从之前中断的地方,也就是下面这行代码,往下走,不执行这一句了。 this.preOrderTraversalNode(node.left) //右走 this.preOrderTraversalNode(node.right) } }
最主要的一点,就是从之前中断的地方往下走,不会死循环
再举一个例子,二叉树的搜索,其实也和插入差不多
BinarySerachTree.prototype.search = function (key) { let node = new Node(key) return this.searchNode(this.root, node) } //内部调用递归搜索 //单纯的return true和false是只会退出当前的上下文,并不会直接退到global BinarySerachTree.prototype.searchNode = function (node, newNode) { if (node != null) { if (newNode.key === node.key) { return true } else if (newNode.key < node.key) { //如果不return, 会保留当前上下文,最后search返回的是undefined // this.searchNode(node.left, newNode) return this.searchNode(node.left, newNode) } else if (newNode.key > node.key) { // this.searchNode(node.right, newNode) return this.searchNode(node.right, newNode) } } else { return false } }