没有重载
参数是由包含零个或多个值的数组表示的。没有函数签名,自然也就没有重载
prototype
属性存储了 Function 的原型对象
函数内部
1、arguments
属性代表传入函数的实参,它是一个类数组对象,包含调用函数时传入的所有参数。以 function 关键字定义函数(相对于使用箭头语法创建函数)时才会有。 arguments 对象其实还有一个 callee 属性,是一个指向 arguments 对象所在函数的 指针。
阶乘函数
function factorial(num) {
if (num <= 1) {
return 1;
} else {
return num * factorial(num - 1);
}
}
阶乘函数一般定义成递归调用的,就像上面这个例子一样。只要给函数一个名称,而且这个名称不 会变,这样定义就没有问题。但是,这个函数要正确执行就必须保证函数名是 factorial ,从而导致 了紧密耦合。使用 arguments.callee 就可以让函数逻辑与函数名解耦:
function factorial(num) {
if (num <= 1) {
return 1;
} else {
return num * arguments.callee(num - 1);
}
}
这个重写之后的 factorial() 函数已经用 arguments.callee 代替了之前硬编码的 factorial 。 这意味着无论函数叫什么名称,都可以引用正确的函数。考虑下面的情况:
let trueFactorial = factorial;
factorial = function() {
return 0;
};
console.log(trueFactorial(5)); // 120
console.log(factorial(5)); // 0
这里, trueFactorial 变量被赋值为 factorial ,实际上把同一个函数的指针又保存到了另一个 位置。然后, factorial 函数又被重写为一个返回 0 的函数。如果像 factorial() 最初的版本那样不 使用 arguments.callee ,那么像上面这样调用 trueFactorial() 就会返回 0 。不过,通过将函数与 名称解耦, trueFactorial() 就可以正确计算阶乘,而 factorial() 则只能返回 0。
2、this
在标准函数中, this 引用的是把函数当成方法调用的上下文对象,这时候通常称其为 this 值(在网页的全局上下文中调用函数时, this 指向 windows )。
window.color = 'red';
let o = {
color: 'blue'
};
function sayColor() {
console.log(this.color);
}
sayColor(); // 'red'
o.sayColor = sayColor;
o.sayColor(); // 'blue'
在箭头函数中, this 引用的是定义箭头函数的上下文。下面的例子演示了这一点。在对 sayColor() 的两次调用中, this 引用的都是 window 对象,因为这个箭头函数是在 window 上下文中定义的
window.color = 'red';
let o = {
color: 'blue'
};
let sayColor = () => console.log(this.color);
sayColor(); // 'red'
o.sayColor = sayColor;
o.sayColor(); // 'red'
在事件回调或定时回调中调用某个函数时, this 值指向的并非想要的对象。此时将回调函数写成箭头函数就可以解决问题。这是因为箭头函数中的 this 会保留定义该函数时的上下文。
function King() {
this.royaltyName = 'Henry';
// this 引用 King 的实例
setTimeout(() => console.log(this.royaltyName), 1000);
}
function Queen() {
this.royaltyName = 'Elizabeth';
// this 引用 window 对象
setTimeout(function() { console.log(this.royaltyName); }, 1000);
}
new King(); // Henry
new Queen(); // undefined
注:函数名只是保存指针的变量。因此全局定义的 sayColor() 函数和 o.sayColor() 是同一个函数,只不过执行的上下文不同。
3、caller
ECMAScript 5 也会给函数对象上添加一个属性: caller 。虽然 ECMAScript 3 中并没有定义,但所 有浏览器除了早期版本的 Opera 都支持这个属性。这个属性引用的是调用当前函数的函数,或者如果是 在全局作用域中调用的则为 null
function outer() {
inner();
}
function inner() {
console.log(inner.caller);
}
outer();
以上代码会显示 outer() 函数的源代码。这是因为 ourter() 调用了 inner() , inner.caller 指向 outer() 。如果要降低耦合度,则可以通过 arguments.callee.caller 来引用同样的值
function outer() {
inner();
}
function inner() {
console.log(arguments.callee.caller);
}
outer();
在严格模式下访问 arguments.callee 会报错。ECMAScript 5 也定义了 arguments.caller ,但 在严格模式下访问它会报错,在非严格模式下则始终是 undefined 。这是为了分清 arguments.caller和函数的 caller 而故意为之的。而作为对这门语言的安全防护,这些改动也让第三方代码无法检测同一上下文中运行的其他代码。严格模式下还有一个限制,就是不能给函数的 caller 属性赋值,否则会导致错误。
4、new.target
ECMAScript 中的函数始终可以作为构造函数实例化一个新对象,也可以作为普通函数被调用。ECMAScript 6 新增了检测函数是否使用 new 关键字调用的 new.target 属性。如果函数是正常调用的,则 new.target 的值是 undefined ;如果是使用 new 关键字调用的,则 new.target 将引用被调用的构造函数。
function King() {
if (!new.target) {
throw 'King must be instantiated using "new"'
}
console.log('King instantiated using "new"');
}
new King(); // King instantiated using "new"
King(); // Error: King must be instantiated using "new"
length
属性指明函数的形参个数
function func1() {}
function func2(a, b) {}
console.log(func1.length);
// expected output: 0
console.log(func2.length);
// expected output: 2
apply()
Function.prototype.apply()
//apply和call的区别传参不一样
fun.apply(thisArg, [argsArray])
function getMax(arr){ return Math.max.apply(null,arr)};/*得到最大值*/
function getMin(arr){ return Math.min.apply(null,arr)};/*得到最小值*/
var arr1 = new Array('1', '2', '3');
var arr2 = new Array('4', '5', '6');
//合并数组
Array.prototype.push.apply(arr1, arr2);
console.log(arr1); //["1", "2", "3", "4", "5", "6"]
//=====
function sum(num1, num2) {
return num1 + num2;
}
function callSum1(num1, num2) {
return sum.apply(this, arguments); // 传入 arguments 对象
}
function callSum2(num1, num2) {
return sum.apply(this, [num1, num2]); // 传入数组
}
console.log(callSum1(10, 10)); // 20
console.log(callSum2(10, 10)); // 20
call()
Function.prototype.call() 1.借用方法,call会修改this指向自身; 2.将伪数组改成真数组。
fun.call(thisArg, arg1, arg2, ...)
function add(a, b) {
return a + b;
}
function reduce(a, b) {
return a * b;
}
add.call(reduce, 10, 20)//30
function sum(num1, num2) {
return num1 + num2;
}
function callSum(num1, num2) {
return sum.call(this, num1, num2);
}
console.log(callSum(10, 10)); // 20
bind()
方法创建一个新的函数,在 bind() 被调用时,这个新函数的 this 被指定为 bind() 的第一个参数,而其余参数将作为新函数的参数,供调用时使用。 Function.prototype.bind()
function.bind(thisArg[, arg1[, arg2[, ...]]])
const module = {
x: 42,
getX: function() {
return this.x;
}
}
const unboundGetX = module.getX;
console.log(unboundGetX()); // The function gets invoked at the global scope
// expected output: undefined
const boundGetX = unboundGetX.bind(module);
console.log(boundGetX());
// expected output: 42
window.color = 'red';
var o = {
color: 'blue'
};
function sayColor() {
console.log(this.color);
}
let objectSayColor = sayColor.bind(o);
objectSayColor(); // blue
toString()
方法返回一个表示当前函数源代码的字符串 Function.prototype.toString()
function sum(a, b) {
return a + b;
}
console.log(sum.toString());//function sum(a, b) {return a + b;}
递归
一个方法自己调用自己,用上一次调用得出的结果作为这次的参数
var factorial = (function f(num) {
return typeof num === "number" ? num <= 1 ? 1 : num + f(num - 1) : "please a number"
})
闭包(closure)
是指有权访问另一个函数作用域中的变量的函数
function MyObject(name, message) {
this.name = name.toString();
this.message = message.toString();
}
(function() {
this.getName = function() {
return this.name;
};
this.getMessage = function() {
return this.message;
};
}).call(MyObject.prototype);
原型链
//ECMAScript的所有内置对象的原型链都指向Function对象的原型
Object.__proto__ === Function.prototype //true
Function.__proto__ === Function.prototype //true
Array.__proto__ === Function.prototype //true
String.__proto__ === Function.prototype //true
Number.__proto__ === Function.prototype //true
Boolean.__proto__ === Function.prototype //true
Date.__proto__ === Function.prototype //true
Error.__proto__ === Function.prototype//true
RegExp.__proto__ === Function.prototype//true
//自定义对象的原型的原型链指向Object对象的原型
Product.prototype.__proto__ === Object.prototype //true
Function.prototype.__proto__ === Object.prototype//true
Object.prototype.__proto__ === null //true 原型链的终点
变量提升
var fn,
function name,
var fn = function(){}
name();
function name(){}