function后面直接跟括号,中间没有函数名的就是匿名函数。javascript
let fn = function() { console.log('我是fn') } let fn2 = fn console.log(fn.name) //fn console.log(fn2.name)//fn,fn和fn2指向的是同一个function。
function后面有函数名字的,不是直接跟括号的的就是具名函数。
若是把一个具名函数赋值给一个变量,那么这个具名函数的做用域就不是window了。html
let fn = function fn1() { console.log('function') } console.log(fn.name) //fn1 console.log(fn1,name) // ReferenceError: fn1 is not defined
箭头函数是es6知识点,具备如下几个特色:java
let fn = e => e+1 console.log(fn(1)) //2 let fn1 = (i,y) => i+y console.log(fn1(2,3)) //5 let fn2 = (i,y) => { i+=1; y+=2; return i+y } console.log(fn2(5,6)) //13
静态做用域又叫作词法做用域,采用词法做用域的变量叫词法变量。词法变量有一个在编译时静态肯定的做用域。词法变量的做用域能够是一个函数或一段代码,该变量在这段代码区域内可见(visibility);在这段区域之外该变量不可见(或没法访问)。词法做用域里,取变量的值时,会检查函数定义时的文本环境,捕捉函数定义时对该变量的绑定。
词法做用域:变量的做用域是在定义时决定而不是执行时决定,也就是说词法做用域取决于源码,经过静态分析就能肯定,所以词法做用域也叫作静态做用域。 with和eval除外,因此只能说JS的做用域机制很是接近词法做用域(Lexical scope)。es6
经过词法做用域树能判断变量指向关系,可是不能判定变量的值,变量的值还须要根据执行顺序进一步做出判断,看一下例子:ajax
由于JavaScript采用的是词法做用域,bian'liang的做用域基于函数建立的位置,跟调用时的位置无关。数组
var i = 1, j = 2, k = 3; function a(o, p, x, q) { var x = 4; alert(i); function b(r, s) { var i = 11, y = 5; alert(i); function c(t) { var z = 6; alert(i); }; var d = function() { alert(y); }; c(60); d(); }; b(40, 50); } a(10, 20, 30); //1 11 11 5
/** * 模拟创建一棵语法分析树,存储function内的变量和方法 */ var SyntaxTree = { // 全局对象在语法分析树中的表示 window: { variables:{ i:{ value:1}, j:{ value:2}, k:{ value:3} }, functions:{ a: this.a } }, a:{ variables:{ x:'undefined' }, functions:{ b: this.b }, scope: this.window }, b:{ variables:{ i:'undefined' y:'undefined' }, functions:{ c: this.c, d: this.d }, scope: this.a }, c:{ variables:{ z:'undefined' }, functions:{}, scope: this.b }, d:{ variables:{}, functions:{}, scope: { scope: this.b } } };
/** * 活动对象:函数执行时建立的活动对象列表 */ let ActiveObject = { window: { variables: { i: { value: 1 } j: { value: 2 } k: { value: 3 } }, functions: { a: this.a } } a: { variables: { x: { vale: 4 }, functions: { b: this.b }, scope: this.window, params: { o: { value: 10 }, p: { value: 20 }, x: this.variables.x q: { vale: 'undefined' } }, arguments: [this.params.o, this.params.p, this.params.x] } } b: { variables: { i: { vale: 11 }, y: { vale: 5 }, }, functions: { c: this.c, d: this.d }, params: { r: { value: 40 } s: { value: 50 } }, arguments: [this.params.r, this.params.scope] scope: this.a } c: { variables: { z: { value: 6 }, functions: {}, params: { t: { value: 60 } }, arguments: [this.params.t] scope: this.b } } d: { variables: {}, functions: {}, params: {}, arguments: [] this.scope: this.b } }
进入call stack 时的一些规则:app
函数的全部形参(若是咱们是在函数执行上下文中)异步
全部函数声明(FunctionDeclaration, FD)ide
全部变量声明(var, VariableDeclaration)函数
/* * example1:形参 */ function test(a, b) { /* var a = 10 var b = undefined 根据规则1,在进入执行上下文时会自动对形参声明而且赋值。 */ console.log(a) var c = 10; function d() {} var e = function _e() {}; (function x() {}); } test(10); // 10
/* * example2:函数声明 */ function test(a, b) { console.log(a) function a() {} var e = function _e() {}; } test(10); // ƒ a() {} .根据规则2,进入执行上下文会自动声明形参而且赋值,可是同名的函数声明会替换这个变量。 function test(a, b) { console.log(a) var a = 30; var a = function _e() {}; } test(10); // 10 .根据规则2,进入执行上下文会自动声明形参而且赋值,可是同名的函数声明会替换这个变量。
/* * example3:变量声明 */ console.log(foo);//会打印出foo函数,根据规则3,同名的变量声明不会干扰函数声明和形参 function foo(){ console.log("foo"); } var foo = 1;
在es5中,函数有四种调用方式:
1. fn(p1,p2) 2. obj.fn(p1,p2) 3. fn.call(context,p1,p2) 4. fn.apply(context,p1,p2)
第三和第四种才是正常的js函数调用方式,其余两种就是语法糖。
fn(p1,p2) 等价于 fn.call(undefined,p1,p2) 等价于 fn.apply(context,[p1,p2]) obj.fn(p1,p2) 等价于 obj.fn.call(obj,p1,p2) 等价于 obj.fn.apply(obj,[p1,p2])
若是你传的 context 就 null 或者 undefined,那么 window 对象就是默认的 context(严格模式下默认 context 是 undefined)
this是call的第一个参数!!!!
var obj = { foo: function(){ console.log(this) } } var bar = obj.foo obj.foo() // 打印出的 this 是 obj bar() // 打印出的 this 是 window
obj.foo() 至关于 obj.foo.call(obj) 也就至关于把函数名前面的做为call的第一个参数,也就是this,若是没有就是window。 bar() 至关于 bar.call(undefined)
在执行函数的时候,this是隐藏的一个参数,且必须是一个对象,若是不是,js是自动把它转为对象。
function fn() { console.log(this) console.log(arguments) } fn.call(1,2,3) // Number {1} [2,3]
arguments是伪数组它相似于Array,但除了length属性和索引元素以外没有任何Array属性。
call和apply里面除了第一个参数以外的都是arguments,若是arguments的个数少建议使用call,使用apply也能够,若是不肯定就使用apply。
使用一下方法吧arguments转为真正的数组:
var args = Array.prototype.slice.call(arguments); var args = [].slice.call(arguments); // ES2015 const args = Array.from(arguments); const args = [...arguments]
MDN 官方文档对 bind() 的定义:
The bind() method creates a new function that, when called, has its this keyword set to the provided value, with a given sequence of arguments preceding any provided when the new function is called.
大概意思就是,bind会返回一个新的函数(并无的调用原来的函数),这个新函数会call原来的函数,call的参数由你决定。看例子:
this.x = 9; var module = { x: 81, getX: function() { return this.x; } }; var retrieveX = module.getX; var boundGetX = retrieveX.bind(module); boundGetX(); // 81
retrieveX.bind(module)返回了一个新的函数boundGetX,而后调用这个新的函数的时候,把这个函数里面的this绑定到了module对象上,因此this.x就至关于module.x也就是等于81.
在计算机科学中,柯里化(英语:Currying),又译为卡瑞化或加里化,是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,而且返回接受余下的参数并且返回结果的新函数的技术。这个技术由克里斯托弗·斯特雷奇以逻辑学家哈斯凯尔·加里命名的,尽管它是Moses Schönfinkel和戈特洛布·弗雷格发明的。
说的明白一点就是,给函数传递一部分参数,让它返回一个函数去处理其余参数,举个例子,求三个数之和:
let addOne = function add(x) { return function(y) { return function(z) { return x+y+z } } } let one = addOne(3) console.log(one)//ƒ (y) {return function (z) {return x + y + z}} let two = one(4) console.log(two)//ƒ (z) {return x + y + z} let three = two(5) console.log(three)//12
在数学和计算机科学中,高阶函数是至少知足下列一个条件的函数:
- 接受一个或多个函数做为输入
- 输出一个函数
举一些高阶函数的例子:
/* *接受一个或多个函数做为输入 */ 1. Array.prototype.filter() 2. Array.prototype.forEach() 3. Array.prototype.reduce() 4. Array.prototype.map() 5. Array.prototype.find() 6. Array.prototype.every()
/* *输出一个函数 */ 1. fn.bind(args)
函数A做为参数(函数引用)传递到另外一个函数B中,而且这个函数B执行函数A。咱们就说函数A叫作回调函数。若是没有名称(函数表达式),就叫作匿名回调函数。
名词形式:被当作参数的函数就是回调
动词形式:调用这个回调
注意回调跟异步没有任何关系
传递的方式有两种,函数引用和函数表达式。
$.get('myhtmlpage.html', myCallBack);//这是对的 $.get('myhtmlpage.html', myCallBack('foo', 'bar'));//这是错的,那么要带参数呢? $.get('myhtmlpage.html', function(){//带参数的使用函数表达式 myCallBack('foo', 'bar'); });
箭头函数的主要区别在this,箭头函数是没有this这个概念的,看例子:
setTimeout(function(a){ console.log(this) //这个this指的是{name:'Jack'} setTimeout(function(a){ console.log(this) //这个this指的是window,由于没有bind,调用setTimeout的是window },1000) }.bind({name:'Jack'}),1000)
setTimeout(function(a){ console.log(this) //这个this指的是{name:'Jack'} setTimeout(function(a){ console.log(this) //这个this指的是{name: "Jack"},由于bind了外面的this也就是{name: "Jack"} },1000) }.bind({name:'Jack'}),1000)
setTimeout(function(a){ console.log(this) //这个this指的是{name:'Jack'} setTimeout(a=>console.log(this),1000)//这个this指的是{name:'Jack'},由于箭头函数没有this的概念,它指的this就是外面的this,也就是{name:'Jack'} }.bind({name:'Jack'}),1000)
至此基本上说了js的全部函数内容,只是简单举个例子,更深刻的研究还须要看一些其余大佬的博客哦~~~~