关注前端小鱼,阅读更多原创技术文章相关代码→10.9函数内部ES5函数内部有两个特殊对象arguments和this,一个内部属性callerES6新增.target属性10.9。1argumentsarguments是一个类数组对象,里面包含了调用函数时传入的所有参数。只有用funciton关键字定义函数时才会有arguments对象(箭头函数没有)。该对象有一个callee属性,它指向参数所在的函数。指针(注意:是指针或函数名,不是函数)在严格模式下,访问arguments.callee会报错//递归函数:计算阶乘functionfactorial(num){if(num<=1)return1elsereturnnum*factorial(num-1)}//使用arguments.callee解耦函数逻辑和函数名functionfactorial(num){if(num<=1)return1elsereturnnum*arguments.callee(num-1)//callee指向arguments对象所在的函数}lettrueFactorial=factorial//保存函数指针//重写factorial函数,trueFactorial指针不变factorial=function(){return0}console.log(trueFactorial(5))//120,已经使用Arguments.callee解耦了函数体中的代码和函数名,仍然可以正常计算console.log(factorial(5))//0,函数被重写10.9.2this在标准函数中,this指向调用函数context对象,即函数执行的环境对象(全局作用域指向window)window.color='red'//vscode是node运行环境,无法识别全局对象window。在测试期间将窗口更改为globalleto={color:'blue'}functionsayColor(){console.log(this.color)}sayColor()//'red',this指向全局对象o.sayColor=sayColoro.sayColor()//'blue',this指向箭头函数中的对象o,this指向定义函数的上下文对象,即函数外的环境对象letsayColor2=()=>{console.log(this.color)//this指向定义sayColor2的上下文,即全局对象}sayColor2()//'red',this指向全局对象o.sayColor2=sayColor2o.sayColor2()//'red',this指向全局对象在事件回调或定时调用函数时回调,this没有指向想要的对象,把回调函数写成箭头函数即可解决问题functionKing(){this.royaltyName='Henry'setTimeout(()=>{)//箭头函数,this指向函数定义的上下文,即King()的函数上下文},1000)}functionQueen(){this.royaltyName='Elizabeth'setTimeout(function(){console.log(this.royaltyName)//标准函数,this指向调用函数的上下文,即setTimeout()的函数上下文},1000)}newKing()//'Henry',1秒后打印newQueen()//undefined,1秒后打印10.9.3callerES5定义caller属性,指向调用当前函数的函数(在全局范围内为null)functioncallerTest(){console.log(callerTest.caller)}callerTest()//null,调用functionouter(){inner()}functioninner(){console.log(inner.caller)}outer()//[函数n:outer],calledinouter()//解耦函数inner(){console.log(arguments.callee.caller)//arguments.callee指向参数所在函数的指针,即inner}outer()//[Function:outer],调用outer()时arguments.caller的值总是undefined。这是为了区分arguments.caller和函数的调用者。在严格模式下,访问arguments.caller并为函数的caller属性赋值会报错函数:inner2]}inner2()10.9.4new.targetES6函数内部添加new.target属性,检测函数是否使用new关键字调用未使用的new调用,new.target的值为undefined使用newcall,new.target的值为被调用的构造函数King2(){if(!new.target){console.log(new.target,'King2mustbeinstantiatedusing"new"')}else{console.log(new.target,'King2instantiatedusing"new"')}}newKing2()//[Function:King2]'King2instantiatedusing"new"'King2()//undefined'King2mustbeinstantiatedusing"new"'10.10函数属性和方法函数包含2个属性:length和prototypelength,用于保存函数期望接收的命名参数个数functionnameLength(名称){返回名称}函数sumLength(sum1,sum2){returnsum1+sum2}functionhelloLength(){return'Hello'}console.log(nameLength.length,sumLength.length,helloLength.length)//120prototype指向函数的原型对象,保存所有实例方法函数的不能枚举(使用for-in无法找到)console.log(Array.prototype)//在浏览器中查看Array的原型对象,包括sort()等方法console.log(Object.keys(Array))//[],Array构造函数本身的所有可枚举属性console.log(Object.getOwnPropertyNames(Array))//['length','name','prototype','isArray','from','of'],Array构造函数本身的所有属性函数都有3个方法:apply()、call()和bind()functionsumPrototype(num1,num2){returnnum1+num2}apply()和call()将使用指定this按值调用函数,即调用函数时在函数体中设置this的指向。apply()接收2个参数:①运行函数的作用域(指定this);②参数数组(可以使用实例或arguments对象)functionapplySum1(num1,num2){returnsum.apply(this,arguments)//传入arguments对象}functionapplySum2(num1,num2){returnsum.apply(this,[num1,num2])//传入数组实例}console.log(applySum1(10,10))//20console.log(applySum2(10,10))//20call()接收几个参数:①运行函数的范围(指定这个);其余参数传递给functioncallSum(num1,num2){returnsum.打电话(你s,num1,num2)//每个参数一个一个传入}console.log(callSum(10,10))//20apply()和call()的真正强大之处在于能够扩展函数的作用域操作,即控制函数体中this的值window.color='red'//vscode是node运行环境,无法识别全局对象window,所以测试时将window改为globalleto2={color:'blue'}functionsayColor3(){console.log(this.color)}sayColor3()//'red',this指向全局对象sayColor3.call(this)//'red',this指向globalobjectsayColor3.call(window)//'red',this指向全局对象,测试时,将窗口更改为globalsayColor3.call(o2)//'blue',this指向对象o2Function.prototype.apply.call(),将函数原型的apply方法与call()绑定(可以通过Reflect.apply()使用,简化代码)letf1=function(){console.log(arguments[0]+this.标记)}leto3={标记:95,}f1([15])//'15undefined',this指向f1的函数上下文,this.mark为undefinedf1.apply(o3,[15])//110,将f1的this绑定到o3Function.prototype.apply.call(f1,o3,[15])//110,函数f1的原型对象的apply方法使用call绑定Reflect.apply(f1,o3,[15])//110,通过指定参数列表,三个参数(目标函数、绑定指定this对象、实参列表)bind()创建一个新的函数实例,其this绑定到传递给bind()的对象上leto4={color:'blue'}functionsayColor4(){console.log(这个。山口or)}letbindSayColor=sayColor4.bind(o4)//创建一个实例bindSayColor,它的this绑定到o4sayColor4()//'red',this指向全局对象bindSayColor()//'blue',thisisbound对象o410.11函数表达式的函数声明的关键特性是函数声明提升,即函数声明将在代码执行之前得到定义sayHi()//'Hi',先调用再声明functionsayHi(){console.log('Hi')}函数表达式必须在使用前赋值,即创建一个匿名函数(函数后没有标识符),然后赋值给一个变量。匿名函数的name属性为空字符串sayHi2()//ReferenceError:Cannotaccess'sayHi2'beforeinitialization,cannotbecalledandthenassignedletsayHi2=functionsayHi(){console.log('Hi')}函数声明和函数表达式的区别在于提升。避免在条件块中使用函数声明,你可以使用函数表达式)}}sayHi3()//不同的浏览器有不同的结果,避免在条件块中使用函数声明letsayHi4if(condition){sayHi4=function(){console.log('true')}}else{sayHi4=function(){console.log('false')}}sayHi4()//false,你可以在条件块中使用函数表达式来创建函数并将它们赋值给变量,它可以用来返回另一个函数作为函数中的值/***根据某个对象数组objectkey,进行数组排序*@param{String}key待排序的key*@param{String}正向/反向排序:asc/desc,默认为asc*/functionarraySort(key,sort){returnfunction(a,b){if(sort==='asc'||sort===undefined||sort===''){//positive顺序:a[key]>b[key]if(a[key]>b[key])return1elseif(a[key]b[key])return-1elsereturn0}}}varuserList=[{name:'Tony',id:3},{name:'Tom',id:2},{name:'Jack',id:5},]console.log(userList.sort(arraySort('id')))//[{name:'Tom',id:2},{name:'Tony',id:3},{name:'Jack',id:5}],按id正序排列console.log(userList.sort(arraySort('id','desc')))//[{name:'Jack',id:5},{name:'Tony',id:3},{name:'Tom',id:2}],按id倒序排序console.log(userList.sort(arraySort('name')))//[{name:'Jack',id:5},{name:'Tom',id:2},{name:'Tony',id:3}],按姓名正序排列摘要并询问参数是什么?争论。被调用者指向哪里?写一段代码说明函数名的阶乘函数this的指向和标准函数与箭头函数的函数逻辑解耦的区别?为什么在事件回调或定时回调中使用箭头函数更好?函数的调用者属性指向哪里?arguments.caller的值是多少?严格模式对调用者有什么限制?new.target的作用和价值是什么?函数有什么性质?它的方向和用法是什么?请用代码证明apply()、call()、bind()是如何扩展函数作用域的,并解释Function.prototype.apply.call()的含义函数声明和函数表达式最大的区别是什么?如何理解语句提升?写一段代码,根据对象数组的一个对象属性进行排序,根据参数确定排序属性和升/降序
