• **this**是 this 那条语句所在的执行上下文,在非严格模式下,全局指向**window**,在函数中则取决于函数的调用位置(即函数被谁调用了)

浏览器(runtime)

非严格模式

  • this的四种绑定规则
    • 默认绑定
      • 独立的函数调用。直接fn()
    • 隐式绑定
      • a.b.fn()的时候,fn里面的this指向了离fn最近的对象b
    • 显示绑定
      • call、apply、bind方法,改变this的绑定
    • new 绑定

      默认绑定

      ```javascript // 案例一 function a() { console.log(this); } a(); // window

/**

  • 就是function a,挂载在window上
  • 所以当执行a(),可以理解成window.a() */ console.log(window.a);
    1. ```javascript
    2. // 案例二
    3. function a() {
    4. function b() {
    5. function c() { console.log(this) }
    6. c()
    7. }
    8. b()
    9. }
    10. a(); // window
    ```javascript // 案例三 let obj = {} function a() { function b() { function c() { console.log(this) } c() } b.apply(obj) } a(); // window /**
  • 这说明c的this并不受所在函数b的影响
  • 仅仅是因为直接c(),这样调用c函数,即使用了默认绑定的方式 */ ```

    隐式绑定

    ```javascript // 案例一 let obj = { a: function() {
    1. console.log(this)
    } } obj.a(); // obj /**
  • 很明显,a被obj调用,所以函数a里面的this指向obj */ javascript // 案例二 // 本来是隐式绑定,但实际上 隐式丢失 了,变成了默认绑定 let obj = { a: function() { console.log(this) } }

let fn = obj.a fn(); // window /**

  • obj.a赋给了fn。调用fn的时候,前面没有xxx.fn,而是直接fn(),所以采用了默认绑定 */ javascript // 案例三 // 同理,另一个隐式丢失的情况 let obj = { a: function() { return function() {
    1. console.log(this)
    } } }

let fn = obj.a(); fn(); // window

  1. <a name="j3MHy"></a>
  2. ### 显示绑定
  3. - call、apply、bind的区别
  4. - `fn.call( <this> ,p1,p2...)`
  5. - `fn.apply( <this> ,[p1,p2...])`
  6. - `fn.bind( <this> )(p1,p2...)`
  7. - 注意:如果把`null`或者`undefined`作为 this 的绑定对象传入`call`、`apply`或者`bind`,这些值在调用时会被忽略,实际应用的是默认绑定规则。
  8. - 注意:如果传入的是 `值类型` 而不是 `引用类型` 的话,那么将会把`值类型`隐式转换为对应的 `对象形式`(也就是 `new String()`、`new Number()`之类的)
  9. ```javascript
  10. // 案例一
  11. let obj = {
  12. name: 'kons'
  13. }
  14. function a() {
  15. console.log(this.name);
  16. }
  17. a.call(obj); // kons
  18. a.apply(obj); // kons
  19. a.bind(obj)(); // kons
  1. // 案例二
  2. // 理解bind的实现,简陋版
  3. Function.prototype.mybind = function (obj) {
  4. let __this = this; // 获取函数实例
  5. return function (...rest) {
  6. __this.apply(obj, rest); // 硬绑定
  7. }
  8. }
  9. // 知道了这个之后,就知道下面这个,为什么是window,而不是obj
  10. let obj = {
  11. a: function () {
  12. console.log(this)
  13. }
  14. }
  15. let fn = obj.a
  16. fn.bind(null).call(obj); // window
  1. // 手写bind函数
  2. Function.prototype.mybind = function (objThis, ...params) {
  3. const thisFn = this; // 保存当前调用的函数
  4. let funcForBind = function (...otherParams) {
  5. // 如果是new出来的,this会指向新new出来的对象。如果不是,this是指向window,改为指向objThis
  6. const isNew = this instanceof funcForBind;
  7. const thisArg = isNew ? this : objThis;
  8. return thisFn.call(thisArg, ...params, ...otherParams);
  9. }
  10. // 克隆一下
  11. funcForBind.prototype = Object.create(thisFn.prototype);
  12. return funcForBind;
  13. }

new绑定

  • 定义JS的“构造函数”:在JS中,构造函数只是一些使用new操作符时被调用的函数。它们只是被new操作符调用的普通函数而已。
    • 包括内置对象函数,Number、String等等,也只是普通函数
    • 实际上并不存在所谓的“构造函数”,只有对函数的“构造调用”
  • new来调用函数、或者说发生构造函数调用时,会自动执行下面的五步
    • 1.创建一个新的空对象{}
    • 2.将构造函数的prototype属性赋值给新对象的__proto__
    • 3.将构造函数的this指向新对象
    • 4.执行构造函数的代码
    • 5.如果函数没有返回其他引用类型,那么new表达式中的函数调用会自动返回这个新对象 ```javascript // 案例一 //在声明函数的时候,会自动创建一个prototype属性,我们管他叫函数原型对象,一般用来存放实例公用的方法 function CreateCat(name){ this.name = name; }

CreateCat.prototype.eat = function(something){ console.log(this.name + ‘ eat ‘ + something); } /**

  • CreateCat.prototype = new Object() —> {
  • proto: Object.prototype,
  • constructor: CreateCat(){…},
  • eat: function(something){…}
  • } */

var catA = new CreateCat(‘xiaoA’); /**

  • catA = {
  • proto: CreateCat.prototype,
  • name: ‘xiaoA’
  • } */ javascript // 案例二 function Test() { this.name = ‘Test’; this.count = 2; return 456 }

const one = new Test();

console.log(one); // {name: ‘Test’, count: 2}

  1. ```javascript
  2. // 案例三
  3. function Test() {
  4. this.name = 'Test';
  5. this.count = 2;
  6. return [456]; // 换成其他引用类型就会改变,如{go:4}、function(){}、new Number(456)
  7. }
  8. const one = new Test();
  9. console.log(one); // [456]

四种绑定的优先级

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

绑定的例外

  • 软绑定

    • 作用:解决由于硬绑定,无法使用 隐式绑定 或者 显示绑定 来修改this
      1. // 软绑定的实现
      2. Function.prototype.softBind = function(objThis,...params) {
      3. let thisFn = this;
      4. let bound = function(...otherParams){
      5. let context = (!this || this === (window || global)) ? objThis: this;
      6. return thisFn.call(context, ...params, ...otherParams);
      7. }
      8. bound.prototype = Object.create(thisFn.prototype);
      9. return bound;
      10. }
      11. // 使用方法
      12. let obj = {};
      13. function a() {
      14. console.log(this);
      15. }
      16. a.bind(null).apply(obj); // window
      17. a.softBind(null).apply(obj); // obj
  • 箭头函数

    • 函数体内的this对象,继承的是外层代码块的this
    • 函数没有prototype原型
    • 不可以作为构造函数。new了会报错
    • 没有arguments
    • 箭头函数没有自己的this,所以不能用call()、apply()、bind()这些方法去改变this的指向