this|this 指针详解

this 指针详解 概念 this 是当前函数/当前模块的运行环境上下文。是一个指针型变量,普通函数中的 this 是在调用时才被绑定确认指向的。
通过不同的 this 调用同一个函数,可以产生不同的结果。
到底如何确认 this 绑定的内容是什么?
this 绑定的规则 1.默认绑定

function a() {} a();

函数独立调用的时候,不带任何修饰的函数引用.
  • 非严格模式下 this 指向全局对象
var a = 'hello'; var obj = { a: 'world', foo: function () { console.log(this.a); }, }; let bar = obj.foo; bar(); // hello 在调用的时候是直接调用的。所以是指向全局的this // obj.foo(); // world

  • 严格模式下,this 指向 undefined,严格模式下,不允许指向全局对象。
var a = 'hello'; var obj = { a: 'world', foo: function () { 'use strict'; console.log(this.a); }, }; let bar = obj.foo; bar(); // 会报错因为this是指向的undefined

  • 普通函数作为参数传递的情况,setTimeOut,setInterval, 非严格模式下 this 指向全局对象。
var name = 'hello'; var person = { name: 'world', sayHi: sayHi, }; function sayHi() { console.log(this); // person setTimeout(function () { // 指向了全局对象 console.log(this.name); // hello }); }person.sayHi();

2.隐式绑定
【this|this 指针详解】与默认绑定相反,函数调用的时候有显式的修饰,
var a = 'hello'; var obj = { a: 'world', foo: function () { console.log(this.a); }, }; // 谁调用 这个函数(foo)谁就是这个函数的this obj.foo();

  • 在链式调用的情况下,this 就近指向
function sayHi() { console.log(this.name); }var person1 = { name: 'hello', sayHi: sayHi, }; var person2 = { name: 'world', friend: person1, }; // 链式调用的时候是就近指向 person2.friend.sayHi();

显式绑定
call apply bind 可以修改函数的 this 指向
call 和 apply 的异同
  • 都是改变 this 指向,然后执行原有函数
  • 第一个参数都是作为 this 的,绑定到函数体的 this 上,如果不传参数 fun.cal() , 非严格模式下,this 会绑定到全局对象
func.call(this, arg1, arg2, ..., argn); func.apply(this, [arg1, ..., argn]) // 只有object tostring 可以返回类型 Object.prototype.toString.call(obj) === '[object Array]'

  • 如果 call 的第一个参数,传了数字或者字符串等基本类型 会发生什么?
    得到字符串的对象,数字的对象 [Number: 1] [String: 'lubai'] 等
bind bind 方法,会创建一个新的函数,
当这个新函数被调用的时候,bind 的第一个参数会作为函数运行时的 this,之后的一系列参数都会在传递实参前传入作为它的函数.
var account = { name: 'hello', author: 'world', subscribe: function (subsc) { console.log(`${subsc} ${this.name}`); }, }; account.subscribe('微言'); // 微言 hello var subsc1 = account.subscribe.bind({ name: 'name', author: 'author' }, 'subsc'); subsc1(); // subsc name (显式绑定的优先级,比隐式绑定的优先级高)

new
  1. 创建一个空对象
  2. 将空对象的\_\_proto\_\_指向原型对象的 prototype
  3. 以新对象为 this 执行原有的构造函数
  4. return
function Study(name) { this.name = name; }var study = new Study('hello'); console.log(study.name);

5. this 绑定的优先级
new 绑定 > 显式(bind, call, apply)绑定 > 隐式绑定(obj.foo()) > 默认绑定(foo())
// 显式绑定的优先级,比隐式绑定高 function foo(a) { // console.log(this.a); this.a = a; }var obj1 = { a: 2, foo: foo, }; var obj2 = { a: 3, foo: foo, }; // 隐式绑定 obj1.foo(); // 2 obj2.foo(); //3// 将this的指向进行强行更改 obj1.foo.call(obj2); // 3 obj2.foo.call(obj1); // 2

function foo(a) { // console.log(this.a); this.a = a; } var obj1 = { foo: foo, }; var obj2 = {}; obj1.foo(2); console.log(obj1.a); // 2// 强行把foo的参数指向了obj2上 obj1.foo.call(obj2, 3); console.log(obj2.a); // 3// new 将obj1指向bar 相当于 bar.a = a, 并不会改变obj1这个对象 var bar = new obj1.foo(4); console.log(obj1.a); // 2 console.log(bar.a); // 4

function foo(a) { this.a = a; } var obj1 = {}; // bind 执行的this改变成obj1 var bar = foo.bind(obj1); bar(2); console.log(obj1.a); // 2var barNew = new bar(3); // new的过程中,以新对象为this运行原来的构造函数 function foo(a) {this.a = a} // 新对象是 barNewconsole.log(obj1.a); // 2console.log(barNew.a); // 3

箭头函数
  1. 箭头函数没有arguments
  2. 箭头函数没有构造函数 (本身没有constructor)
  3. 没有自己的this (this的指向是由定义箭头函数的位置决定的,而普通函数是调用的时候才确定的)
题目练习
  1. 题目1
    var a = 123; function getA() { console.log(this.a) // undefined }getA()

var a = 123; var obj = { a: 456, getA: function() {// console.log(this)这里的this指向obj function getAA() { // 里面有独立的this console.log(this.a) // undefined } getAA() // 默认绑定 } } obj.getA() // undefined

  1. 题目2
    var length = 10; function fn() { console.log(this.length) } var obj = { length: 5, method: function(fn) { // this = obj // fn 是一个参数,以函数为参数的 this 指向全局。 fn(); 10// arguments{0:fn, 1: 1, length:2} 相当于隐式绑定绑定到了fn对象上 arguments[0]() } } obj.method(fn, 1)

    推荐阅读