反复观看
1, call 和apply 的区别
这两个方法都会以指定的 this 值来调用函数,即会设 置调用函数时函数体内 this 对象的值。apply()方法接收两个参数:函数内 this 的值和一个参数数 组。第二个参 数可以是 Array 的实例,但也可以是 arguments 对象。
这里的 callSum()函数必须逐个地把参数传给 call()方法。结果跟 apply()的例子一样。到底是 8 使用 apply()还是 call(),完全取决于怎么给要调用的函数传参更方便。如果想直接传 arguments
对象或者一个数组,那就用 apply();否则,就用 call()。当然,如果不用给被调用的函数传参,则 使用哪个方法都一样。ECMAScript 5 出于同样的目的定义了一个新方法:bind()。bind()方法会创建一个新的函数实例, 其 this 值会被绑定到传给 bind()的对象。比如:
函数声明有会带来变量提升
arguments.callee 就是一个指向正在执行的函数的指针,因此可以在函数内部递归调用,如下 所示:
function factorial(num) { if (num <= 1) {
return 1; } else {
return num * arguments.callee(num - 1);
} }
像这里加粗的这一行一样,把函数名称替换成 arguments.callee,可以确保无论通过什么变量 调用这个函数都不会出问题。因此在编写递归函数时,arguments.callee 是引用当前函数的首选。
不过,在严格模式下运行的代码是不能访问 arguments.callee 的,因为访问会出错。此时,可 以使用命名函数表达式(named function expression)达到目的。比如:
const factorial = (function f(num) { if (num <= 1) {
return 1; } else {
return num * f(num - 1);
} });
这里创建了一个命名函数表达式 f(),然后将它赋值给了变量 factorial。即使把函数赋值给另 一个变量,函数表达式的名称 f 也不变,因此递归调用不会有问题。这个模式在严格模式和非严格模式 下都可以使用。
使用var 和不使用var的区别,如果不使用var的话,比如 num = 1; 这其实是一个赋值操作,那么就会在当前作用域链中寻找这个变量,如果找不到,就在window上创建一个属性。声明变量和创建对象属性这两者之间是有区别的。
即便如此,可能你还是很难明白"变量声明"跟"创建对象属性"在这里的区别。事实上,Javascript 的变量声明、创建属性以及每个 Javascript 中的每个属性都有一定的标志说明它们的属性----如只读(ReadOnly)不可枚举(DontEnum)不可删除(DontDelete)等等。
由于变量声明自带不可删除属性,比较 var num = 1 跟 num = 1,前者是变量声明,带不可删除属性,因此无法被删除;后者为全局变量的一个属性,因此可以从全局变量中删除
setTimeout就一定在设置的时间里执行吗,不一定,只是在设定的时间里,将setTimeout的回掉函数放到消息队列里,至于什么时候,回掉函数从队列里弹出来,这个时间是不可控制的。
try catch 不能捕获promise.reject的错误,因为 promise.reject是异步的,而try catch 是同步的。我们看到的异常,是消息队列在抛出的错误。