针对高级前端的八个级JavaScript面试问题( 二 )

另一方面,__proto__ 属性,通常读作 "dunder proto",存在于每一个 JavaScript 对象中 。在 JavaScript 中,除了原始类型外,一切都可以被视为对象 。每个这样的对象都有一个原型 , 该原型作为对另一个对象的引用 。__proto__ 属性简单地是对这个原型对象的引用 。
当你试图访问对象上的一个属性或方法时 , JavaScript 会进行查找过程来找到它 。这个过程主要涉及两个步骤:
对象的自有属性:JavaScript 首先检查对象自身是否直接拥有所需的属性或方法 。如果在对象内找到了该属性 , 则直接访问和使用 。原型链查找:如果在对象自身没有找到该属性,JavaScript 将查看对象的原型(由 __proto__ 属性引用)并在那里搜索该属性 。这个过程会递归地沿着原型链进行,直到找到该属性或直到查找达到 Object.prototype 。如果在 Object.prototype 中甚至没有找到该属性,JavaScript 将返回 undefined,表示该属性不存在 。
4-作用域当编写 JavaScript 代码时,理解作用域的概念非常重要 。作用域指的是变量在代码的不同部分的可访问性或可见性 。下面我们通过一个代码片段来更仔细地了解这个概念:
function foo() {  console.log(a);}function bar() {  var a = 3;  foo();}var a = 5;bar();代码定义了两个函数 foo() 和 bar(),以及一个值为5的变量 a 。所有这些声明都发生在全局作用域中 。在bar()函数内部,声明了一个变量a并赋值为 3 。那么当bar()函数被调用时,你认为会输出哪个值的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函数的作用域 。果然,那里存在一个值为3a 。因此,控制台语句将输出3
5-对象强制类型转换const obj = {  valueOf: () => 42,  toString: () => 27};console.log(obj + '');一个引人入胜的方面是探究JavaScript如何处理对象转换为基本值,例如字符串、数字或布尔值 。这是一个有趣的问题,测试你是否了解对象的强制类型转换 。


推荐阅读