JavaScript基础学习-this

this是指向当前的函数吗? 不是
  • demo
    我们试图在函数foo中调用自己count变量,但是事实上,this.count并不是foo的count,执行foo函数时,this的指向是window,所以this.count会在全局中查找,但是没有找到,会在全局变量中创建一个count变量,count为undefined,当对count变量进行++时出错,全局count的值为NaN
  function foo(num) {
    this.count++; // 调用时候的this 指向windows 创建全局变量 count
  }

  foo.count = 0;
  foo()
  console.log(foo.count)
this是什么

this是在运行时进行绑定的,并不是在编写时绑定,它的上下文取决于函数调用时的各种条件。this的绑定和函数声明的位置没有关系,只取决于函数的调用方式。
找到函数的调用位置
浏览器的Call Stack的第二个元素,就是函数的调用位置。
在这里插入图片描述

如何找到this
默认绑定
  • demo
    foo是直接调用的,this指向window,foo运行在严格模式下,this为undefined。严格模式下调用foo,不影响默认绑定。
  function foo() {
    // 'use strict'; // 严格模式下this为undefinedUncaught TypeError: Cannot read property 'a' of undefined
    console.log('默认绑定', this.a);
  }

  var a = 2; 
  foo(); // 2
   (() => {
    'use strict'; // 在严格模式下调用foo ,this还是window
    foo(); // 2
  })();
隐式绑定

当函数引用有上下文对象时,this绑定到这个上下文对象

  • demo1
    调用foo时,this被绑定到obj,所以this.a相当于obj.a
  function foo() {
    console.log('隐式绑定', this.a);
  }

  var obj = {
    a: 2,
    foo
  };

  obj.foo(); // 隐式绑定 2

  • demo2
    对象的属性调用中,只有最后一层影响this
    隐式丢失,bar是obj1.obj2.foo的一个引用,bar()是直接调用,默认绑定
  function foo() {
  console.log('隐式绑定', this.a);
}

var obj2 = {
  a: 3,
  foo
};
var obj1 = {
  a: 2,
  obj2
};
var a = 'global'
obj1.obj2.foo(); // 隐式绑定 3
var bar = obj1.obj2.foo;
bar(); // 隐式丢失 global
显式绑定

应用call(obj,arg),apply(obj,arguments),bind(obj)来指定this绑定。

  • demo1
    通过call,apply,bind指定this绑定
    硬绑定,函数bar和baz每次执行的时候都会绑定obj,所以叫硬绑定,硬绑定的this指向不可以修改
    例外,当null/undefined 作为this绑定对象传入call,apply,bind时,应用默认绑定规则,指向window
function foo(arg) {
  console.log(arg, this.a);
}

var obj = { a: 2 };
var a = 3
foo.call(obj, 'call'); // call 2
foo.apply(obj, ['apply']); // apply 2
foo.bind(obj)('bind'); // bind 2
var bar = foo.bind(obj);
bar('bind'); // bind 2
bar.call(window, 'bind window'); // bind window 2   bind绑定后,不可以在修改它的this 硬绑定

// this 绑定为null 或 undefined时,指向window
foo.call(null,'window'); // window 3
foo.call(undefined,'window'); // window 3

// 可以模拟bind
function baz() {
  foo.call(obj, '硬绑定');
}

baz(); // 硬绑定 2
baz.call(window); // 硬绑定 2   硬绑定  不可以修改this的指向
new绑定

JavaScript 的构造函数只是使用new操作符调用的函数,不属于某个类,也不会实例化一个类。任何函数都可以用new来调用,这种函数调用被称为构造函数调用。
new 调用函数过程

  1. 创建(或者说构造)一个全新的对象
  2. 这个新对象会被执行[[Prototype]]连接
  3. 这个新对象会绑定到函数调用的this
  4. 如果函数没有返回其他对象,那么new表达式中的函数调用会自动返回这个新对象
  • demo
    new 调用foo时,我们会构造一个新对象并把它绑定到foo调用中this上。
  function foo(a) {
    this.a = a;
  }

  var bar = new foo(2);
  console.log('bar.a', bar.a); // bar.a 2
this绑定优先级

new>显式绑定(call,apply,bind)>隐式绑定>默认绑定

  • demo1 new绑定>隐式绑定
  function foo(a) {
    this.a = a;
  }
  var obj1 = { foo };
  var obj2 = {};

  obj1.foo(2); // 隐式绑定
  console.log('隐式绑定', obj1.a); // 隐式绑定 2

  obj1.foo.call(obj2, 3); // 显式绑定
  console.log('显式绑定', obj2.a); // 显式绑定 3

  var bar = new obj1.foo(4); // new 绑定
  console.log(obj1.a); // 2
  console.log('new绑定', bar.a); // new 绑定4

  • demo2 new绑定>显式绑定
  function foo(a) {
    this.a = a;
  }
  var obj1 = {};
  var bar = foo.bind(obj1);
  bar(2);
  console.log('显式绑定', obj1.a); // 显式绑定 2

  var baz = new bar(3);
  console.log(obj1.a);
  console.log('new 绑定', baz.a); // new 绑定 3

  • demo3 bind可以将除了第一参数外的其他参数都传给下层函数(“部分应用”)
  function foo(p1, p2) {
    this.val = p1 + p2;
  }

  var bar = foo.bind(null, 'p1');
  var baz = new bar('p2');

  console.log(baz.val); // p1p2
软绑定

默认绑定一个全局对象,实现硬绑定的效果,同时保留隐式绑定或者显式绑定来修改this

  if (!Function.prototype.softBind) {
    Function.prototype.softBind = function(obj) {
      var fn = this;
      curried = [].slice.call(arguments, 1);
      var bound = function() {
        return fn.apply(!this || this === (window || global) ? obj : this, [
          ...curried,
          ...arguments
        ]);
      };
      bound.prototype = Object.create(fn.prototype);
      return bound;
    };
  }

  function foo() {
    console.log(`name:${this.name}`);
  }

  var obj = { name: 'obj' },
    obj2 = { name: 'obj2' },
    obj3 = { name: 'obj3' },
    fooOBJ = foo.softBind(obj);

  fooOBJ(); // name:obj

  obj2.foo = foo.softBind(obj);
  obj2.foo(); // name obj2

  fooOBJ.call(obj3); // name obj3
箭头函数

箭头函数不使用this的四种标准规则,而是根据外层(函数或者全局)作用域来决定this。
箭头函数的绑定无法被修改

  • demo1
    foo()调用时this被绑定到obj1,不会再被修改,所以输出2。
  function foo() {
    return a => {
      console.log('箭头函数', this.a);
    };
  }

  var obj1 = { a: 2 },
    obj2 = { a: 3 },
    bar = foo.call(obj1);

  bar.call(obj2); // 箭头函数 2

  • demo2
    上面的箭头函数类似于我们经常写的这种方式
  function foo() {
  var self = this;
  return function(a) {
    console.log('模拟箭头函数', self.a);
  };
}

var obj1 = { a: 2 },
  obj2 = { a: 3 },
  bar = foo.call(obj1);

bar.call(obj2); // 模拟箭头函数 2

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值