我相信学习新事物和评估我们所知道的对我们自己的进步非常有用,并且避免我们觉得我们的知识已经过时的情况。在本文中,我将介绍一些常见的JavaScript知识。享受!1.声明看下面的代码并回答输出什么(以及为什么)。//situation1console.log(person);varperson='John';//situation2console.log(person);letperson='Phill';//situation3console.log(person);constperson='Frank';//situation4constperson='Vanessa';console.log(person);person='Mike';console.log(person);//situation5varperson='John';letperson='Mike';console.log(person);//situation6varperson='John';if(person){letperson='Mike';console.log(person);}console.log(person);描述情况1:预期结果是在控制台中看到文本John,但令人惊讶的是,我们看到记录了undefined。想知道为什么吗?好吧,这是经典的JavaScript在运行。这种行为称为提升。在幕后,该语言将变量声明和赋值分为两部分。无论开发人员最初在何处声明该变量,该变量都会移至顶部并声明其值设置为未定义。看起来像这样:varperson;console.log(person);person='John';情况2:在这里,结果将是引用错误。UncaughtReferenceError:Cannotaccess'person'beforeinitialization错误文本说明了一切。因为我们使用了关键字let,我们的变量被提升了,但没有被初始化,并且抛出这个错误通知我们我们正在尝试访问一个未初始化的变量。ES6中引入了let关键字,允许我们在块范围内使用变量,这有助于我们防止意外行为。这里我们得到和情况2一样的错误,不同的是我们使用了关键字const,这样可以防止变量在初始化后被重新赋值。ES6中也引入了这个关键字。情况4:在这种情况下,我们可以看到关键字const的工作原理以及它如何避免无意中重新分配变量。在我们的示例中,首先在控制台中看到Vanessa,然后是类型错误。UncaughtTypeError:Assignmenttoconstantvariableconst变量的使用随着我们的代码库呈指数级增长。情况5:如果变量已经在关键字var的范围内定义,在同一范围内使用关键字let再次声明变量将引发错误。因此,在我们的示例中,不会输出任何内容,并且会显示语法错误。UncaughtSyntaxError:Identifier'person'hasalreadybeendeclared情况6:我们有一个函数范围的变量和一个块范围的变量。在这种情况下,它们是否具有相同的名称或标识符并不重要。在控制台中,我们应该看到Mike和John按顺序输出。为什么?因为let关键字为我们提供了块范围内的变量,这意味着它们只存在于它们自己创建的范围内,在这种情况下,在if...else语句中。内部变量优先于外部变量,这就是我们可以使用相同标识符的原因。2.继承考虑以下类并尝试回答输出什么以及为什么。classPerson{constructor(){this.sayHello=()=>{return'Hello';}}sayBye(){return'Bye';}}classStudenttextendsPerson{sayHello(){return'HellofromStudent';}}conststudent=newStudent();console.log(student.sayHello());说明如果你的回答是你好,你是对的!为什么:每次我们创建一个新的Student实例时,我们将sayHello属性设置为一个函数,并返回字符串Hello。这发生在父(Person)类的构造函数中。在JavaScript中,类是语法糖,在我们的例子中,Student类中的sayHello方法是在原型链上定义的。考虑到每次我们创建Student类的实例时,我们都会为该实例设置sayHello属性,使其成为一个返回字符串Hello的函数,我们从不使用原型链上定义的函数,我们也从不看到消息Hello来自学生。3.对象可变性考虑以下情况下各部分的输出://situation1constuser={name:'John',surname:'Doe'}user={name:'Mike'}console.log(user);//situation2constuser={name:'John',surname:'Doe'}user.name='Mike';console.log(user.name);//situation3constuser={name:'John',surname:'Doe'}constanotherUser=user;anotherUser.name='Mike';console.log(user.name);//situation4constuser={name:'John',surname:'Doe',address:{street:'MyStreet'}}Object.freeze(user);user.name='Mike';user.address.street='MyDifferentStreet';console.log(user.name);console.log(user.address.street);说明情况一:如我们上面所说正如我们在第1节中了解到的,我们尝试重新分配一个不允许的const变量,所以我们会得到一个类型错误。控制台中的结果会显示如下文本:UncaughtTypeError:AssignmenttoconstantvariableSituation2:在这种情况下,即使我们用关键字const代替声明变量,也会有不同的行为。不同之处在于我们修改的是对象属性而不是它的引用,这在const对象变量中是允许的。控制台中的结果应该是单词Mike。情况3:通过将用户分配给另一个用户变量,您可以在它们之间共享引用或存储位置(如果您愿意)。换句话说,它们都将指向内存中的同一个对象,因此更改一个对象的属性将反映对另一个对象的更改。控制台中的结果应该是Mike。情况4:这里我们使用Object.freeze方法来提供先前场景(情况3)所缺少的功能。通过这个方法,我们可以“冻结”对象,使其属性值不允许被修改。但是有一个陷阱!它只进行浅层冻结,这意味着它不保护深层属性更新。这就是为什么我们能够在保持name属性不变的情况下更改street属性的原因。控制台中的输出为John,然后是MyDifferentStreet。4.箭头函数运行以下代码段后,会输出什么以及为什么:conststudent={school:'MySchool',fullName:'JohnDoe',printName:()=>{console.log(this.fullName);},printSchool:function(){console.log(this.school);}};student.printName();student.printSchool();表示控制台中的输出将是undefined,依次是MySchool。您可能熟悉以下语法:varme=this;//orvarself=this;//...//...//somewheredeep...//me.doSomething();您可以将me或self变量视为父作用域,它可用于在其中创建的每个嵌套函数。当使用箭头函数时,这是自动完成的,我们不再需要存储this引用以在代码中进一步访问。箭头函数本身并没有绑定,而是从父作用域继承了一个箭头函数,这也是调用printName函数后输出undefined的原因。5.销毁请查看下面的销毁信息,并回答会输出什么。是否允许给定语法,否则会引发错误?constrawUser={name:'John',surname:'Doe',email:'john@doe.com',displayName:'SuperCoolJohn',joined:'2016-05-05',image:'path-to-the-image',followers:45}letuser={},userDetails={};({name:user.name,surname:user.surname,...userDetails}=rawUser);console.log(用户);console.log(userDetails);表明虽然它有点开箱即用,但上面的语法是允许的,不会抛出错误!很整洁吧?上面的语法非常强大,让我们能够轻松地将任何对象拆分成两个更具体的对象,上面例子的控制台输出是://{name:"John",surname:"Doe"}//{email:"john@doe.com",displayName:"SuperCoolJohn",joined:"2016-05-05",image:"path-to-the-image",followers:45}6.调用下面会输出什么异步运行/等待?(async()=>{letresult='SomeData';letpromise=newPromise((resolve,reject)=>{setTimeout(()=>resolve('Somedataretrievedfromtheserver'),2000);});result=awaitpromise;console.log(result);})();如果你认为它在两秒后输出从服务器检索到的一些数据,那么你是对的!代码将暂停,直到承诺得到解决。两秒后,它将继续执行并输出给定??的文本。这意味着JavaScript引擎实际上一直在等待,直到异步操作完成。可以说async/await是获取promise结果的语法糖。它也被认为是一种更具可读性的promise.then方式。7.Return语句constmultiplyByTwo=(x)=>{return{result:x*2};}console.log(multiplyByTwo(2));意味着如果你的答案是{result:4},那你就错了。输出未定义。但是不要对自己太苛刻,考虑到我也写C#代码,这曾经也困扰过我,这在C#中不是问题。由于自动插入分号,上述代码将返回undefined。return关键字和表达式之间不允许有行尾。解决方案是通过以下方式之一修复函数:constmultiplyByTwo=(x)=>{return{result:x*2};}或constmultiplyByTwo=(x)=>{return({result:x*2});}
