2.this全面解析
2.1 调用位置
调用位置就是函数在代码中被调用的位置
分析调用栈:当前位置的函数调用列表,就是调用栈。栈中的第二个元素,就是真正的调用位置
2.2 绑定规则
- 默认绑定
独立函数调用:应用了this的默认绑定(指向全局对象),严格模式下,全局对象无法使用默认绑定,绑定到undefined。
决定this绑定对象的并不是调用位置处于严格模式而是函数体是否处于严格模式
- 隐式绑定
当函数引用有上下文对象时,this绑定到这个上下文对象
对象属性引用链中只有最顶层(最后一层)会影响调用位置
- 显式绑定
call(...)、apply(...)
如果传入一个原始值,这个原始值会被转换成他的对象形式,即 new String()。这种方式被称为装箱
- new绑定
在JavaScript中,构造函数只是一些使用new操作符时被调用的函数。他们并不属于一个类,也不会实例化一个类,它们甚至都不能说是一种特殊的函数类型,他们只是被new操作符调用的普通函数。
实际上并不存在所谓的“构造函数”,只有对于函数的“构造调用”。
使用new来调用函数,会执行以下操作:
- 创建(构造)一个全新的对象
- 这个新创建的对象会被执行“原型”连接
- 这个新对象会绑定到函数调用的this
- 如果函数没有其他返回对象,那么new表达式中的函数调用会自动返回这个新对象。
2.3 优先级
判断this:
1. 函数是否在 new 中调用( new 绑定) ? 如果是的话 this 绑定的是新创建的对象。
var bar = new foo()
2. 函数是否通过 call、 apply( 显式绑定) 或者硬绑定调用? 如果是的话, this 绑定的是
指定的对象。
var bar = foo.call(obj2)
3. 函数是否在某个上下文对象中调用( 隐式绑定) ? 如果是的话, this 绑定的是那个上
下文对象。
var bar = obj1.foo()
4. 如果都不是的话, 使用默认绑定。 如果在严格模式下, 就绑定到 undefined, 否则绑定到
全局对象。
var bar = foo()
var bar = new foo()
2. 函数是否通过 call、 apply( 显式绑定) 或者硬绑定调用? 如果是的话, this 绑定的是
指定的对象。
var bar = foo.call(obj2)
3. 函数是否在某个上下文对象中调用( 隐式绑定) ? 如果是的话, this 绑定的是那个上
下文对象。
var bar = obj1.foo()
4. 如果都不是的话, 使用默认绑定。 如果在严格模式下, 就绑定到 undefined, 否则绑定到
全局对象。
var bar = foo()
2.4 绑定例外
2.4.1 被忽略的this
如果把null或undefined作为this的绑定对象传入call,apply或bind,这些值在调用时会被忽略,实际应用的是默认绑定规则。
apply bind
安全的做法是传入一个特殊的对象,把this绑定到这个对象不会对程序产生任何副作用
∅ = Object.create(null);保护全局对象
2.4.2 间接引用
- function foo(){
- console.log(this.a);
- }
- var a = 2;
- var o = {a:3,foo;foo};
- var p = {a:4};
- o.foo(); //3
- (p.foo = o.foo)(); //2
(p.foo = o.foo) 的返回值是 目标函数的引用。因此调用位置是foo()
2.4.3 软绑定
硬绑定会大大降低函数的灵活性,硬绑定之后无法使用隐式绑定或显示绑定来修改this
softBind
2.5 this用法
箭头函数不使用this的四条标准规则,而是根据当前的作用域来解决this
箭头函数会继承外层函数调用的this绑定,绑定无法被修改,new也不行。
箭头函数和self = this都可以取代 bind();从本质来说,想取代的是this机制。
需尽量用bind,避免使用 箭头函数和self = bind;