函数声明会提升,但是函数表达式不会。
foo(); // 不是 ReferenceError, 而是 TypeError! var foo = function bar() { // ... };变量标识符 foo 被提升并被附着在这个程序的外围作用域,所以 foo() 不会作为一个 ReferenceError 而失败。但 foo 还没有值,所以, foo() 就是试图调用一个 undefined 值,这是一个 TypeError —— 非法操作。
同时回想一下,即使它是一个命名的函数表达式,这个名称标识符在外围作用域中也是不可用的:
foo(); // TypeError bar(); // ReferenceError var foo = function bar() { // ... };这个代码段更准确地解释为:
var foo; foo(); // TypeError bar(); // ReferenceError foo = function() { var bar = ...self... // ... }虽然多个/重复的 var 声明实质上是被忽略的,但是后续的函数声明确实会覆盖前一个。
防止 this Implicitly Lost,导致意外情况发生。
function foo(something) { console.log( this.a, something ); return this.a + something; } var obj = { a: 2 }; var bar = foo.bind( obj ); var b = bar( 3 ); // 2 3 console.log( b ); // 5注意: 在ES6中,bind(..)生成的硬绑定函数有一个名为.name的属性,它源自于原始的 目标函数(target function)。举例来说:bar = foo.bind(..)应该会有一个bar.name属性,它的值为"bound foo",这个值应当会显示在调用栈轨迹的函数调用名称中。
这种行为的主要原因是,创建一个实质上忽略 this 的 硬绑定 而预先设置一部分或所有的参数的函数(这个函数可以与 new 一起使用来构建对象)。 bind(...) 的一个能力是,任何在第一个 this 绑定参数之后被传入的参数,默认地作为当前函数的标准参数(技术上这称为“局部应用”),是一种“柯里化”。
function foo(p1,p2) { this.val = p1 + p2; } // 在这里使用`null`是因为在这种场景下我们不关心`this`的硬绑定 // 而且反正它将会被`new`调用覆盖掉! var bar = foo.bind( null, "p1" ); var baz = new bar( "p2" ); baz.val; // p1p2MDN —— Function.prototype.bind()
fun.bind(thisArg[, arg1[, arg2[, ...]]])Parameters:
thisArg The value to be passed as the this parameter to the target function when the bound function is called.The value is ignored if the bound function is constructed using the new operator.arg1, arg2, ... Arguments to prepend to arguments provided to the bound function when invoking the target function.return value a copy of the given function with the specified this value and initial arguments.现在,我们可以按照优先顺序来总结一下从函数调用的调用点来判定this的规则了。按照这个顺序来问问题,然后在第一个规则适用的地方停下。
a) 函数是和 new 一起被调用的吗(new 绑定)?如果是,this 就是新构建的对象。
var bar = new foo()b) 函数是用 call 和 apply 被调用(明确绑定),甚至是隐藏在 bind 硬绑定 之中吗?如果是,this 就是明确指定的对象。
var bar = foo.call(obj2)c) 函数是用环境对象(也称为拥有者或容器对象)被调用的吗(隐含绑定)?如果是,this 就是那个环境对象。
var bar = obj1.foo()d) 否则,使用默认 this (默认绑定)。如果在 strict mode 下,就是 undefined,否则是 global 对象。 var bar = foo()。 以上,就是理解对于普通的函数调用来说的 this 绑定规则所需的全部。(almost)
创建完全为空的对象 的最简单方法就是 Object.create(null)。Object.create(null) 和 {} 很相似,但是没有 Object.prototype 的委托,所以它比 {} “空的更彻底”。
注意:代码最好在浏览器环境测试,node 环境中没有window变量,而且对于 setTimeout 中,this 也不是 global 对象。