乐趣区

关于javascript: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. 隐式绑定

与默认绑定相同,函数调用的时候有显式的润饰,

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); // 2

var barNew = new bar(3);
// new 的过程中,以新对象为 this 运行原来的构造函数 function foo(a) {this.a = a}
// 新对象是 barNew

console.log(obj1.a); // 2

console.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)
退出移动版