Function 函数
JS
的函数是一个 Function
对象(typeof function(){} === 'function'
) (function(){}).constructor === Function
构造函数
Function()
动态创建函数,它只能创造全局执行的函数
JS
const sum = new Function('a', 'b', 'return a + b');
// 等同于
const function sum(a, b) {
return a + b;
}
const sum = new Function('a', 'b', 'return a + b');
// 等同于
const function sum(a, b) {
return a + b;
}
实例属性
name
函数名称displayName
函数的显示名称length
函数期望参数数量,ES6
支持了默认参数与rest
参数,这个值可能不准确
实例方法
apply
call
bind
函数类型
- 函数声明
JS
function foo() { }
function foo() { }
- 函数表达式
JS
let foo = function() { }
let foo = function() { }
- 匿名函数
JS
function() { }
function() { }
- 箭头函数
JS
let foo = () => { }
let foo = () => { }
- 构造函数
JS
let foo = new Function('a', 'b', 'return a + b');
let foo = new Function('a', 'b', 'return a + b');
ES6 相关
- 增加了参数默认值
- 参数变量不可被再次声明
- 参数可使用解构赋值
- 指定参数默认值后,
length
属性失真 - 设置了参数的默认值,函数进行声明初始化时,参数会形成一个单独的作用域(context)。等到初始化结束,这个作用域就会消失。
- 增加了
rest
参数(...变量名取代原有arguments
)注意,arguments
是类数组对象,转为数组方法有:Array.prototype.slice.call(arguments)
[].slice.call(arguments)
Array.from(arguments)
[...arguments]
- 增加了箭头函数
try{ } catch(err) { }
可以省略catch
参数,即try{ } catch { }
箭头函数
箭头函数注意点
- 函数体内的
this
对象,就是定义时所在的对象,而不是使用时所在的对象 - 不可以当作构造函数,也就是说,不可以使用
new
命令,否则会抛出一个错误,所以也没用prototype
属性 - 不可以使用
arguments
对象,该对象在函数体内不存在。可以用rest
参数代替 - 不可以使用
yield
命令,因此箭头函数不能用作Generator
函数
关于第一点
JS
function foo() {
setTimeout(() => {
console.log('id:', this.id); // 指向定义时的对象,即foo
}, 100);
}
var id = 21;
foo.call({ id: 42 });
// id: 42
function foo() {
setTimeout(() => {
console.log('id:', this.id); // 指向定义时的对象,即foo
}, 100);
}
var id = 21;
foo.call({ id: 42 });
// id: 42
JS
function foo() {
setTimeout(function() {
console.log('id:', this.id); // 执行时已经变为 window 下的普通函数
}, 100);
}
var id = 21;
foo.call({ id: 42 });
// id: 21
function foo() {
setTimeout(function() {
console.log('id:', this.id); // 执行时已经变为 window 下的普通函数
}, 100);
}
var id = 21;
foo.call({ id: 42 });
// id: 21
箭头函数不使用场景
因为箭头函数是定义时确定了 this
指向
- 对象内的方法定义
以下这种情况,this
会指向window
,因为对象没有单独的作用域,所以this
在定义时就指向了最近的外层,即window
JS
const cat = {
lives: 9,
jumps: () => {
this.lives--;
}
}
const cat = {
lives: 9,
jumps: () => {
this.lives--;
}
}
高阶函数
高阶函数名字听着高大上,其实它只是一个函数,接收函数作为参数或将函数作为输出返回。常用到的回调函数或者闭包都是高阶函数。
1. 作为参数
我们日常使用的回调函数所在的函数,就是个高阶函数,还有一些数组的遍历方法的参数,也是传入函数,例如:map
、reduce
等
JS
[].map(function(item, index, arr) {
return item;
})
[].map(function(item, index, arr) {
return item;
})
2. 作为返回值
JS
function bar(){
return function (){
}
}
function bar(){
return function (){
}
}
问题
1. 箭头函数相较传统函数有什么差异
- 写法简洁
- 无
this
指向 - 不能作为构造函数,所以也没用
prototype
属性 - 没有
arguments
对象 - 使用
call,apply,bind
不会改变箭头函数中的this
指向- 当对箭头函数使用
call
或apply
方法时,只会传入参数并调用函数,并不会改变箭头函数中this
的指向。 - 当对箭头函数使用
bind
方法时,只会返回一个预设参数的新函数,并不会改变这个新函数的this
指向。
- 当对箭头函数使用
示例:
JS
window.name = "window_name";
let f1 = function () {
return this.name;
};
let f2 = () => this.name;
let obj = { name: "obj_name" };
console.log(f1.call(obj)); //obj_name
console.log(f2.call(obj)); // window_name
console.log(f1.apply(obj)); // obj_name
console.log(f2.apply(obj)); // window_name
console.log(f1.bind(obj)()); // obj_name
console.log(f2.bind(obj)()); // window_name
window.name = "window_name";
let f1 = function () {
return this.name;
};
let f2 = () => this.name;
let obj = { name: "obj_name" };
console.log(f1.call(obj)); //obj_name
console.log(f2.call(obj)); // window_name
console.log(f1.apply(obj)); // obj_name
console.log(f2.apply(obj)); // window_name
console.log(f1.bind(obj)()); // obj_name
console.log(f2.bind(obj)()); // window_name