深刻JavaScript系列02--this关键字

“You know nothing Jon Snow”web

this关键字

“你不知道的JavaScript学习笔记02”app

概念

  • 定义:当一个函数被调用时,会建立一个执行上下文。这个执行上下文会包含函数在哪里被调用(调用栈)、函数的调用方式、传入的参数等信息。this就是这个记录的一个属性,会在函数执行的过程当中用到
  • 因此能够明确一点:this既不指向函数自身也不指向函数的词法做用域,this指代的是当前函数被调用时的执行上下文
  • this其实是在函数被调用时发生的绑定,它指向什么彻底取决于函数在哪里被调用

绑定规则

默认绑定

  • 独立函数调用,this默认绑定全局对象(在严格模式下默认绑定不会指定上下文对象)
function foo() {
 console.log(this.a)  }  var a = "fuck";  foo();//fuck 复制代码

隐式绑定

  • 当函数做为对象的属性被调用时,会触发隐式绑定
var obj1 = {
 a:1,  foo:function() {  console.log(this.a);  }  }  var obj2 = {  b:2,  bar:function() {  consolelog(this.b);  }  }   obj1.foo();//1  obj2.bar();//2 复制代码
  • 当函数引用有上下文对象时,隐式绑定规则会把函数调用中的this绑定到这个上下文对象。
  • 注意:对象属性引用链中只有上一层或者说最后一层在调用位置中起做用。
function foo() {
 console.log(this.a);  }   var obj1 = {  a:1,  foo:foo  }   var obj2 = {  a:2,  obj1  }   var obj3 = {  a:3,  obj2  }   obj3.obj2.obj1.foo(); //1; 复制代码

隐式丢失

var obj1 = {
 a:1,  foo:function() {  console.log(this.a);  }  }  var a = "shit";   var bar = obj1.foo;  bar(); //shit  复制代码

在js中,函数属于Object的之类,在这块代码块中的RHS其实是传递函数的引用,而this是由调用宿主和执行上下文决定的,函数执行时执行的是默认绑定的规则编辑器

显式绑定

  • 概念:直接指定函数执行时的上下文对象
  • 内置函数(对象)Function上的三个方法:call()、apply()、bind()
var obj1 = {
 a:1  }  function foo() {  console.log(this.a);  }  var a = 2;  foo.call(obj1); // 1  foo.apply(obj1); //1  var bar = foo.bind(obj1);  bar(); //1 复制代码

new声明绑定

  • new关键字函数

    avaScript中的“构造函数”有别于其余语言,在JavaScript中,在函数调用前用new关键字进行声明,该函数就成了“构造函数”,函数自己并没有区别。 使用new来调用函数,或者说发生构造函数调用时,会自动执行下面的操做。1.建立(或者说构造)一个全新的对象。2.这个新对象会被执行[[Prototype]]链接。3.这个新对象会绑定到函数调用的this。4.若是函数没有返回其余对象,那么new表达式中的函数调用会自动返回这个新对象。学习

//eg
function myNew() {   // 第一个参数是构造函数  var Constructor = [].shift.call(arguments);   // 建立一个继承对象  var obj = Object.create(Constructor.prototype);   // 执行构造函数,this执行obj  var result = Constructor.apply(obj, arguments);   // 构造函数返回是对象,优先使用返回的对象,不然是obj  return result instanceof Object ? result : obj;   // 执行构造函数,this执行obj  var result = Constructor.apply(obj, arguments);   // 构造函数返回是对象,优先使用返回的对象,不然是obj  return result instanceof Object ? result : obj; }  var a = 'fuck';  function foo(a) {  this.a = a;  this.saya = function() {  console.log(this.a)  } } var b = "shit"; var obj = myNew(foo,b); // new foo(b) obj.saya; //shit; 复制代码

使用new来调用foo(..)时,咱们会构造一个新对象并把它绑定到foo(..)调用中的this上。new是最后一种能够影响函数调用时this绑定行为的方法,咱们称之为new绑定。ui

优先级

new绑定 > 显式绑定 >隐式绑定 >默认绑定this

能够按照下面的顺序来进行判断:url

1.函数是否在new中调用(new绑定)?spa

若是是的话this绑定的是新建立的对象。prototype

var obj = new foo(); //绑定obj
复制代码

2.函数是否经过call、apply(显式绑定)或者硬绑定调用?

若是是的话,this绑定的是指定的对象。

var bar = new foo.call(obj); //绑定obj
复制代码

3.函数是否在某个上下文对象中调用(隐式绑定)?

若是是的话,this绑定的是那个上下文对象。

var bar = obj.foo(); //绑定obj
复制代码

4.若是都不是的话,使用默认绑定。若是在严格模式下,就绑定到undefined,不然绑定到全局对象。

this
this

箭头函数

箭头函数并非使用function关键字定义的,而是使用被称为“胖箭头”的操做符=>定义的。箭头函数不使用this的四种标准规则,而是根据外层(函数或者全局)做用域来决定this。

function foo() {
 return (a) => {  console.log(this.a)  } } var obj1 = {  a:1 } var obj2 = {  a:2 }  var bar = foo.call(obj1); bar.call(obj2); //1,不是2 复制代码

foo内部的箭头函数会捕获调用foo时的this;箭头函数的this查询规则听从词法;外层函数绑定的this会间接传递给内部的箭头函数,箭头函数的绑定没法被修改。

function foo() {
 var _this = this;  setTimeout(function(){  console.log(_this.a)  },100) } function bar() {  setTimeout(()=>{  console.log(this.a)  },100) } function baz() {  setTimeout(function(){  console.log(this.a)  },100) } var obj = {  a: 1 } var a = 2; foo.call(obj); //1 bar.call(obj); //1 baz.call(obj); //2, 天惹,回调函数的this执行了默认绑定  复制代码

参考文献: 《你不知道的JavaScript(上卷)》

本文使用 mdnice 排版

相关文章
相关标签/搜索