八个针对高级职位的高级 JavaScript 面试题( 二 )

在此示例中 , 我们有一个名为 Person 的构造函数 。通过使用 sayHello 之类的方法扩展 Person.prototype , 我们将此方法添加到所有 Person 实例的原型链中 。这允许 Person 的每个实例访问和利用共享方法 。而不是每个实例都有自己的方法副本 。
另一方面 ,  __proto__ 属性(通常发音为“dunder proto”)存在于每个 JavaScript 对象中 。在 JavaScript 中 , 除了原始类型之外 , 所有东西都可以被视为对象 。这些对象中的每一个都有一个原型 , 用作对另一个对象的引用 。__proto__ 属性只是对此原型对象的引用 。当原始对象不具备属性和方法时 , 原型对象用作属性和方法的后备源 。默认情况下 , 当您创建对象时 , 其原型设置为 Object.prototype 。
当您尝试访问对象的属性或方法时 , JavaScript 会遵循查找过程来查找它 。这个过程涉及两个主要步骤:
对象自己的属性:JavaScript 首先检查对象本身是否直接拥有所需的属性或方法 。如果在对象中找到该属性 , 则直接访问和使用它 。
原型链查找:如果在对象本身中找不到该属性 , JavaScript 将查看该对象的原型(由 __proto__ 属性引用)并在那里搜索该属性 。此过程在原型链上递归地继续 , 直到找到属性或查找到达 Object.prototype 。
如果即使在 Object.prototype 中也找不到该属性 , JavaScript 将返回 undefined , 表明该属性不存在 。
4、范围编写 JavaScript 代码时 , 理解作用域的概念很重要 。范围是指代码不同部分中变量的可访问性或可见性 。在继续该示例之前 , 如果您不熟悉提升以及 JavaScript 代码的执行方式 , 可以从此链接了解它 。这将帮助您更详细地了解 JavaScript 代码的工作原理 。
让我们仔细看看代码片段:
function foo() {console.log(a);}function bar() {var a = 3;foo();}var a = 5;bar();该代码定义了 2 个函数 foo() 和 bar() 以及一个值为 5 的变量 a 。所有这些声明都发生在全局范围内 。在 bar() 函数内部 , 声明了一个变量 a 并赋值为 3 。那么当调用 thebar() 函数时 , 你认为它会打印 a 的值是多少?
当 JavaScript 引擎执行此代码时 , 声明全局变量 a 并为其赋值 5 。然后 , 调用 bar() 函数 。在 bar() 函数内部 , 声明了一个局部变量 a 并赋值为 3 。该局部变量 a 与全局变量 a 不同 。之后 , 从 bar() 函数内部调用 foo() 函数 。
在 foo() 函数内部 , console.log(a) 语句尝试记录 a 的值 。由于 foo() 函数的作用域内没有定义局部变量 a , JavaScript 会查找作用域链以找到最近的名为 a 的变量 。作用域链是指函数在尝试查找和使用变量时可以访问的所有不同作用域 。
现在 , 我们来解决 JavaScript 将在哪里搜索变量 a 的问题 。它会在 bar 函数的范围内查找 , 还是会探索全局范围?事实证明 , JavaScript 将在全局范围内进行搜索 , 而这种行为是由称为词法范围的概念驱动的 。
词法作用域是指函数或变量在代码中编写时的作用域 。当我们定义 foo 函数时 , 它被授予访问其自己的本地作用域和全局作用域的权限 。无论我们在哪里调用 foo 函数 , 无论是在 bar 函数内部还是将其导出到另一个模块并在那里运行 , 这个特征都保持一致 。词法范围不是由我们调用函数的位置决定的 。
这样做的结果是输出始终相同:在全局范围内找到的 a 值 , 在本例中为 5 。
但是 , 如果我们在 bar 函数中定义了 foo 函数 , 则会出现不同的情况:
function bar() {var a = 3;function foo() {console.log(a);}foo();}var a = 5;bar();在这种情况下 ,  foo 的词法作用域将包含三个不同的作用域:它自己的局部作用域、 bar 函数的作用域和全局作用域 。词法范围由编译时将代码放置在源代码中的位置决定 。
当此代码运行时 , foo 位于 bar 函数内 。这种安排改变了范围动态 。现在 , 当 foo 尝试访问变量 a 时 , 它将首先在其自己的本地范围内进行搜索 。由于它在那里找不到 a , 因此它将搜索范围扩大到 bar 函数的范围 。你瞧 , a 存在 , 其值为 3 。因此 , 控制台语句将打印 3 。
5、对象强制const obj = {valueOf: () => 42,toString: () => 27};console.log(obj + '');


推荐阅读