本篇介绍javascript函数的相关概念javascript
var fn = function(){
console.log(1)
}
复制代码
function fnf(){
console.log(1)
}
复制代码
传递参数 参数名称,参数字符串java
var fnc = new Function('name','age','console.log(name,age)');
fnc('33',33)
复制代码
var + 函数名字
,而=后的做为参数进行赋值操做function
定义的函数,在变量提高的时候会总体进行提高;//函数表达式
console.log('--函数表达式开始-',fn)
var fn = function(){
console.log(1)
}
console.log('--函数表达式结束-',fn)
/** 函数fun */
console.log('--function开始-',fnf)
function fnf(){
console.log(1)
}
console.log('--function结束-',fnf)
复制代码
具名函数是有函数名字的函数,面试
var fnNameFn = function(){}
function fnNameFn2(){}
console.log(fnNameFn.prototype)
复制代码
无函数名称、如当即执行函数,ajax
(function(){ }())
复制代码
箭头函数涉及的内容比较多,最多见的就是this指向的问题。箭头函数最多见的使用场景就是回调函数了编程
let arrowFun = ()=>{}
console.log(arrowFun.prototype) // undefined
复制代码
箭头函数的定义格式浏览器
// 直接返回值
let arrfn = ()=> 2;
console.log(arrfn())
//传递参数进行判断
let arrfn2 = (name)=> name !='mfy';
console.log(arrfn2())
复制代码
函数的参数分为实参
和形参
markdown
function add(num1,num2){} // num1 、num2是形参
var a=1,b=3;
add(a,b) // a,b 为实参
复制代码
let funMfy =function(){
console.log(arguments)
}
funMfy('mfy','23')
//箭头函数
let fnnn = ()=>{
console.log(arguments)
}
fnnn('mfy',33) //报错
复制代码
let fyy = function(...args){
console.log(args)
}
fyy('mfy',32,[])
复制代码
函数的使用在js中很是很是多了,其实如下的相关介绍,无非就是在基础函数中进行变换和使用才有了下面的名此闭包
一个函数和对其周围状态(lexical environment,词法环境)
的引用捆绑在一块儿(或者说函数被引用包围),这样的组合就是闭包(closure)
。也就是说,闭包让你能够在一个内层函数中访问到其外层函数的做用域。在 JavaScript
中,每当建立一个函数,闭包就会在函数建立的同时被建立出来。app
function clouser(){
let a = '666'
return function(){
console.log(a)
}
}
let bfn = clouser();
bfn();//666
复制代码
扩展知识点:变量提高
做用域
闭包应用:工厂函数
当即执行函数
框架
高阶函数(higher-order-function)指操做函数的函数
,通常地,有如下两种状况:
javascript
中的函数显然知足高阶函数的条件,在实际开发中,不管是将函数看成参数传递,仍是让函数的执行结果返回另一个函数,这两种情形都有不少应用场景。下面将对这两种状况进行详细介绍;
把函数看成参数传递,表明能够抽离出一部分容易变化的业务逻辑,把这部分业务逻辑放在函数参数中,这样一来能够分离业务代码中变化与不变的部分。其中一个常见的应用场景就是回调函数。
回调函数是最多见的参数传递了在ajax异步请求的应用中,回调函数的使用很是频繁。想在ajax请求返回以后作一些事情,但又并不知道请求返回的确切时间时,最多见的方案就是把callback函数
看成参数传入发起ajax请求的方法中,待请求完成以后执行callback函数
;
function ajax(callback){
$.ajax( 'http://xx.com/getUserInfo?' + userId, function( data ){
//不肯定何时返回,进行回调执行
if ( typeof callback === 'function' ){
callback( data );
}
});
}
复制代码
不少框架已经异步处理的时候都使用了函数做为参数传入 Vue的this.nextTick
、React 的setState
闭包
、 工厂函数
、
function People(){}
function Factort(){
var instance = null
return function(){
if(!instance)
instance = new People();
}
return instance;
}
复制代码
函数的柯里化(currying)
又称部分求值。一个currying的函数首先会接受一些参数,接受了这些参数以后,该函数并不会当即求值,而是继续返回另一个函数,刚才传入的参数在函数造成的闭包中被保存起来。待到函数被真正须要求值的时候,以前传入的全部参数都会被一次性用于求值.简称闭包;
//通用的柯里化函数
var curring = function(fn){
var args = [];
return function(){
if(arguments.length ==0){
return fn.apply(this,args);
}else{
[].push.apply(args,arguments);
}
}
}
var cost1 = (function(){
var money = 0;
return function(){
for(var i=0;i<arguments.length;i++){
money+=arguments[i]
}
return money;
}
})()
var cost3 = curring(cost1);
cost3(100);
cost3(200);
cost3(100);
console.log(cost3())
复制代码
传递多个参数时候
/** * 求值柯里化 */
var curring3= function(fn){
//获取fn外的其余参数
var args = [].slice.call(arguments,1);
return function(){
// 获取fn的全部参数
var innerArgs =[].slice.call(arguments);
// 最终参数列表重合展开
var finnalArgs = args.concat(innerArgs);
//将参数列表展开,并传入fn中
return fn.apply(null,finnalArgs)
}
}
var cost6 = (function(){
var money = 0;
return function () {
for (var i = 0, l = arguments.length; i < l; i++) {
money += arguments[i];
}
return money;
}
})()
var costC = curring3(cost6,300,233);
console.log(costC(44))
console.log(costC(2003,444))
复制代码
Array.prototype
上的方法本来只能用来操做array对象。但用call和apply能够把任意对象看成this传入某个方法,这样一来,方法中用到this的地方就再也不局限于原来规定的对象,而是加以泛化并获得更广的适用性
有没有办法把泛化this的过程提取出来呢?反柯里化(uncurrying)就是用来解决这个问题的。反柯里化主要用于扩大适用范围,建立一个应用范围更广的函数。使原本只有特定对象才适用的方法,扩展到更多的对象。
Function.prototype.unCurring=function(){
var _this = this;
return function(){
var obj = Array.prototype.shift.call(arguments);
return _this.apply(obj,arguments); //更改当前的this指向
}
}
//另外一种方法实现
Function.prototype.currying = function() {
var _this = this;
return function() {
return Function.prototype.call.apply(_this, arguments);
}
}
复制代码
递归函数则是本身调用本身自己,最多见的一个就是对象的深拷贝
以及斐波那契
惰性函数
表示函数执行的分支只会在函数第一次调用的时候执行,在第一次调用过程当中,该函数会被覆盖为另外一个按照合适方式执行的函数,这样任何对原函数的调用就不用再通过执行的分支了。
javascript
的浏览器事件兼容
function addEvent(type, element, fun) {
if (element.addEventListener) {
element.addEventListener(type, fun, false);
}
else if(element.attachEvent){
element.attachEvent('on' + type, fun);
}
else{
element['on' + type] = fun;
}
}
//添加事件
//第一次绑定
var ele = document.getElementById("bind-event");
addEvent('bind-event',ele,()=>{
console.log(111)
});
//第二次绑定
var ele1= document.getElementById("bind-event2");
addEvent('click',ele1,()=>{
console.log(222)
})
复制代码
咱们每次绑定的时候都回去判断当前是否支持,而在一个浏览器中,咱们只须要进行判断一次便可;
惰性函数的本质就是函数重写
,所谓惰性载入,指函数执行的分支只会发生一次,有两种实现惰性载入的方式;
function addEvent(type, element, fun){
if (element.addEventListener) {
addEvent = function(type, element, fun){
element.addEventListener(type, fun, false);
}
}else if(element.attachEvent){
addEvent = function(type, element, fun){
element.attachEvent('on' + type, fun);
}
}else{
addEvent =function(type,element,fun){
element['on' + type] = fun;
}
}
return addEvent(type, element, fun)
}
复制代码
在这个惰性载入的addEvent()
中,if语句的每一个分支都会为addEvent变量赋值,有效覆盖了原函数。最后一步即是调用了新赋函数。下一次调用addEvent()
时,便会直接调用新赋值的函数,这样就不用再执行if语句了;
var addEvent = (function () {
if (document.addEventListener) {
return function (type, element, fun) {
element.addEventListener(type, fun, false);
}
}
else if (document.attachEvent) {
return function (type, element, fun) {
element.attachEvent('on' + type, fun);
}
}
else {
return function (type, element, fun) {
element['on' + type] = fun;
}
}
})();
复制代码
简单来讲,一个函数的返回结果只依赖于它的参数,而且在执行过程里面没有反作用,咱们就把这个函数叫作纯函数
。这么说确定比较抽象,咱们把它掰开来看:
var a =1;
function ac(b){
return a+b
}
复制代码
此时不是纯函数,由于此时函数的结果依赖的函数外部的变量a
;
const a = 1
const foo = (x, b) => x + b
foo(1, 2) // => 3
复制代码
此时函数依赖函数传递过来的参数,当传递的参数为1,2的时候,不管如何都不会改变函数传出的结果 一个函数的返回结果只依赖于它的参数。
👉🏻 引用类型数据 看成参数传入的时候,若是内部更改了引用类型的数据,那么他就不是纯函数
,由于出现了反作用;
这个高频点,另分出来进行解释
-《javascript 高级程序设计第四版》