资讯专栏INFORMATION COLUMN

javascript的this简单记忆

Hujiawei / 2865人阅读

摘要:一直感觉中的是一个大坑,虽然一直都有注意,一直都有研究,但是总是会忘记。即使也没有权利改变。但是可以影响后面的参数值。由于只是我根据经验和资料自己总结的,所以不知道是否有疏忽或者遗漏,如果有问题的地方,欢迎提出。

一直感觉javascript中的this是一个大坑,虽然一直都有注意,一直都有研究,但是总是会忘记。在这里,总结一下一些简单的规律

不考虑箭头函数的情况下

下面的所有的都是不考虑箭头函数的情况下,因为箭头函数和普通的差别很大

直接调用的都是window

除非是bind绑定过的,其他情况下,直接调用的方法的this都是window。所谓的直接调用,就是直接以method()的形式调用,没有call, apply, new

看几种情况:

function foo(){
   return this;
}
foo(); // window
var obj = {
  foo: function(){ return this; }
}

var foo = obj.foo;
foo(); // window
function Foo(){
  this.foo = function(){
    console.log(this);
  }

  var foo = this.foo;
  foo(); // window
}

new Foo();
谁调用,谁是this

除非是bind绑定过的,一般情况下,谁调用这个方法,那么内部的this就指向这个对象。也就是说obj.method(),那么就指向objobj.foo.method(),那么就指向obj.foo

看几个例子:

var obj = {
  foo: function(){ return this; }
}
obj.foo(); // obj调用,所以结果是obj
function foo(){ return this };
var obj = {};
obj.foo = foo;
obj.foo(); // obj调用,所以结果是obj
var obj = {
  bar: function(){ return this; },
  foo: function(){
    return this.bar();
  }
}
obj.foo(); // 在foo中, this是obj, 而this调用的bar, 所以返回的是obj
var obj = {
   bar: {
     foo: function(){ return this }
   }
}
obj.bar.foo(); // obj.bar调用的foo,所以返回的结果是bar
function foo(){
  this.bar = function(){ return this }
  return this.bar();
}
foo(); // 由于foo中的this是window, 所以this.bar()返回的是window
function Foo(){
  this.foo = function(){ console.log(this); }
  this.foo();
}
var object = new Foo(); // 由于this.foo中的this是object,所以this是object
new会生成一个新的this

所有情况下,(箭头函数不能使用new关键字),使用了new以后,会把内部的this指向新生成的对象。

除去bind的情况下prototype中的this也指向新生成的对象

function Foo(){
  console.log(this); // this指向新生成的对象,object
}
var object = new Foo(); 
function Foo(){
  this.foo = function(){ return this === object; }
}
var object = new Foo();
object.foo(); // 输出true
function Foo(){}
Foo.prototype.foo = function(){ return this === object; }
var object = new Foo();
object.foo(); // 输出true
call, apply是谁,this就是谁

除非是bind的情况call, apply是谁,那么内部的this就是谁。

注意:如果是基本类型,那么javascript会把基本类型转换成Object的形式

也是看例子:

function foo(){ return this; }
foo.call("a"); // String
typeof foo.call("a"); // object
var obj = {
  foo : function(){ return this; }
}
obj.foo.call(1); // Number
typeof obj.foo.call(1); // object
function Foo(){
  this.foo = function(){ return this; }
}
var object = new Foo();
object.foo.call(1); // Number
bind是谁,this就是谁

除了new这一种特殊情况bind的对象是谁,那么this也就是谁。即使call, apply也没有权利改变。

注意:如果是基本类型,那么javascript会把基本类型转换成Object的形式

function foo() { return this; } 
foo = foo.bind(1);
foo(); // Number
typeof foo(); // object
function foo() { return this; } 
foo = foo.bind(1);
foo.call("a"); // Number 1
function Foo() { return this; } 
Foo.prototype.foo = (function(){ return this; }).bind(1);
var object = new Foo();
object.foo(); // Number

特殊情况
new这个关键词可以改变方法内部的this,使他指向新生成的对象

function Foo(){ this.foo = function(){ console.log(this === obj) } }
Foo = Foo.bind(1);
var obj = new Foo();
obj.foo(); // 输入true
箭头函数

箭头函数的"this"是根据定义环境的this来定的,也就是说定义的函数周围的this是什么,它的"this"就是什么。(注意我在this上加了引号,是因为这个this并不是真的箭头函数的this

而且不会被bind, call, apply所改变

var foo = ()=>{ return this };
foo() // window
var obj = { foo: ()=>this }
obj.foo(); // 由于定义的时候,周围的环境是window,所以返回window
var obj = {
  foo(){
     var bar= ()=>{ return this };
     return bar();
  }
}
obj.foo(); // 由于定义bar的时候,周围环境是obj,所以返回obj
var foo = obj.foo;
foo(); // 同理,这里是window
var foo = ()=>{ return this };
foo = foo.bind(1);
foo(); // window
foo.call(1); // window
foo.apply(1); // window
function Foo(){
  // 箭头函数
  var a = ()=>{
    console.log(this === object); // true
  }

  // 对比普通函数
  var b = function(){
    console.log(this === window); // true
  }
  
  this.foo = function(){
    a(); b();
  }
}

var object = new Foo();
object.foo();
function Foo(){}
// window
Foo.prototype.foo = ()=>{ return this }
// window
var object = new Foo();
object.foo(); // 由于定义foo的时候,周围环境是window,所以这里是window
小结

之前在上面写的都是记忆方法,方便记忆,但是并没有涉及到原理,这里大概点几点:

bind以后,即使再bind, apply, call也不会改变this的值

其实可以从bind的简单实现看出来:

Function.prototype.bind = Function.prototype.bind || function(context, ...args){
  var func = this;
  return function(...currentArgs){
    return func.apply(context, args.concat(currentArgs));
  }
}

所以,从这里看出来,bind以后,返回了一个新的function,所以即使以后再对返回的方法进行bind, apply, call,也只是对新的function操作,并不影响func.apply(context...)中的context值。但是可以影响后面的参数值。

关于bind方法的介绍,今天看到颜海镜、颜大的文档,感觉对bind的了解加深一步,附上链接

关于箭头函数的this

根据MDN的文档,箭头函数是不会生成自己的this的(还有arguments)。所以我才给上面的this加上双引号。而且由于它本身并没有this,所以才不会被applybind, call所改变。

那么在箭头函数中调用的this是怎么来定的呢?

下面来自vajoy的一篇译文

虽然箭头函数没有一个自己的this,但当你在内部使用了this的时候,他会指向最近一层作用域的this

function foo(){
  return ()=>{
    return ()=>{
      return ()=>{
        console.log("id:", this.id);
      }
    }
  }
}
foo.call({id:42})()()(); // id:42

这里只有一次this的绑定,也就是foo()的时候.

这些连接内嵌的函数们都没有生命他们自己的this,所以this.id的引用会简单地顺着作用域链查找,一直查找到foo()函数,他是第一处能找到一个确切存在的this的地方。

由于只是我根据经验和资料自己总结的,所以不知道是否有疏忽或者遗漏,如果有问题的地方,欢迎提出。谢谢

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/81542.html

相关文章

  • JavaScript专题之函数记忆

    摘要:专题系列第十七篇,讲解函数记忆与菲波那切数列的实现定义函数记忆是指将上次的计算结果缓存起来,当下次调用时,如果遇到相同的参数,就直接返回缓存中的数据。 JavaScript 专题系列第十七篇,讲解函数记忆与菲波那切数列的实现 定义 函数记忆是指将上次的计算结果缓存起来,当下次调用时,如果遇到相同的参数,就直接返回缓存中的数据。 举个例子: function add(a, b) { ...

    RobinTang 评论0 收藏0
  • Javascript中函数作为对象魅力

    摘要:赋予了函数非常多的特性,其中最重要的特性之一就是将函数作为第一型的对象。那就意味着在中函数可以有属性,可以有方法,可以享有所有对象所拥有的特性。参考资料忍者秘籍关于函数我之前还写过一篇中高阶函数的魅力有兴趣的话可以看一看。 Javascript赋予了函数非常多的特性,其中最重要的特性之一就是将函数作为第一型的对象。那就意味着在javascript中函数可以有属性,可以有方法, 可以享有...

    morgan 评论0 收藏0
  • JavaScript设计模式(八):组合模式

    摘要:不同于其它静态编程语言,实现组合模式的难点是保持树对象与叶对象之间接口保持统一,可借助定制接口规范,实现类型约束。误区规避组合不是继承,树叶对象并不是父子对象组合模式的树型结构是一种聚合的关系,而不是。 showImg(https://segmentfault.com/img/bVbu79V?w=800&h=600); 组合模式:又叫 部分整体 模式,将对象组合成树形结构,以表示 部分...

    leon 评论0 收藏0
  • JavaScript 编程精解 中文第三版 七、项目:机器人

    摘要:来源编程精解中文第三版翻译项目原文译者飞龙协议自豪地采用谷歌翻译置疑计算机能不能思考就相当于置疑潜艇能不能游泳。这张图将成为我们的机器人在其中移动的世界。机器人在收到包裹时拾取包裹,并在抵达目的地时将其送达。这个机器人已经快了很多。 来源:ApacheCN『JavaScript 编程精解 中文第三版』翻译项目原文:Project: A Robot 译者:飞龙 协议:CC BY-NC-S...

    jas0n 评论0 收藏0
  • 忍者级别JavaScript函数操作

    摘要:我们需要知道的是,对于而言,匿名函数是一个很重要且具有逻辑性的特性。通常,匿名函数的使用情况是创建一个供以后使用的函数。截图自忍者秘籍通过完善之前对匿名函数的粗略定义,我们可以修复解决这个问题。 从名字即可看书,此篇博客总结与《JavaScript忍者秘籍》。对于JavaScript来说,函数为第一类型对象。所以这里,我们主要是介绍JavaScript中函数的运用。 系列博客地址:h...

    suemi 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<