在JavaScript中,this关键字可以说是最复杂的机制之一。对this的作用机制缺乏比较深入的理解很容易在实际开发中出现问题。

1、this的作用

为什么要在JavaScript中使用this呢?因为this提供了一种简明的方式来隐式传递一个对象引用,可以让函数接口设计的简单且容易复用:

function display() {
console.log(this.name);
} var obj1 = {name: "obj1"};
var obj2 = {name: "obj2"}; display.call(obj1); // "obj1"
display.call(obj2); // "obj2"

通过call方法,我们可以在调用display函数时为this传入不同的对象。如果不使用this关键字,那么上面的函数就需要显示增加一个调用时上下文参数:

function display(context) {
console.log(context.name);
} var obj1 = {name: "obj1"};
var obj2 = {name: "obj2"}; display(obj1); // "obj1"
display(obj2); // "obj2"

实际上这不够简洁,当使用模式比较复杂时,显示的上下文传递会让代码变得混乱复杂。使用this关键字,我们可以在调用时为this传入不同的对象引用,保证了方法的使用灵活性。

2、this的使用复杂性

this使用机制复杂,在开发容易出问题的根本原因在于:this是在运行时绑定,而不是在编写时绑定,this实际值取决于函数调用时的上下文。this的绑定和函数声明的位置没有关系,只取决于函数的调用方式。在JavaScript中,当函数被调用时,会创建一个活动记录(执行时上下文),这个记录包含函数在何处调用、函数的调用方法和传入参数等信息,this会记录其中一个属性。判断this实际绑定值,关键在于分析函数实际调用的位置。

3、this绑定规则

前面说了函数的实际调用位置决定了this的绑定值。在JavaScript中,this有4种绑定规则。

3.1、new绑定

在JavaScript中使用new调用函数会自动执行下面的操作:

  (1)创建一个新的对象

  (2)对新对象执行原型链接

  (3)新对象会被绑定到函数的this

  (4)如果函数没有返回其他对象,那么新对象会被返回

new绑定容易理解,下面是一段常见的用new调用函数创建对象的代码:

function Book(name, author, isbn) {
this.name = name;
this.author = author;
this.isbn = isbn;
} let book = new Book("Zakas", "ES6", 12345); console.log(book.name); // "Zakas"

3.2、隐式绑定

当对象内部包含一个指向函数的属性,并且在调用时通过这个属性间接引用函数(obj.prop()的形式),那么函数内的this会隐式指向这个对象,也即隐式绑定:

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

在调用位置上,函数是通过obj.foo来引用的,可以说函数被调用时obj对象拥有或包含它。此时,this绑定在obj这个上下文对象上。

3.3、显示绑定

在某些情况下,我们希望函数内的this绑定在某些指定的对象上,这称为显示绑定。在JavaScript中可以使用call和apply为函数显示指定this绑定。call和apply的第一个参数是一个对象,这个对象会被绑定到this上:

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

使用bind也可以让this绑定在指定对象上,bind绑定也是一种显示绑定,又称为硬绑定:

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

3.4、默认绑定

当使用独立函数调用(func()形式),会发生默认绑定,可以把这条规则看成是无法使用其他规则时的默认规则。看下面的示例代码:

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

当调用foo时,使用默认绑定规则,this被绑定到全局对象上。在strict模式下,this会绑定到undefined。

4、绑定优先级

上面4种绑定规则独立使用的话,判断this的绑定值并不复杂。但实际函数调用时,可能多条绑定规则都可以使用,那么这时就要根据每个规则的绑定优先级来判断this实际的绑定值。接下来看各种绑定规则的优先级。

4.1、默认绑定优先级最低

默认绑定的优先级最低,这个容易理解。因为当无法使用其他的绑定规则时才会使用默认规则。

4.2、显示绑定优先级高于隐式绑定

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

上面的代码中,obj1.foo()使用隐式绑定规则,this绑定到obj1对象上。obj1.foo.call()可同时使用隐式绑定和显示绑定规则,显示绑定优先级高于隐式绑定,this绑定到obj2对象上。

4.3、new绑定优先级高于隐式绑定

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

上面代码中,new obj1.foo(4)可同时使用new绑定和隐式绑定。由bar.a的值为4可以知道,new绑定优先级高于隐式绑定。

4.4、new绑定优先级高于显示绑定

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

上面代码中,new bar(3)可同时使用new绑定和bind绑定。baz.a的值为3,说明new绑定优先级高于隐式绑定。

4.5、综述

现在可以根据this绑定优先级判断函数在调用位置实际绑定的值。实际可以按照下面的顺序判断:

  (1、函数是否在new中调用?如果是的话this绑定新创建的对象。调用例子:var bar = new foo()。

  (2、函数是否通过apply、call显示绑定或者bind硬绑定?如果是,this绑定指定的对象。调用例子:var bar = foo.call(obj)。

  (3、函数是否在某个上下文对象中调用(隐式绑定)?如果是,this绑定在上下文对象上。调用例子:var bar = obj.foo()。

  (4、如果都不是的话,使用默认绑定。在严格模式下,this绑定到undefined,在非严格模式下,绑定到全局对象。调用例子:var bar = foo()。

5、箭头函数中的this

ES6中引入了箭头函数,箭头函数使用操作符=>定义。箭头函数不使用上面4种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); //

foo内部的箭头函数创建时,foo函数内this绑定到obj1上,bar(箭头函数)的this也会绑定到obj1上,箭头函数内的this是不能被修改的。

JavaScript this用法总结的更多相关文章

  1. javascript webstorm用法

    javascript  webstorm用法 一.什么是webstorm?       WebStorm 是jetbrains公司旗下一款JavaScript 开发工具.被广大中国JS开发者誉为“We ...

  2. JavaScript this用法总结(**************************************)

    JavaScript this用法总结 在JavaScript中,this关键字可以说是最复杂的机制之一.对this的作用机制缺乏比较深入的理解很容易在实际开发中出现问题. 1.this的作用 为什么 ...

  3. <a href="javascript:;">的用法说明

    <a href="javascript:;">的用法说明 1.标签的 href 属性用于指定超链接目标的 URL,href 属性的值可以是任何有效文档的相对或绝对 UR ...

  4. javascript:void(0)和javascript:;的用法

    一.JavaScript:void(0) 我们经常会使用到 javascript:void(0) 这样的代码,那么在 JavaScript 中 javascript:void(0) 代表的是什么意思呢 ...

  5. JavaScript高级用法二之内置对象

    综述 本篇的主要内容来自慕课网,内置对象,主要内容如下 1 什么是对象 2 Date 日期对象 3 返回/设置年份方法 4 返回星期方法 5 返回/设置时间方法 6 String 字符串对象 7 返回 ...

  6. Javascript typeof 用法

    在js里用到数组,比如 多个名字相同的input, 若是动态生成的, 提交时就需要判断其是否是数组. if(document.mylist.length != "undefined" ...

  7. javascript sort 用法

    <html> <head> <title></title> <script type="text/javascript" sr ...

  8. 一个好玩的小制作,以及在<a/>中的标签href="javascript:;"/href="javascript:void(0);"/href="javascript:"的用法

    一:一个小图标的制作 我们在支付宝.微信等某些地方上传文件时会遇到以下的图标,但是这样的图标其实可以用<a/>标签以及css样式完成, 具体代码如下: <!DOCTYPE html& ...

  9. JavaScript高级用法三之浏览器对象

    综述 本篇的主要内容来自慕课网,内置对象,主要内容如下 1 window对象 2 JavaScript 计时器 3 计时器setInterval() 4 取消计时器clearInterval() 5 ...

随机推荐

  1. 关于兼容性——百分比对于IE浏览器的影响

    之前为了适应页面放大或者缩小,很多宽度都是写的百分比,后来发现有产生换行现象 总结一下: 如果页面是满占位的,我想百分比在谷歌.火狐都应该没什么问题,在IE 就会产生换行  因为IE浏览器存在一个四舍 ...

  2. C# Winform学习---MDI窗体的设计,PictureBox控件(图片上一页下一页),Timer控件,MenuStrip控件

    一.MDI窗体的设计 1.MDI简介 MDI(Multiple Document Interface)就是所谓的多文档界面,与此对应就有单文档界面 (SDI), 它是微软公司从Windows 2.0下 ...

  3. Android布局6大类

    1:在我们Android开发中,常见的布局的方式有6大类 线性布局LinearLayout 相对布局RelativeLayout 表格布局TableLayout 单帧布局FrameLayout 绝对布 ...

  4. (二)catalina.bat

    startup.bat在最后调用catalina.bat,并且传递了start参数,设置了CATALINA_HOME和CURRENT_DIR俩个临时环境变量.那么catalina.bat都做了什么? ...

  5. OA及权限系统

    一直想找一款适合自己的权限管理后台,始终都没找到合适的,决定自己写一个 开发环境:vs2012 ,sql2008 语言:C# 前端:ligurui,jquery ORM框架:EF6.0 先来晒下我的数 ...

  6. PTGM and APTM

    1. 性能测试过程模型(PTGM) PTGM模型包括以下几个步骤: 测试前期的准备 测试工具的引入 测试计划 测试设计与开发 测试执行与管理 测试分析 测试前期准备:主要任务为保证系统稳定和建立合适的 ...

  7. 123. Best Time to Buy and Sell Stock (三) leetcode解题笔记

    123. Best Time to Buy and Sell Stock III Say you have an array for which the ith element is the pric ...

  8. Reveal分析IOS界面,plist文件读取

    Reveal分析IOS界面,需要得到app的 softwareVersionBundleId上传到iphone中 , 而IOS8的iTunesMetadata.plist (设备路径/var/mobi ...

  9. Python的包管理工具Pip (zz )

    Python的包管理工具Pip 接触了Ruby,发现它有个包管理工具RubyGem很好用,并且有很完备的文档系统http://rdoc.info 发现Python下也有同样的工具,包括easy_ins ...

  10. app之间的跳转,进入二级界面

    功能实现:A跳到B并打开B中指定页面.http://blog.csdn.net/dollyyang/article/details/50325307 点击页面判断是否安装app并打开,否则跳转app ...