JavaScript 带你理解this关键字

前言 本篇文章将讲到之前new原理中的为讲到的call()方法

为什么要有this ?

  • this 提供了一种更优雅的方式来隐式的传递一个对象的引用,可以让代码更加简洁利于复用
js 复制代码
//需要给speek和identify显示传入一个上下文对象
function identfy(context) {
  return context.name.toUpperCase(); //英文大写
}
function speak(context) {
  var greeting = "hello ,I'm " + identfy(context) + ",I hate Trump!";
  console.log(greeting);
}

var me = {
  name: "",
};
speak(me);



function identfy1() {
  return this.name.toUpperCase(); // toUpperCase(); //英文大写
}
function speak1() {
  var greeting = "hello ,I'm " + identfy1.call(this) + ",I love China!";
  console.log(greeting);
}

var me1 = {
  name: "Donald Trump",
};
speak1.call(me1); //调用的时候

this可以使用在哪里?

  • 函数作用域:
  • 全局作用域:默认this指向的是window
  • 块级作用域?不不没有它,只有上面两个,为什么?
js 复制代码
//块级
{
  let a = this;
  console.log(a);
}

来,你看这段代码,块级作用域是指let的变量和{}一起是块级,那么这this就不是在块级里面了,实则是在全局window上哦

  • this是一个代词,它代指一个对象

this的绑定规则

1.默认绑定---当函数 被独立调用时 ,函数的this默认指向到window

(即使this是在函数体里的,但是被独立调用,仍然会指向全局的window)

js 复制代码
// 代指:
var a = 1; //挂在window
function foo() {
  console.log(this.a);//this是在foo里面的,但它指向的是window
}
function Bar() {
  var a = 2;
  foo();//独立调用
}
Bar();

要在浏览器上才能看到挂在windowd的上的a,编译器上运行node结果是undefined,所以后续要用到window全局的,代码都在浏览器上执行

独立调用是什么?没有其他前缀的调用

js 复制代码
var obj = { a: 1 ,
  foo: function () {
    console.log(this);
  }//不是独立调用
};
obj.foo();

这段代码就不是独立调用 有obj去调用它

在来看下面这段代码: 同理因为是独立调用触发的是默认绑定,绑定在window,全局上,所以this是函数作用域外面的全局作用域

2.隐式绑定---当函数引用有上下文对象且被该对象调用时,隐式绑定规则会把函数调用中的this绑定到这个上下文对象

什么是函数引用 是指foo()不带() 的 foo

js 复制代码
var a = 1;
function foo() {
  console.log(this.a);
}


var obj = {
  a: 2,
  foo: function () {
    console.log(this.a);
  }, 
};
obj.foo();



var obj = {
  a: 2,
  foo: foo, //foo引用 来找找到函数
};
obj.foo();



var obj = {
  a: 2,
  foo: foo(),
};
obj.foo(); //报错
obj.foo

第一个obj与第二个obj是等同的,单写foo是指引用,v8执行时会去找foo变量或者函数,这里没有变量就会找到函数foo

第三种写法是错误的,foo()加了括号这里就是调用函数,而这里的函数没有返回值,这里的值就是undefin,那么foo:undefined,而后在对象外面调用的话,obj.foo(),是调用名为foo的函数,但这里foo:undefined值是undefined不是函数体,所以会报错,如果是obj.foo的话是指对象的一个属性,属性名为foo,并且这里没有做任何操作,也不会报错。

3.隐式丢失---当一个函数被多层对象调用时,函数的this会指向最近的那一层对象

js 复制代码
var a = 1;
function foo() {
  console.log(this.a);
}


var obj = {
  a: 2,
  foo: foo, //foo引用
};

var obj2 = {
  a: 3,
  obj:obj
   
};
obj2.obj.foo();

函数的this会指向最近的那一层对象即obj而不是obj2

4.显示绑定

1.fn.call(obj,x,y,....)显示的将fn里面的this绑定到obj对象上,并且call帮fn接收参数

js 复制代码
function foo(x,y){
  console.log(this.a,x+y);

}
var obj={
  a:2
}
foo.call(obj,1,2)//显示绑定
foo.call(1,1,2)//如果第一个参数不是对象,默认给一个null
foo.call(null,1,2)//显示绑定

call方法是定义在Funtion.prototype上的foo.prototype.__proto__===Function.prototype call将this指向obj ,并且帮忙接收foo参数和调用foo函数

2.fn.apply(obj,[x,y,....])显示的将fn里面的this绑定到obj对象上,并且apply帮fn接收参数,参数必须以数 组的形式盛放

js 复制代码
foo.apply(obj,[1,2])//区别

3.fn.bind(obj,x,y,....)(x,x, ....)显示的将fn里面的this绑定到obj对象上,并且bind会返回一个新的函数,bind和新函数都可以负责帮fn接收参数,参数零散的传入

js 复制代码
const bar=foo.bind(obj,1,2)//
bar()
const bar1=foo.bind(obj)
bar1(1,2)
const bar3=foo.bind(obj,2,4)
bar3(1)

bind会返回一个新的函数体,但是我们要自己触发这个函数,才能接着触发foo的函数

5.new绑定 --new 的原理会导致函数的this绑定到实例对象上

js 复制代码
function Person() {
  //var obj = {};
  //Person.call(obj);
  this.name = "特朗普";
  this.age = 18;
  console.log(this);
  //obj.__proto__ = Person.prototype;
  //return obj;
}
const p1 = new Person();

因为new的过程使用了call()方法将将Person的this指向obj,最后将obj返回给实例对象,即即把Person的this绑定到了实例对象上

箭头函数

箭头函数中没有this这个概念,写在了箭头函数的中的this,也是它外层那个非箭头函数的this

js 复制代码
function a() {
  console.log(this);
  let b = function () {
    let c = () => {
      let d = () => {
        console.log(this);//箭头函数里面没有this这个关键字
      };
      d();
    };
    c();
  };
  b();
}
a();

这的this是在fuction a(){} 里面的,但不指向funtion a(){},因为默认绑定规则,所以是指向window的

js 复制代码
var a = 1
var obj = {
  a: 2,
  bar: function() {
    const baz = () => {
      console.log(this.a);
    }
    baz()
  }
}
obj.bar()

如有错误欢迎指正,欢迎各位友友评论点赞!

相关推荐
Lupino8 分钟前
被 React “玩弄”的 24 小时:为了修一个不存在的 Bug,我给大模型送了顿火锅钱
前端·react.js
米丘14 分钟前
了解 Javascript 模块化,更好地掌握 Vite 、Webpack、Rollup 等打包工具
前端
Heo16 分钟前
深入 React19 Diff 算法
前端·javascript·面试
滕青山17 分钟前
个人所得税计算器 在线工具核心JS实现
前端·javascript·vue.js
小怪点点18 分钟前
手写promise
前端·promise
国思RDIF框架26 分钟前
RDIFramework.NET Web 敏捷开发框架 V6.3 发布 (.NET8+、Framework 双引擎)
前端
Mintopia28 分钟前
如何在有限的时间里,活出几倍的人生
前端
炫饭第一名28 分钟前
速通Canvas指北🦮——变形、渐变与阴影篇
前端·javascript·程序员
Neptune129 分钟前
让我带你迅速吃透React组件通信:从入门到精通(上篇)
前端·javascript
阿懂在掘金30 分钟前
Vue 表单避坑(一):为什么 v-model 绑定对象属性会偷偷修改父组件数据?
前端·vue.js