创建函数的5中方式
1 具名函数
function f(x,y){
return x+y
}
f.name // f
复制代码
2 匿名函数
var f
f = function(x,y){
return x+y
}
f.name // f
复制代码
3 具名函数赋值
var f
f = function f2(x,y){
return x+y
}
f.name // f2 what fuck 什么鬼?为啥是f2
console.log(f2) // undefined
复制代码
4 Function构造函数 window.Function
var f = new Function('x','y','return x+y')
f.name // anonymous(匿名的意思)
复制代码
5 箭头函数
var f = (x,y) => {
return x+y
}
//如果{}内只有一句话 则花括号和return可以同时省略
var sum = (x,y) => x+y
//如果()内只有一个参数,则可以省略括号
var n2 = n => n*n
复制代码
函数的内存图
let f = {}
f.param = ['x','y']
f.fbody = 'console.log(111)'
f.call = function(){
eval(f.fbody)
}
f.call() // 111
复制代码
f 是一个对象,把函数体封装成一个属性,通过f.call()去执行这个函数的函数体
scope 作用域
javascript在读取代码时会先将代码转换成 语法树
是否听过这么一句话?
如果在声明变量的时候不加var 你就是在声明全局变量 例如:a = 3
- 优先认为这是一个赋值语句
- 它会在当前作用域寻找 a的声明,如果没有,沿着作用域树向上查找,如果全局scope也没有变量a ,只能退而求其次,先声明变量a 再执行 a=3
就近原则
javascript 中作用域分为 全局作用域和函数作用域 只要有函数,就存在其对应的作用域 寻找一个变量的作用域 遵循 就近原则
this 和 arguments
- this的值到底是什么?
当前函数运行时所在的环境(即this的指向),也可以说 当前函数运行时所处的对象
复制代码
- arguments是什么?
当前函数的参数集合,它是一个类数组(likeArray)
复制代码
var obj = {
foo: function(){
console.log(this)
}
}
var bar = obj.foo
obj.foo() // 打印出的 this 是 obj
bar() // 打印出的 this 是 window
复制代码
最后两行函数的值为什么不一样?
函数的调用
function f(x,y){return x+y}
//第一种调用 语法糖
f(1,2) //3
//第二种调用 硬核玩家通过call调用函数 函数真正的使用方式应该是第二种
f.call(undefined,1,2) //3
复制代码
JavaScript 提供了call、apply、bind这三个方法,来切换/固定this的指向
call
用法
func.call(thisValue, arg1, arg2, ...)
复制代码
函数实例的call方法,可以指定函数内部this的指向(即函数执行时所在的作用域),然后在所指定的作用域中,调用该函数
var obj = {};
var f = function () {
return this;
};
f() === window // true 全局环境运行函数f时,this指向全局环境(浏览器为window对象)
f.call(obj) === obj // true call方法可以改变this的指向,指定this指向对象obj,然后在对象obj的作用域中运行函数f
复制代码
call方法的参数,应该是一个对象。如果参数为空、null和undefined,则默认传入全局(window)
var n = 123;
var obj = { n: 456 };
function a() {
console.log(this.n);
}
a.call() // 123
a.call(null) // 123
a.call(undefined) // 123
a.call(window) // 123
a.call(obj) // 456
复制代码
call方法还可以接受多个参数,第一个参数为this,后面的所有参数组成这个方法的参数集合arguments,它是一个伪数组
var fn1 = function(x,y){
return x+y
}
fn1.call(window,1,2) //this指向window arguments:[0:'1',1:'2',length:'2']
复制代码
apply
apply方法的作用与call方法类似,也是改变this指向,然后再调用该函数。唯一的区别就是:
- 它接收一个数组作为函数执行时的参数
用法
func.apply(thisValue, [arg1, arg2, ...])
复制代码
function f(x, y){
console.log(x + y);
}
f.call(null, 1, 1) // 2
f.apply(null, [1, 1]) // 2
复制代码
bind
- bind方法用于将函数体内的this绑定到某个对象,然后返回一个新函数。
- bind方法的参数就是所要绑定this的对象
var counter = {
count: 0,
inc: function () {
this.count++;
}
};
var func1 = counter.inc;
func1();
counter.count // 0 this指向window
var func2 = counter.inc.bind(counter);
func2();
counter.count // 1 通过bind绑定 this指向counter
复制代码
箭头函数
ES6中新出的函数创建方式
function log(a){
return a*2
}
//只有一个参数时,可以不用()将参数括起来
let log = a => a*2
function add(a,b){
return a+b
}
//方法体只有一句话时 可以不用{}将方法体括起来,也可以省略 return
let add = (a,b) => a+b
function sum(x,y){
let s = x+y;
return s
}
//方法体有多行时,需要用{}将方法体括起来
let sum = (x,y) => {
let s = x+y;
return s
}
复制代码
箭头函数的this
箭头函数内部的this是词法作用域,由上下文确定.也就是说箭头函数所处的作用域就是this的指向
setTimeout(function(){
console.log(this)
}.bind({name:'dsying'}),1000)
//输出:{name:'dsying'}
复制代码
setTimeout(function(){
console.log(this)
setTimeout(function(a){
console.log(this)
},1000)
}.bind({name:'dsying'}),1000)
//输出:
//{name:'dsying'}
//window
复制代码
要想让第二个定时器也打印出{name:'dsying'}
setTimeout(function(){
console.log(this)
setTimeout(function(a){
console.log(this)
}.bind(this),1000)
}.bind({name:'dsying'}),1000)
//输出:
//{name:'dsying'}
//{name:'dsying'}
复制代码
由于this在箭头函数中已经按照词法作用域绑定了,所以,用call()或者apply()调用箭头函数时,无法对this进行绑定,即传入的第一个参数被忽略:
setTimeout(function(){
console.log(this)
setTimeout(a => console.log(this),1000)
}.bind({name:'dsying'}),1000)
//输出:
//{name:'dsying'}
//{name:'dsying'}
复制代码