this的那些事

this用法

全局上下文

无论是否在严格模式下,在全局执行环境中(在任何函数体外部)this 都指向全局对象。

// 在浏览器中, window 对象同时也是全局对象:
console.log(this === window); // true

a = 37;
console.log(window.a); // 37

this.b = "MDN";
console.log(window.b)  // "MDN"
console.log(b)         // "MDN"


函数上下文

在函数内部,this的值取决于函数被调用的方式。

因为下面的代码不在严格模式下,且 this 的值不是由该调用设置的,所以 this 的值默认指向全局对象,浏览器中就是 window。

function f1(){
  return this;
}
//在浏览器中:
f1() === window;   //在浏览器中,全局对象是window

//在Node中:
f1() === globalThis;
function f2(){
  "use strict"; // 这里是严格模式
  return this;
}

f2() === undefined; // true

在第二个例子中,this 应是 undefined,因为 f2 是被直接调用的,而不是作为对象的属性或方法调用的(如 window.f2())。有一些浏览器最初在支持严格模式时没有正确实现这个功能,于是它们错误地返回了window对象。

类上下文

this 在 类 中的表现与在函数中类似,因为类本质上也是函数,但也有一些区别和注意事项。
在类的构造函数中,this 是一个常规对象。类中所有非静态的方法都会被添加到 this 的原型中:
class Example {
  constructor() {
    console.log("Example--this", this)
    const proto = Object.getPrototypeOf(this);
    console.log(Object.getOwnPropertyNames(proto));
  }
  first(){}
  second(){}
  static third(){}
}

new Example(); // ['constructor', 'first', 'second']
// 注意:静态方法不是 this 的属性,它们只是类自身的属性。
// 对象可以作为 bind 或 apply 的第一个参数传递,并且该参数将绑定到该对象。
var obj = {a: 'Custom'};

// 声明一个变量,并将该变量作为全局对象 window 的属性。
var a = 'Global';

function whatsThis() {
  return this.a;  // this 的值取决于函数被调用的方式
}

whatsThis();          // 'Global' 因为在这个函数中 this 没有被设定,所以它默认为 全局/ window 对象
whatsThis.call(obj);  // 'Custom' 因为函数中的 this 被设置为obj
whatsThis.apply(obj); // 'Custom' 因为函数中的 this 被设置为obj

显示的改变的指向 call、apply、bind方法

this 和对象转换

function add(c, d) {
  return this.a + this.b + c + d;
}

var o = {a: 1, b: 3};

// 第一个参数是用作“this”的对象
// 其余参数用作函数的参数
add.call(o, 5, 7); // 16

// 第一个参数是用作“this”的对象
// 第二个参数是一个数组,数组中的两个成员用作函数参数
add.apply(o, [10, 20]); // 34

在非严格模式下使用 call 和 apply 时,如果用作 this 的值不是对象,则会被尝试转换为对象。null 和 undefined 被转换为全局对象。原始值如 7 或 'foo' 会使用相应构造函数转换为对象。因此 7 会被转换为 new Number(7) 生成的对象,字符串 'foo' 会转换为 new String('foo') 生成的对象。

function bar() {
  console.log(Object.prototype.toString.call(this));
}

bar.call(7);     // [object Number]
bar.call('foo'); // [object String]
bar.call(undefined); // [object global]

bind方法(返回的一个函数)

ECMAScript 5 引入了 Function.prototype.bind()。调用f.bind(someObject)会创建一个与f具有相同函数体和作用域的函数,但是在这个新函数中,this将永久地被绑定到了bind的第一个参数,无论这个函数是如何被调用的。

function f(){
  return this.a;
}

var g = f.bind({a:"azerty"});
console.log(g()); // azerty

var h = g.bind({a:'yoo'}); // bind只生效一次!
console.log(h()); // azerty

var o = {a:37, f:f, g:g, h:h};
console.log(o.a, o.f(), o.g(), o.h()); // 37, 37, azerty, azerty

 隐式改变this指向

function A(name){
  
  this.name=name
  console.log('A-->', this)
}

let a1 =new A('lucy')
console.log('a1', a1.name, a1.__proto__, a1.__proto__==A.prototype)

 

可以看到实例a1.  this指向构造函数

一般谁调用this指向谁,对象调用指向对象,函数调用指向函数,如果函数有返回值返回值不是对象类型,this还是指向函数的实例

箭头函数比较特殊

箭头函数在箭头函数中,this与封闭词法环境的this保持一致。在全局代码中,它将被设置为全局对象:

var globalObject = this;
var foo = (() => this);
console.log(foo() === globalObject); // true

注意:如果将this传递给call、bind、或者apply来调用箭头函数,它将被忽略。不过你仍然可以为调用添加参数,不过第一个参数(thisArg)应该设置为null。

// 接着上面的代码
// 作为对象的一个方法调用
var obj = {foo: foo};
console.log(obj.foo() === globalObject); // true

// 尝试使用call来设定this
console.log(foo.call(obj) === globalObject); // true

// 尝试使用bind来设定this
foo = foo.bind(obj);
console.log(foo() === globalObject); // true

 来几个例子

let name="globalname"
const obj = {
  name: 'lily',
  age: ()=>{
    console.log("obj-age", this, '--', this.name, '--name--',name)
    function demo(){
      console.log("obj-demo", this, '--',this.name, '--name--',name)
    }
    demo()
    
  },
  bar: function() {
    console.log('obj--bar>', this, '--',this.name)
    const x = (() =>  this.name);
    console.log('obj--x>', this, '--', x())
    
  }
};
obj.age()
obj.bar()

在来几个例子

function fn1()
{
    this.name = 'hello1';
    return {};
}
var a = new fn1();
console.log(a.name); //undefined

function fn2()  
{  
    this.age = 18;  
    return function(){};
}
var a = new fn2();  
console.log(a.age); //undefined

function fn3()
{
  this.name = 'hello3';
    return 1;
}
var a = new fn3;
console.log(a.name); //hello3

obj={
  name: 'hi',
  fn: function(){
    setTimeout(() => {
      console.log(this, this.name)
    }, 200);
  }
}
obj.fn()

待更新

posted @ 2021-07-27 17:59  pikachuWorld  阅读(36)  评论(0编辑  收藏  举报