this

全局作用域下的this

在全局作用域下

  • 浏览器的this绑定为window{globalObject}
  • Node环境的this绑定为{},原因是Node环境下执行函数默认调用为function.call({})

函数作用域下的this

函数作用域下的this是动态绑定

  • 函数的this是在调用时才绑定在其FEC(函数执行上下文)

  • 跟函数所处位置无关

  • 仅跟函数被调用的方式有关

this的绑定规则

1.默认绑定

独立函数调用时,使用的默认绑定

  1. function foo(){
  2. console.log(this);
  3. bar();
  4. }
  5. function bar(){
  6. console.log(this);
  7. }
  8. /* 独立函数调用 */
  9. foo(); // window window

2.隐式绑定

通过某个对象进行调用,使用的隐式绑定

  1. const obj={
  2. name:'rv',
  3. say:function(){
  4. console.log(this.name);
  5. }
  6. }
  7. /* 通过对象调用 */
  8. obj.say();

3.apply(),call(),bind()

  1. function foo(){
  2. console.log(this);
  3. }
  4. /* 独立函数调用 */
  5. foo() // window
  6. /* call */
  7. foo.call({id:1}) // {id:1}
  8. /* apply */
  9. foo.apply({id:2}) // {id:2}
  10. /* bind */
  11. const f=foo.bind({id:3})
  12. f() // {id:3}

4.new绑定

使用new关键字来调用函数,会执行如下操作

  1. 创建一个新对象

  2. 该对象执行prototype连接

  3. 对该对象进行this绑定(将该会像绑定到函数执行上下文的this上)

    1. FEC{
    2. VO
    3. scopeChain
    4. thisBinging
    5. --------------
    6. 代码执行
    7. }
  1. 如果函数没有返回其他对象,则表达式会返回该对象

this绑定优先级

new绑定>显式绑定>隐式绑定>默认绑定

  1. function foo(){
  2. console.log(this);
  3. }
  4. var obj={
  5. foo:foo;
  6. }
  7. /* new绑定高于显式绑定 */
  8. var bar=foo.bind("abc");
  9. new bar() // foo:{}
  10. /* 显式绑定高于于隐式绑定 */
  11. obj.foo.call("abc") // String{"abc"}
  12. /* bind高于call和apply */
  13. foo.bind("abc").call("cba") // String{"abc"}

特殊情况——忽略显式绑定

当显式绑定传入null,undefined时,自动将this绑定成全局对象

  1. function foo(){
  2. console.log(this)
  3. }
  4. foo.apply(null) // window
  5. foo.call(undefined) // window

特殊情况——间接函数引用

  1. var obj1={
  2. foo:function(){
  3. console.log(this)
  4. }
  5. }
  6. var obj2={};
  7. /*
  8. 此处不加';'代码解析会出现问题,发出报错
  9. Uncaught TypeError: Cannot set properties of undefined (setting 'bar')
  10. */
  11. (obj2.bar=obj1.foo)() // window

ES6 箭头函数

省略语法糖

  • 参数只有一个时,()可以省略

  • 函数执行体只有一行且将执行结果作为函数返回值时,{}可以省略

  • 函数执行体只有一行且返回一个对象,{}省略的同时须加()告诉js解析器此处为整体

    1. var bar=()=>({
    2. name:'rv',age:18
    3. })

箭头函数的this获取

this永远指向定义时的上层作用域,任意绑定均不改变其this指向

测试面试题

第一题

  1. var name='window';
  2. var person={
  3. name:'person',
  4. sayName:function(){
  5. console.log(this.name);
  6. }
  7. }
  8. function sayName(){
  9. var s=person.sayName;
  10. s();
  11. person.sayName();
  12. (person.sayName)();
  13. (b=person.sayName)();
  14. }
  15. // 答案
  16. /*
  17. window(独立函数调用)
  18. person(隐式绑定)
  19. person(隐式绑定)
  20. window(独立函数调用)
  21. */

第二题

  1. var name='window';
  2. var person1={
  3. name:'person1',
  4. foo1:function(){
  5. console.log(this.name);
  6. },
  7. foo2:()=>console.log(this.name),
  8. foo3:function(){
  9. return function(){
  10. console.log(this..name);
  11. }
  12. },
  13. foo4:function(){
  14. return ()=>console.log(this.name)
  15. }
  16. }
  17. var person2={name:'person2'};
  18. person1.foo1();
  19. person1.foo1.call(person2);
  20. person1.foo2();
  21. person1.foo2.call(person2);
  22. person1.foo3()();
  23. person1.foo3.call(person2)();
  24. person.foo3().call(person2);
  25. person1.foo4();
  26. person1.foo4.call(person2)();
  27. person1.foo4().call(person2);
  28. // 答案
  29. /*
  30. person1(隐式绑定)
  31. person2(显式绑定)
  32. window(箭头函数,上层作用域为window)
  33. window(箭头函数,上层作用域为window)
  34. window(独立函数调用)
  35. window(独立函数调用)
  36. person2(显式绑定)
  37. person1(箭头函数,上层作用域为person1)
  38. person2(箭头函数,上层作用域为person2)
  39. person1(箭头函数,上层作用域为person1)
  40. */

第三题

  1. var name='window';
  2. function Person(name){
  3. this.name=name;
  4. this.foo1=function(){
  5. console.log(this.name);
  6. };
  7. this.foo2=()=>console.log(this.name);
  8. this.foo3=function(){
  9. return function(){
  10. console.log(this.name);
  11. };
  12. };
  13. this.foo4=function(){
  14. return ()=>{
  15. console.log(this.name);
  16. };
  17. };
  18. }
  19. var person1=new Person('person1');
  20. var person2=new Person('person2');
  21. person1.foo1();
  22. person1.foo1.call(person2);
  23. person1.foo2();
  24. person1.foo2.call(person2);
  25. person1.foo3()();
  26. person1.foo3.call(person2)();
  27. person1.foo3().call(person2);
  28. person1.foo4()();
  29. person1.foo4.call(person2)();
  30. person1.foo4().call(person2);
  31. // 答案
  32. /*
  33. person1(隐式绑定)
  34. person2(显式>隐式)
  35. person1(箭头函数,上层作用域person1)
  36. person1(箭头函数,上层作用域person1)
  37. window(默认绑定)
  38. window(默认绑定)
  39. person2(显式绑定)
  40. person1(箭头函数,上层作用域person1)
  41. person2(箭头函数,上层作用域person2)
  42. person1(箭头函数,上层作用域person1)
  43. */

第四题

  1. var name='window';
  2. function Person(name){
  3. this.name=name;
  4. this.obj={
  5. name:'obj',
  6. foo1(){
  7. return function(){
  8. console.log(this.name);
  9. };
  10. },
  11. foo2(){
  12. return ()=>console.log(this.name);
  13. },
  14. }
  15. }
  16. var person1=new Person('person1');
  17. var person2=new Person('person2');
  18. person1.obj.foo1()();
  19. person1.obj.foo1.call(person2)();
  20. person1.obj.foo1().call(person2);
  21. person1.obj.foo2()();
  22. person1.obj.foo2.call(person2)();
  23. person1.obj.foo2().call(person2);
  24. // 答案
  25. /*
  26. window
  27. window
  28. person2
  29. obj
  30. person2
  31. o
  32. */