this关键字之三板斧

1.第一板斧——this的原则

this代表函数运行时,自动生成的一个内部对象,只能在函数内部使用。随着函数使用场合的不同,this的值会发生变化。但是有一个原则是不变的:this指向调用函数的对象。

2.第二板斧——this的四种绑定形式

  • 默认绑定

    function foo(){
    console.log(this.a);
    }
    var a=2;
    foo();//2

    这是我们最常见的函数调用类型:独立函数调用。foo()是直接使用不带任何修饰的函数引用进行调用的,只能使用默认绑定(看完下面的三条规则,再来理解这句话),无法应用其他规则。此时this指向全局对象,如果使用严格模式,this会绑定到undefined。
  • 隐式绑定
function foo(){console.log(this.a);
}
var obj={a:2,foo:foo};
obj.foo();//2

像这种函数调用是属于函数引用有上下文对象,这种是最好理解的,因为高级语言比如C#,java就是采用这种机制。这时隐式绑定规则会把函数调用中的this绑定到上下文对象。

  • 显式绑定
    再讲这个绑定之前,我们应该知道JavaScript提供的绝大多数函数以及你自己创建的函数都有call()和apply()方法,至于这两个函数的差别,自己去查资料,这不是本文的重点。
    这两个函数的第一个参数是一个对象,在函数调用时会将这个对象绑定到this。因为你可以直接指定this的绑定对象,称之为显式绑定;此外ES5中还提供了bind()方法,这个函数与上面两个函数的不同之处在于,bind()会返回一个新的函数,并把你指定的参数设置为this。
function foo(){console.log(this.a);
}
var obj={a:2};
foo.call(obj);//2
  • new关键字绑定
function foo(a){this.a=a;
}
var bar=new foo(2);
console.log(bar.a);

我们首先来了解一下,我们使用new来调用函数,会执行下面的操作:
1.创建一个全新的对象。
2.这个新对象会被执行Prototype连接。
3.这个新对象会绑定到this
4.如果函数没有返回其他对象,那么new表达式中的函数调用会自动返回这个对象。
这是我们会看到this绑定到新创建的对象上了,我们称之为new绑定

3.第三板斧——代码分析

最近《画江湖之不良人》真人版莫名其妙的火了,看完之后感觉挺不错,片中的女演员挺漂亮。期待《画江湖之灵主》也能拍成真人版。这里我先给大家剧透一些《灵主》中的一些情节——男猪脚的武功最后练到九重山,但是我们理解this关键字也有九重山,让我们开始修炼吧。
结合1和2的原则和绑定形式,我们来分析一些代码中易混淆的this指向。
(1) 一重山
var a=1;
function test(){
var a=2;
console.log(this.a); //1
}
test();

这段代码在浏览器中是比较常见,我们结合四种绑定规则的特点,我们发现这种情况适合默认绑定——this指向全局对象window,所以这里打印的是“1”。
(2)二重山

var a=1;
function test(){
console.log(this.a);
}
var obj={
a:2,
fun:test
};
obj.fun(); // 2
var fun1=obj.fun;
fun1(); // 1

不知道你看到这段代码有没有晕,没有晕的话,且听我慢慢道来。obj.fun()这种调用形式,我们查看四种规则,发现符合第二种规则——隐式绑定,this指向obj,打印的是obj中的a。
再看fun1()这种调用形式,我们发现它符合四种规则的第一种,但是fun1=obj.fun()正好又符合第二种规则隐式绑定。我们仔细发现,fun1和obj.fun都是函数test的引用,因此fun1()等价于test(),所以第一种规则——默认绑定胜出。

(3)三重山

var a=1;
function test(){console.log(this.a); // 2function test2(){console.log(this.a); //1}test2();
}
var obj={a:2,fun:test};
obj.fun();

看完这段代码你能坚定的答出,test2中打印的是“1”吗?其实只要坚持四种规则,并且相信自己,你应该大声的说出是他,就是他,我们的小伙伴——“1”;其实这种明显符合第一种规则,但是obj.fun()给我们造成了迷惑,但是只要弄清四种绑定规则的特点,就应该毫无疑问的认为就是第一种情况。
(4)四重山

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

首先,我们还是用四种规则来去适配这段代码,发现仍然是第二种规则–隐式绑定符合,但是事实是这样吗?这段代码里面有个特殊的函数setTimeout,传递了一个回调函数,这个回调函数1秒之后 会被调用。这里我们可以模拟一下setTimeout的函数实现:

function setTimeout(fn,delay){//等待delay毫秒
fn();
}

通过观察这段代码我们就会发现,其实这种情况我们三重山中的例子相似,this指向全局变量,所以打印的结果是 2。

(5)五重山

var a=1;
var obj={
a:2,
foo:function(){console.log(this.a);}
};
var obj2={a:3};
obj.foo.call(); //1
obj.foo.call(obj2); //3

首先看obj.foo().call(),当无参数时,this
这里适用第三种规则–显式绑定,this指向obj2,所以打印的结果是3,而不是2。

(6)六重山

function Person(name){
this.name=__name;
}
Person.prototype.show=function(){
console.log(this.name);
}
var stu=new Person('Bob');
stu.show(); //Bob

这种适用第四种规则——new关键字绑定,这有点类似高级语言java、c#的用法,这点比较好理解。

(7)七重山——四种规则的优先级
毫无疑问,默认绑定的优先级是最低的。其次,显示绑定的优先级比隐式优先级高,我们可以找段代码试一下:

function foo(){console.log(this.a);
}
var obj1={a:2,foo:foo};
var obj2={a:3,foo:foo};
obj1.foo(); //2
obj2.foo();//3obj1.foo.call(obj2); //3
obj2.foo.call(obj1); //2

从最后两端代码中可以看出,显示绑定的优先级要高于隐式绑定
然后还有new关键字来打擂台,当然先找个级别较低的——隐式绑定来比较,谁的武功比较高强,当然还是写代码来比较:

 function foo(something){this.a=something;}var obj1={};obj1.foo(2);console.log(obj1.a); //2var bar=new obj1.foo(4);console.log(obj1.a); //2console.log(bar.a); //4 

可以看到new的武功比较高,隐式绑定的优先较低
那么new的武功和显式绑定比较呢,来,进入下一回合:

function foo(something){
this.a=something;
}
var obj1={};
var bar=foo.bind(obj1);
bar(2);
console.log(bar.a); //2
var baz=new bar(3);
console.log(obj1.a); //2
console.log(baz.a); //3

从上面的代码中可以看到,new确实修改了this的绑定,new关键字绑定又胜一局。显示绑定落败,优先级比new较低。接下来我们来看两个变态等级:

(8)八重山——eval函数

var a=3;
function foo(){
eval(“console.log(this.a)”);
}
var obj={a:2,foo:foo);
obj.foo(); //2
var test=obj.foo;
test(); //3

其实我们套用四种规则来判定this的指向也行,this绑定到当前作用域的对象上。
(9)九重山——箭头函数
箭头函数不使用this的四种绑定规则,而是根据外层作用域来决定this。

function foo(){
return (a)=>{
console.log(this.a);
}
}
var obj1={a:2};
var obj2={a:3};
var bar =foo.call(obj1);
bar.call(obj2); // 2

foo()内部创建的箭头函数会捕获调用时foo()的this,由于this绑定到obj1,bar的this也会绑定到obj1,箭头函数的绑定无法被修改。(new也不行)
说到这里,this的关键字算是告一段落。

参考文章

js中this关键字详解
Javascript中this关键字详解
JS中this关键字

js中的this关键字相关推荐

  1. Js中的const关键字

    const关键字 和 let 关键字一样都是有块级作用域. const声明一个只读的常量.一旦声明,常量的值就不能改变.一旦声明变量,就必须立即初始化,不能留到以后赋值. const foo; // ...

  2. 简单记录js中的this关键字

    1.this只会指向调用this所在函数的上一级对象,而不会上两级: 2.this永远指向的是最后调用它的对象(赋值的情况不是调用执行): 3.new关键字可以改变this的指向,将这个this指向对 ...

  3. js中for(i in array)和for(i=0;i<array.length;i++)之间的坑

    前情提要 刚刚接触到js写for循环的时候,觉得for(i in array)这种格式简直是非常直观,比三段论的for循环好写得多.直到遇到了一个坑,事情是这样的: 最开始的网页中,鉴于方便,清一色使 ...

  4. JS中this的指向

    JS中this的指向,this是js中的一个关键字 1.this的指向有这四种情况 1. 在普通的函数中,this指向全局对象window 2.在构造函数中,this指向创造出来的实例 3.对象的方法 ...

  5. 深入理解JS中this关键字

    为什么要使用this关键字 看个例子 function indetify() {retun this.name.toUpperCase()}var obj = {name: 'zz'}indetify ...

  6. JS中this关键字

    JS中this关键字 this是javascript的一个关键字,随着函数使用场合不同,this的值会发生变化.但是总有一个原则,那就是this指的是调用函数的那个对象. 1.全局代码中的this a ...

  7. Vue.js-Day01-PM【事件绑定(事件传参、事件对象、传参+获取事件对象)、样式处理操作(模板、事件、属性绑定)、Tab切换(原生js实现、Vue.js实现)、js中的this详解关键字】

    Vue.js实训[基础理论(5天)+项目实战(5天)]博客汇总表[详细笔记] 目   录 4.事件绑定 4.1.事件绑定(点击.双击.鼠标移动) 点击按钮-最简单的事件绑定(无参函数) 格式 点击按钮 ...

  8. js中的关键字总结呢

    1.document.write(""); 输出语句 2.JS中的注释为// 3.传统的HTML文档顺序是:document->html->(head,body) 4. ...

  9. JS中关键字in的作用

    JS中关键字in的作用 in关键字可以用来检测某个属性是否存在某个对象中,对于对象的属性要用字符串指定属性的名称("属性名") // 举个栗子:console.log(" ...

最新文章

  1. 编写程序记录文件位置
  2. 导师推荐的学术前沿号
  3. CDN预热与刷新在促销活动中的应用
  4. robot framework集成Jenkins环境
  5. ASIHTTPRequest详解
  6. CGLI 报错 :VerifyError: class net.sf.cglib.core.DebuggingClassWriter overrides final method visit
  7. 用Docker快速搭建一个博客网站,很简单的嘛~
  8. DevExpress统计图TextPattern说明
  9. HttpClient的使用方法
  10. MyBatis代码自动生成
  11. #C语言或C++中强大的图形库——easyx
  12. 项目管理-项目风险管理
  13. 安装chrome插件:FireShot
  14. js判断文件后缀名方法
  15. 记忆网络之Dynamic Memory Networks模型介绍及代码实现
  16. 易捷行云EasyStack携新一代私有云亮相中国电子信息博览会
  17. 一个男人写给前女友的话。。。真心哭了
  18. 【错误集】 MonkeyPatchWarning: Monkey-patching ssl after ssl has already been imported may lead to errors
  19. Java 中this和super的用法总结
  20. 小兵围大炮||大兵小将【C++】

热门文章

  1. 使用canal 监听mysql binlog获取增量数据
  2. php开发框架及cms总结
  3. 非门,与非门,或非门
  4. 开元弧焊机器人编程_焊接机器人编程的2种方法
  5. 计算机ps课如何把玫瑰花绿色,PhotoShop制作喷溅的玫瑰花朵效果的教程
  6. 在亚马逊中如何选择关键词?
  7. google closure
  8. C#之CAD二次开发(16) 表格操作
  9. 有刘谦的春晚去哪了?
  10. 1、TI335x环境建立