1. JavaScript function this points to

 1 binding rules for this

2 apply/call/bind

3 this binding priority

4 Situations outside of binding

5 Use of arrow functions

6 points for this interview question

  <script>

    // 定义函数
    function foo(name) {
      console.log("foo函数:", this)
    }

    // 1.方式一: 直接调用 这里的this指向window
    // foo()

    // 2.方式二: 通过对象调起 这里的this指向obj
    var obj = { name: "why" }
    obj.aaa = foo
    
    obj.aaa()

  </script>

this binding rule 1 - default binding

 <script>
    // "use strict"

    // 定义函数
    // 1.普通的函数被独立的调用 这里的this指向window
    function foo() {
      console.log("foo:", this)
    }
    foo()


    // 2.函数定义在对象中, 但是独立调用
    var obj = {
      name: "why",
      bar: function() {
        console.log("bar:", this)
      }
    }
    // 这里的this指向window
    var baz = obj.bar
    baz()


    // 3.高阶函数 这里的this指向window
    function test(fn) {
      fn()
    }

    test(obj.bar)

    // 4.严格模式下, 独立调用的函数中的this指向的是undefined

  </script>

this binding rule 2 - implicit binding

 <script>
    // 你不知道的JavaScript(上中下)
    // 隐式绑定  这里的this指向obj
    function foo() {
      console.log("foo函数:", this)
    }

    var obj = {
      bar: foo
    }

    obj.bar()

  </script>

this binding rule three-new binding

 <script>

    /*
      1.创建新的空对象
      2.将this指向这个空对象
      3.执行函数体中的代码
      4.没有显示返回非空对象时, 默认返回这个对象
    */
    function foo() {
      this.name = "why"
      console.log("foo函数:", this)
    }

    new foo()

  </script>

this binding rule four - explicit binding

 <script>
    // 显式绑定
    var obj = {
      name: "why"
    }

    function foo() {
      console.log("foo函数:", this)
    }

    // 执行函数, 并且函数中的this指向obj对象
    // obj.foo = foo
    // obj.foo()

    // 执行函数, 并且强制this就是obj对象
    foo.call(obj)
    foo.call(123)
    foo.call("abc")

  </script>

Extra function supplement-apply-call

 <script>

    // call/apply
    function foo(name, age, height) {
      console.log("foo函数被调用:", this)
      console.log("打印参数:", name, age, height)
    }

    // ()调用
    // foo("why", 18, 1.88)

    // apply
    // 第一个参数: 绑定this
    // 第二个参数: 传入额外的实参, 以数组的形式
    // foo.apply("apply", ["kobe", 30, 1.98])

    // call
    // 第一个参数: 绑定this
    // 参数列表: 后续的参数以多参数的形式传递, 会作为实参
    foo.call("call", "james", 25, 2.05)

  </script>

Extra function supplement-bind

 <script>

    function foo(name, age, height, address) {
      console.log("foo:", this)
      console.log("参数:", name, age, height, address)
    }

    var obj = { name: "why" }

    // 需求: 调用foo时, 总是绑定到obj对象身上(不希望obj对象身上有函数)
    // 1.bind函数的基本使用
    // var bar = foo.bind(obj)
    // bar() // this -> obj

    // 2.bind函数的其他参数(了解)
    var bar = foo.bind(obj, "kobe", 18, 1.88)
    bar("james")

  </script>

Built-in function call binding

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  
  <button>按钮</button>

  <script>
    // 内置函数(第三方库): 根据一些经验
    // 1.定时器 这里的this指向window
    // setTimeout(function() {
    //   console.log("定时器函数:", this)
    // }, 1000)

    // 2.按钮的点击监听 这里的this指向button标签
    // var btnEl = document.querySelector("button")
    // btnEl.onclick = function() {
    //   console.log("btn的点击:", this)
    // }

    // btnEl.addEventListener("click", function() {
    //   console.log("btn的点击:", this)
    // })

    // // 3.forEach  这里的this指向aaaa;如果不绑定aaaa的话指向的是names数组对象
    var names = ["abc", "cba", "nba"]
    names.forEach(function(item) {
      console.log("forEach:", this)
    }, "aaaa")

  </script>

</body>
</html>

this binding rule priority

Priority from high to low: 1, new; 2, bind; 3, call/apply; 4, implicit binding; 5, default binding.

<script>

    // function foo() {
    //   console.log("foo:", this)
    // }

    // 比较优先级:

    // 1.显式绑定绑定的优先级高于隐式绑定
    // 1.1.测试一:apply高于默认绑定
    // var obj = { foo: foo }
    // obj.foo.apply("abc")
    // obj.foo.call("abc")

    // 1.2.测试二:bind高于默认绑定
    // var bar = foo.bind("aaa")
    // var obj = {
    //   name: "why",
    //   baz: bar
    // }
    // obj.baz()


    // 2.new绑定优先级高于隐式绑定
    // var obj = {
    //   name: "why",
    //   foo: function() {
    //     console.log("foo:", this)
    //     console.log("foo:", this === obj)
    //   }
    // }
    // new obj.foo()


    // 3.new/显式
    // 3.1. new不可以和apply/call一起使用

    // 3.2. new优先级高于bind
    // function foo() {
    //   console.log("foo:", this)
    // }
    // var bindFn = foo.bind("aaa")
    // new bindFn()


    // 4.bind/apply优先级
    // bind优先级高于apply/call
    function foo() {
      console.log("foo:", this)
    }
    var bindFn = foo.bind("aaa")
    bindFn.call("bbb")

  </script>

Situations outside this binding

In strict mode: If you explicitly bind this, it will directly point to the content you bind, such as null and undefined.

Non-strict mode: if this is explicitly bound, it will be changed to window if it is null or undefined. Strings etc. will be wrapped in an object.

<script>
    // 1.情况一: 显式绑定null/undefined, 那么使用的规则是默认绑定
    // function foo() {
    //   console.log("foo:", this)
    // }
    // 下面三个的this都是指向window,如果是严格模式则显示是abc和null、undefined
    // foo.apply("abc")
    // foo.apply(null)
    // foo.apply(undefined)


    // 2.情况二: 间接函数引用
    var obj1 = {
      name: "obj1",
      foo: function() {
        console.log("foo:", this)
      }
    }
    var obj2 = {
      name: "obj2"
    };

    // {}[]()连续的括号要加分号,否则浏览器不能识别

    // obj2.foo = obj1.foo
    // obj2.foo()
    // 下面这行代码的this指向window
    (obj2.foo = obj1.foo)()

  </script>

Use of arrow functions

Note that the arrow function does not bind this and arguments;

and cannot be used with new

Basic usage:

<script>

    // 1.之前的方式
    function foo1() {}
    var foo2 = function(name, age) {
      console.log("函数体代码", this, arguments)
      console.log(name, age)
    }

    // 2.箭头函数完整写法
    var foo3 = (name, age) => {
      console.log("箭头函数的函数体")
      console.log(name, age)
    }

    // 3.箭头函数的练习
    // 3.1. forEach
    var names = ["abc", "cba", "nba"]
    names.forEach((item, index, arr) => {
      console.log(item, index, arr)
    })
    // 3.2. setTimeout
    setTimeout(() => {
      console.log("setTimeout")
    }, 3000)


  </script>

Abbreviation for arrow function

A single parameter can be omitted ()

A line of execution body can omit {}

If a line of execution returns an object type, you need to add a layer () outside the {} of the object

 <script>

    var names = ["abc", "cba", "nba"]
    var nums = [20, 30, 11, 15, 111]

    // 1.优化一: 如果箭头函数只有一个参数, 那么()可以省略
    // names.forEach(item => {
    //   console.log(item)
    // })
    // var newNums = nums.filter(item => {
    //   return item % 2 === 0
    // })

    // 2.优化二: 如果函数体中只有一行执行代码, 那么{}可以省略
    // names.forEach(item => console.log(item))

    // 一行代码中不能带return关键字, 如果省略, 需要带return一起省略(下一条规则)
    // var newNums = nums.filter(item => {
    //   return item % 2 === 0
    // })

    // 3.优化三: 只有一行代码时, 这行代码的表达式结果会作为函数的返回值默认返回的
    // var newNums = nums.filter(item => item % 2 === 0)
    // var newNums = nums.filter(item => item % 2 === 0)


    // 4.优化四: 如果默认返回值是一个对象, 那么这个对象必须加()
    // 注意: 在react中我会经常使用 redux

    // var arrFn = () => ["abc", "cba"]
    // var arrFn = () => {} // 注意: 这里是{}执行体
    // var arrFn = () => ({ name: "why" })
    // console.log(arrFn())

    // 箭头函数实现nums的所有偶数平方的和
    var nums = [20, 30, 11, 15, 111]
    var result = nums.filter(item => item % 2 === 0)
                     .map(item => item * item)
                     .reduce((prevValue, item) => prevValue + item)
    console.log(result)

  </script>

Use of this in arrow functions

Since the arrow function itself does not have this, the this in the arrow function will point to this in the scope of the outer layer of the arrow function. If the outer layer is also an arrow function, it will continue to look outward for the scope. The { } curly braces of the object type are not scoped, so this skips directly when looking for this.

Arrow functions using explicit binding this are also useless.

The search order of this and parameters of an arrow function is very similar.

<script>

    // 1.普通函数中是有this的标识符
    // function foo() {
    //   console.log("foo", this)
    // }

    // foo()
    // foo.apply("aaa")

    // 2.箭头函数中, 压根没有this
    // var bar = () => {
    //   console.log("bar:", this)
    // }
    // bar()
    // 通过apply调用时, 也是没有this
    // bar.apply("aaaa")

    // console.log("全局this:", this)
    // var message = "global message"

    // 3.this的查找规则
    // var obj = {
    //   name: "obj",
    //   foo: () => {
    //     var bar = () => {
    //       console.log("bar:", this)
    //     }
    //     return bar
        
    //   }
    // }
    // var fn = obj.foo()
    // fn.apply("bbb")

    

  </script>

This application in arrow function

 <script>

    // 网络请求的工具函数
    function request(url, callbackFn) {
      var results = ["abc", "cba", "nba"]
      callbackFn(results)
    }

    // 实际操作的位置(业务)
    var obj = {
      names: [],
      network: function() {
        // 1.早期的时候
        // var _this = this
        // request("/names", function(res) {
        //   _this.names = [].concat(res)
        // })

        // 2.箭头函数写法
        request("/names", (res) => {
          this.names = [].concat(res)
        })
      }
    }

    obj.network() //影式绑定了obj对象
    console.log(obj)

  </script>

var name = "window";

var person = {
  name: "person",
  sayName: function () {
    console.log(this.name);
  }
};

function sayName() {
  var sss = person.sayName;

  sss(); // 绑定: 默认绑定, window -> window

  person.sayName(); // 绑定: 隐式绑定, person -> person

  (person.sayName)(); // 绑定: 隐式绑定, person -> person

  (b = person.sayName)(); // 术语: 间接函数引用, window -> window
}

sayName();

var name = 'window'


// {} -> 对象
// {} -> 代码块
var person1 = {
  name: 'person1',
  foo1: function () {
    console.log(this.name)
  },
  foo2: () => console.log(this.name),
  foo3: function () {
    return function () {
      console.log(this.name)
    }
  },
  foo4: function () {
    // console.log(this) // 第一个表达式this -> person1
    // console.log(this) // 第二个表达式this -> person2
    // console.log(this) // 第三个表达式this -> person1
    
    return () => {
      console.log(this.name)
    }
  }
}

var person2 = { name: 'person2' }


// 开始题目:
person1.foo1(); // 隐式绑定: person1
person1.foo1.call(person2); // 显式绑定: person2

person1.foo2(); // 上层作用域: window
person1.foo2.call(person2); // 上层作用域: window

person1.foo3()(); // 默认绑定: window
person1.foo3.call(person2)(); // 默认绑定: window
person1.foo3().call(person2); // 显式绑定: person2

person1.foo4()(); // person1
person1.foo4.call(person2)(); // person2
person1.foo4().call(person2); // person1

 

var name = 'window'

/*
  1.创建一个空的对象
  2.将这个空的对象赋值给this
  3.执行函数体中代码
  4.将这个新的对象默认返回
*/
function Person(name) {
  this.name = name
  this.foo1 = function () {
    console.log(this.name)
  },
  this.foo2 = () => console.log(this.name),
  this.foo3 = function () {
    return function () {
      console.log(this.name)
    }
  },
  this.foo4 = function () {
    return () => {
      console.log(this.name)
    }
  }
}

// person1/person都是对象(实例instance)
var person1 = new Person('person1')
var person2 = new Person('person2')


// 面试题目:
person1.foo1() // 隐式绑定: person1
person1.foo1.call(person2) // 显式绑定: person2

person1.foo2() // 上层作用域查找: person1
person1.foo2.call(person2) // 上层作用域查找: person1

person1.foo3()() // 默认绑定: window
person1.foo3.call(person2)() // 默认绑定: window
person1.foo3().call(person2) // 显式绑定: person2

person1.foo4()() // 上层作用域查找: person1(隐式绑定)
person1.foo4.call(person2)() //  上层作用域查找: person2(显式绑定)
person1.foo4().call(person2) // 上层作用域查找: person1(隐式绑定)

Because this function is in the form of a constructor, what is new is an object type, similar to the key and value in an object.   

{

        name:'person1',

        foo1: the memory address of the function

}

 

var name = 'window'

/*
  1.创建一个空的对象
  2.将这个空的对象赋值给this
  3.执行函数体中代码
  4.将这个新的对象默认返回
*/
function Person(name) {
  this.name = name
  this.obj = {
    name: 'obj',
    foo1: function () {
      return function () {
        console.log(this.name)
      }
    },
    foo2: function () {
      return () => {
        console.log(this.name)
      }
    }
  }
}

var person1 = new Person('person1')
var person2 = new Person('person2')

person1.obj.foo1()() // 默认绑定: window
person1.obj.foo1.call(person2)() // 默认绑定: window
person1.obj.foo1().call(person2) // 显式绑定: person2

person1.obj.foo2()() // 上层作用域查找: obj(隐式绑定)
person1.obj.foo2.call(person2)() // 上层作用域查找: person2(显式绑定)
person1.obj.foo2().call(person2) // 上层作用域查找: obj(隐式绑定)

Guess you like

Origin blog.csdn.net/weixin_56663198/article/details/131121066