您的位置  娱乐资讯

看完这几道 JavaScript 面试题,让你与考官对答如流(中)

  • 来源:互联网
  • |
  • 2020-01-13
  • |
  • 0 条评论
  • |
  • |
  • T小字 T大字

作者:Mark A
译者:前端小智
来源:dev


  • 26. 什么是IIFE,它的用途是什么?
  • 27. Function.prototype.apply方法的用途是什么?
  • 28. Function.prototype.call方法的用途是什么?
  • 29. Function.prototype.apply 和 Function.prototype.call 之间有什么区别?
  • 30. Function.prototype.bind的用途是什么?
  • 31. 什么是函数式编程? JavaScript的哪些特性使其成为函数式语言的候选语言?
  • 32. 什么是高阶函数?
  • 33. 为什么函数被称为一等公民?
  • 34. 手动实现`Array.prototype.map`方法
  • 35. 手动实现`Array.prototype.filter`方法
  • 35. 手动实现`Array.prototype.reduce`方法
  • 37. arguments 的对象是什么?
  • 38. 如何创建一个没有 prototype(原型) 的对象?
  • 39. 为什么在调用这个函数时,代码中的`b`会变成一个全局变量?
  • 40. ECMAScript是什么?
  • 41. ES6或ECMAScript 2015有哪些新特性?
  • 42. `var`,`let`和`const`的区别是什么
  • 43. 什么是箭头函数?
  • 44. 什么是类?
  • 45. 什么是模板字符串?
  • 46. 什么是对象解构?
  • 47. 什么是 ES6 模块?
  • 48. 什么是`Set`对象,它是如何工作的?
  • 49. 什么是回调函数?
  • 50. Promise 是什么?


26. 什么是 IIFE,它的用途是什么?

IIFE或立即调用的函数表达式是在创建或声明后将被调用或执行的函数。创建IIFE的语法是,将function (){}包裹在在括号()内,然后再用另一个括号()调用它,如:(function(){})()

(function(){...}());(function(){...})();(functionnamed(params){...})();(()=>{});(function(global){...})(window);constutility=(function(){return{...}})

这些示例都是有效的IIFE。倒数第二个救命表明我们可以将参数传递给IIFE函数。最后一个示例表明,我们可以将IIFE的结果保存到变量中,以便稍后使用。

IIFE的一个主要作用是避免与全局作用域内的其他变量命名冲突或污染全局命名空间,来个例子。

假设我们引入了一个omelibr.js的链接,它提供了一些我们在代码中使用的全局函数,但是这个库有两个方法我们没有使用:createGraph和drawGraph,因为这些方法都有bug。我们想实现自己的createGraph和drawGraph方法。

解决此问题的一种方法是直接覆盖:

functioncreateGraph(){//createGraphlogichere}functiondrawGraph(){//drawGraphlogichere}

当我们使用这个解决方案时,我们覆盖了库提供给我们的那两个方法。

另一种方式是我们自己改名称:

functionmyCreateGraph(){//createGraphlogichere}functionmyDrawGraph(){//drawGraphlogichere}

当我们使用这个解决方案时,我们把那些函数调用更改为新的函数名。

还有一种方法就是使用IIFE

constgraphUtility=(function(){functioncreateGraph(){//createGraphlogichere}functiondrawGraph(){//drawGraphlogichere}return{createGraph,drawGraph}})

在此解决方案中,我们要声明了graphUtility 变量,用来保存IIFE执行的结果,该函数返回一个包含两个方法createGraph和drawGraph的对象。

IIFE 还可以用来解决一个常见的面试题:

varli=document.querySelectorAll('.list-group>li');for(vari=0,len=li.length;i

假设我们有一个带有list-group类的ul元素,它有5个li子元素。当我们单击单个li元素时,打印对应的下标值。但在此外上述代码不起作用,这里每次点击 li 打印 i 的值都是5,这是由于闭包的原因。

闭包只是函数记住其当前作用域,父函数作用域和全局作用域的变量引用的能力。当我们在全局作用域内使用var关键字声明变量时,就创建全局变量i。因此,当我们单击li元素时,它将打印5,因为这是稍后在回调函数中引用它时i的值。

使用 IIFE 可以解决此问题:

varli=document.querySelectorAll('.list-group>li');for(vari=0,len=li.length;i

该解决方案之所以行的通,是因为IIFE会为每次迭代创建一个新的作用域,我们捕获i的值并将其传递给currentIndex参数,因此调用IIFE时,每次迭代的currentIndex值都是不同的。

27. Function.prototype.apply 方法的用途是什么?

apply() 方法调用一个具有给定this值的函数,以及作为一个数组(或类似数组对象)提供的参数。

constdetails={message:'HelloWorld!'};functiongetMessage(){returnthis.message;}getMessage.apply(details);//'HelloWorld!'

call()方法的作用和 apply() 方法类似,区别就是call()方法接受的是参数列表,而apply()方法接受的是一个参数数组。

constperson={name:"MarkoPolo"};functiongreeting(greetingMessage){return`${greetingMessage}${this.name}`;}greeting.apply(person,['Hello']);//"HelloMarkoPolo!"

28. `Function.prototype.call` 方法的用途是什么?

call() 方法使用一个指定的 this 值和单独给出的一个或多个参数来调用一个函数。

constdetails={message:'HelloWorld!'};functiongetMessage(){returnthis.message;}getMessage.call(details);//'HelloWorld!'

注意:该方法的语法和作用与 apply() 方法类似,只有一个区别,就是call() 方法接受的是一个参数列表,而 apply() 方法接受的是一个包含多个参数的数组。

constperson={name:"MarkoPolo"};functiongreeting(greetingMessage){return`${greetingMessage}${this.name}`;}greeting.call(person,'Hello');//"HelloMarkoPolo!"

29. Function.prototype.apply 和 Function.prototype.call 之间有什么区别?

apply()方法可以在使用一个指定的 this 值和一个参数数组(或类数组对象)的前提下调用某个函数或方法。call()方法类似于apply(),不同之处仅仅是call()接受的参数是参数列表。

constobj1={result:0};constobj2={result:0};functionreduceAdd(){letresult=0;for(leti=0,len=arguments.length;i

30. Function.prototype.bind 的用途是什么?

bind() 方法创建一个新的函数,在 bind() 被调用时,这个新函数的this 被指定为 bind() 的第一个参数,而其余参数将作为新函数的参数,供调用时使用。

importReactfrom'react';classMyComponentextendsReact.Component{constructor(props){super(props);this.state={value:""}this.handleChange=this.handleChange.bind(this);//将“handleChange”方法绑定到“MyComponent”组件}handleChange(e){//dosomethingamazinghere}render(){return(>)}}

31. 什么是函数式编程? JavaScript 的哪些特性使其成为函数式语言的候选语言?

函数式编程(通常缩写为FP)是通过编写纯函数,避免共享状态、可变数据、副作用 来构建软件的过程。数式编程是声明式 的而不是命令式 的,应用程序的状态是通过纯函数流动的。与面向对象编程形成对比,面向对象中应用程序的状态通常与对象中的方法共享和共处。

函数式编程是一种编程范式 ,这意味着它是一种基于一些基本的定义原则(如上所列)思考软件构建的方式。当然,编程范示的其他示例也包括面向对象编程和过程编程。

函数式的代码往往比命令式或面向对象的代码更简洁,更可预测,更容易测试 - 但如果不熟悉它以及与之相关的常见模式,函数式的代码也可能看起来更密集杂乱,并且 相关文献对新人来说是不好理解的。

JavaScript支持闭包和高阶函数是函数式编程语言的特点。

32. 什么是高阶函数?

高阶函数只是将函数作为参数或返回值的函数。

functionhigherOrderFunction(param,callback){returncallback(param);}

33. 为什么函数被称为一等公民?

在JavaScript中,函数不仅拥有一切传统函数的使用方式(声明和调用),而且可以做到像简单值一样赋值(var func = function(){})、传参(function func(x,callback){callback();})、返回(function(){return function(){}}),这样的函数也称之为第一级函数(First-class Function)。不仅如此,JavaScript中的函数还充当了类的构造函数的作用,同时又是一个Function类的实例(instance)。这样的多重身份让JavaScript的函数变得非常重要。

34. 手动实现 `Array.prototype.map 方法`

map() 方法创建一个新数组,其结果是该数组中的每个元素都调用一个提供的函数后返回的结果。

functionmap(arr,mapCallback){//首先,检查传递的参数是否正确。if(!Array.isArray(arr)||!arr.length||typeofmapCallback!=='function'){return[];}else{letresult=[];//每次调用此函数时,我们都会创建一个result数组//因为我们不想改变原始数组。for(leti=0,len=arr.length;i

35. 手动实现`Array.prototype.filter`方法

filter() 方法创建一个新数组, 其包含通过所提供函数实现的测试的所有元素。

functionfilter(arr,filterCallback){//首先,检查传递的参数是否正确。if(!Array.isArray(arr)||!arr.length||typeoffilterCallback!=='function'){return[];}else{letresult=[];//每次调用此函数时,我们都会创建一个result数组//因为我们不想改变原始数组。for(leti=0,len=arr.length;i

36. 手动实现`Array.prototype.reduce`方法

reduce() 方法对数组中的每个元素执行一个由您提供的reducer函数(升序执行),将其结果汇总为单个返回值。

functionreduce(arr,reduceCallback,initialValue){//首先,检查传递的参数是否正确。if(!Array.isArray(arr)||!arr.length||typeofreduceCallback!=='function'){return[];}else{//如果没有将initialValue传递给该函数,我们将使用第一个数组项作为initialValuelethasInitialValue=initialValue!==undefined;letvalue=hasInitialValue?initialValue:arr[0];、//如果有传递initialValue,则索引从1开始,否则从0开始for(leti=hasInitialValue?0:1,len=arr.length;i

37. arguments 的对象是什么?

arguments对象是函数中传递的参数值的集合。它是一个类似数组的对象,因为它有一个length属性,我们可以使用数组索引表示法arguments[1]来访问单个值,但它没有数组中的内置方法,如:forEach、reduce、filter和map。

我们可以使用Array.prototype.slice将arguments对象转换成一个数组。

functionone(){returnArray.prototype.slice.call(arguments);}

注意:箭头函数中没有arguments对象。

functionone(){returnarguments;}consttwo=function(){returnarguments;}constthree=functionthree(){returnarguments;}constfour=()=>arguments;four();//Throwsanerror-argumentsisnotdefined

当我们调用函数four时,它会抛出一个ReferenceError: arguments is not defined error。使用rest语法,可以解决这个问题。

constfour=(...args)=>args;

这会自动将所有参数值放入数组中。

38. 如何创建一个没有 prototype(原型)的对象?

我们可以使用Object.create方法创建没有原型的对象。

consto1={};console.log(o1.toString());//[objectObject]consto2=Object.create(null);console.log(o2.toString());//throwsanerroro2.toStringisnotafunction

39. 为什么在调用这个函数时,代码中的`b`会变成一个全局变量?

functionmyFunc(){leta=b=0;}myFunc();

原因是赋值运算符是从右到左的求值的。这意味着当多个赋值运算符出现在一个表达式中时,它们是从右向左求值的。所以上面代码变成了这样:

functionmyFunc(){leta=(b=0);}myFunc();

首先,表达式b = 0求值,在本例中b没有声明。因此,JS引擎在这个函数外创建了一个全局变量b,之后表达式b = 0的返回值为0,并赋给新的局部变量a。

我们可以通过在赋值之前先声明变量来解决这个问题。

functionmyFunc(){leta,b;a=b=0;}myFunc();

40. ECMAScript 是什么?

ECMAScript 是编写脚本语言的标准,这意味着JavaScript遵循ECMAScript标准中的规范变化,因为它是JavaScript的蓝图。

ECMAScript 和 Javascript,本质上都跟一门语言有关,一个是语言本身的名字,一个是语言的约束条件
只不过发明JavaScript的那个人(Netscape公司),把东西交给了ECMA(European Computer Manufacturers Association),这个人规定一下他的标准,因为当时有java语言了,又想强调这个东西是让ECMA这个人定的规则,所以就这样一个神奇的东西诞生了,这个东西的名称就叫做ECMAScript。

javaScript = ECMAScript + DOM + BOM(自认为是一种广义的JavaScript)

ECMAScript说什么JavaScript就得做什么!

JavaScript(狭义的JavaScript)做什么都要问问ECMAScript我能不能这样干!如果不能我就错了!能我就是对的!

免责声明:本站所有信息均搜集自互联网,并不代表本站观点,本站不对其真实合法性负责。如有信息侵犯了您的权益,请告知,本站将立刻处理。联系QQ:1640731186
友荐云推荐
热网推荐更多>>