JS 里的 this

  • 在 function 内部被创建
  • 指向调用时所在函数所绑定的对象(拗口)
  • this 不能被赋值,但可以被 call/apply 改变

1. this 和构造函数

    function C(){
this.a = 37;
} var o = new C();
console.log(o.a); // logs 37 function C2(){
this.a = 37;
return {a:38};
} var b = new C2();
console.log(b.a); // logs 38

2. this 和对象

对象内部方法的this指向调用这些方法的对象:

  • 函数的定义位置不影响其this指向,this指向只和调用函数的对象有关。
  • 多层嵌套的对象,内部方法的this指向离被调用函数最近的对象(window也是对象,其内部对象调用方法的this指向内部对象, 而非window)。
    //1:this指向调用函数的对象
var o = {
prop: 37,
f: function() {
return this.prop;
}
};
console.log(o.f()); //37 this指向o
var a = o.f;
console.log(a()): //undefined this指向a ,a中没有定义prop var o = {prop: 37};
function independent() {
return this.prop;
}
o.f = independent;
console.log(o.f()); // logs 37 this指向o

//2:this指向离被调用函数最近的对象
var o = {
prop: 37,
f: function() {
return this.prop;
}
};
function independent() {
return this.prop;
}
o.b = {
g: independent,
prop: 42
};
console.log(o.b.g()); //42 this指向o.b

3. this 和函数

普通函数内部的this分两种情况,严格模式非严格模式

//非严格模式下,this 默认指向全局对象window
function f1(){
return this;
}
f1() === window; // true //而严格模式下, this为undefined
function f2(){
"use strict"; // 这里是严格模式
return this;
}
f2() === undefined; // true

4. 全局环境的this

前面提到 this 是 “指向调用时所在函数所绑定的对象”, 这句话拗口但绝对正确,没有一个多余的字。

全局环境中有不同的宿主对象,浏览器环境中是 window, node 环境中是 global。这里重点说下浏览器环境中的 this。

浏览器环境中非函数内 this 指向 window

    alert(window=== this) // true

因此你会看很很多开源 JS lib 这么写

    (function() {
// ... })(this);

或这样写

    (function() {
// ... }).call(this);

比如 underscore 和 requirejs,大意是把全局变量 window 传入匿名函数内缓存起来,避免直接访问。至于为啥要缓存,这跟 JS 作用域链有关系,读取越外层的标识符性能会越差。

浏览器中比较坑人,非函数内直接使用 var 声明的变量默认为全局变量,且默认挂在 window 上作为属性。

    var andy = '刘德华'
alert(andy === window.andy) // true
alert(andy === this.andy) // true
alert(window.andy === this.andy) // true

因为这个特性,有些笔试题如

    var x = 10;
function func() {
alert(this.x)
}
var obj = {
x: 20,
fn: function() {
alert(this.x)
}
}
var fn = obj.fn
func() // 10
fn() // 10

没错,最终输出的都是全局的 10。永远记住这一点:

判断 this 指向谁,看执行时而非定义时只要函数(function)没有绑定在对象上调用,它的 this 就是 window

5. this和DOM事件

当函数被当做监听事件处理函数时, 其 this 指向触发该事件的元素 (针对于addEventListener事件)

    // 被调用时,将关联的元素变成蓝色
function bluify(e){
//在控制台打印出所点击元素
console.log(this);
//阻止时间冒泡
e.stopPropagation();
//阻止元素的默认事件
e.preventDefault();
this.style.backgroundColor = '#A5D9F3';
} // 获取文档中的所有元素的列表
var elements = document.getElementsByTagName('*'); // 将bluify作为元素的点击监听函数,当元素被点击时,就会变成蓝色
for(var i=0 ; i<elements.length ; i++){
elements[i].addEventListener('click', bluify, false);

6. this和内联事件

内联事件中的this指向分两种情况:

  • 当代码被内联处理函数调用时,它的this指向监听器所在的DOM元素
  • 当代码被包括在函数内部执行时,其this指向等同于 函数直接调用的情况,即在非严格模式指向全局对象window, 在严格模式指向undefined







    依次点击上边的三个按钮后在控制台的输出结果

7. setTimeout & setInterval

对于延时函数内部的回调函数的this指向全局对象window(当然我们可以通过bind方法改变其内部函数的this指向)

看下边代码及截图

    //默认情况下代码
function Person() {
this.age = 0;
setTimeout(function() {
console.log(this);
}, 3000);
} var p = new Person();//3秒后返回 window 对象
==============================================
//通过bind绑定
function Person() {
this.age = 0;
setTimeout((function() {
console.log(this);
}).bind(this), 3000);
} var p = new Person();//3秒后返回构造函数新生成的对象 Person{...}



8. this可以被 call/apply 改变

当函数通过Function对象的原型中继承的方法 call() 和 apply() 方法调用时, 其函数内部的this值可绑定到 call() & apply() 方法指定的第一个对象上, 如果第一个参数不是对象,JavaScript内部会尝试将其转换成对象然后指向它。

例子:

    function add(c, d){
return this.a + this.b + c + d;
} var o = {a:1, b:3}; add.call(o, 5, 7); // 1 + 3 + 5 + 7 = 16 add.apply(o, [10, 20]); // 1 + 3 + 10 + 20 = 34 function tt() {
console.log(this);
}
// 返回对象见下图(图1)
tt.call(5); // Number {[[PrimitiveValue]]: 5}
tt.call('asd'); // String {0: "a", 1: "s", 2: "d", length: 3, [[PrimitiveValue]]: "asd"}

9. me/self/that/_this 暂存 this

如果采用 OOP 方式写 JS 代码,无可避免的会用到 this,方法内会访问类的内部属性(字段),也可能会调用类的另一个方法。当类的方法内又有一个 function 时,比如浏览器端开发经常遇见的给 DOM 元素添加事件,这时如果事件处理器(handler)中的想调用类的一个方法,此时 handler 内的 this 是 dom 元素而非类的当前对象。这个时候,需要把 this 暂存,开发者发挥着自己的聪明才智留下了几种经典的命名** me, self, that, _this**。如



如:



一般会在每个方法的第一句就把 this 暂存下来

10. ES5 中新增的 bind 和 this

bind方法在ES5引入, 在Function的原型链上, Function.prototype.bind。通过bind方法绑定后, 函数将被永远绑定在其第一个参数对象上, 而无论其在什么情况下被调用。

function f(){
return this.a;
} var g = f.bind({a:"azerty"});
console.log(g()); // azerty var o = {a:37, f:f, g:g};
console.log(o.f(), o.g()); // 37, azerty

11. ES6 箭头函数=> 和 this

箭头函数的一个重要特征就是颠覆了上面的一句话,再贴一次

判断 this 指向谁,看执行时而非定义时,只要函数(function)没有绑定在对象上调用,它的 this 就是 window

是的,前面一直用这句话来判断 this 的指向,在箭头函数里前面半句就失效了。箭头函数的特征就是,定义在哪,this 就指向那。即箭头函数定义在一个对象里,那箭头函数里的 this 就指向该对象。如下

var book = {
author: 'John Resig',
init: function() {
document.onclick = ev => {
alert(this.author) ; // 这里的 this 不是 document 了
}
}
};
book.init()

对象 book 里有一个属性 author, 有一个 init 方法, 给 document 添加了一个点击事件,如果是传统的函数,我们知道 this 指向应该是 document,但箭头函数会指向当前对象 book。

箭头函数让 JS 回归自然和简单,函数定义在哪它 this 就指向哪,定义在对象里它指向该对象,定义在类的原型上,就指向该类的实例,望文知意这样更容易理解。

作为方法的箭头函数this指向全局window对象,而普通函数则指向调用它的对象

原文参考:

https://www.cnblogs.com/snandy/p/4773184.html

http://www.cnblogs.com/dongcanliang/p/7054176.html

JavaScript中的this关键字的几种用法的更多相关文章

  1. java 中的this关键字的几种用法

    转自:http://blog.csdn.net/anmei2010/article/details/4091227 1.     当成员变量和局部变量重名时,在方法中使用this时,表示的是该方法所在 ...

  2. 如何理解JavaScript中的this关键字

    前言 王福朋老师的 JavaScript原型和闭包系列 文章看了不下三遍了,最为一个初学者,每次看的时候都会有一种 "大彻大悟" 的感觉,而看完之后却总是一脸懵逼.原型与闭包 可以 ...

  3. 转载 深入理解JavaScript中的this关键字

    转载原地址: http://www.cnblogs.com/rainman/archive/2009/05/03/1448392.html 深入理解JavaScript中的this关键字   1. 一 ...

  4. JavaScript中的this关键字的用法和注意点

    JavaScript中的this关键字的用法和注意点 一.this关键字的用法 this一般用于指向对象(绑定对象); 01.在普通函数调用中,其内部的this指向全局对象(window); func ...

  5. 博文推荐】Javascript中bind、call、apply函数用法

    [博文推荐]Javascript中bind.call.apply函数用法 2015-03-02 09:22 菜鸟浮出水 51CTO博客 字号:T | T 最近一直在用 js 写游戏服务器,我也接触 j ...

  6. JavaScript中常见的数组操作函数及用法

    JavaScript中常见的数组操作函数及用法 昨天写了个帖子,汇总了下常见的JavaScript中的字符串操作函数及用法.今天正好有时间,也去把JavaScript中常见的数组操作函数及用法总结一下 ...

  7. JavaScript中常见的字符串操作函数及用法

    JavaScript中常见的字符串操作函数及用法 最近几次参加前端实习生招聘的笔试,发现很多笔试题都会考到字符串的处理,比方说去哪儿网笔试题.淘宝的笔试题等.如果你经常参加笔试或者也是一个过来人,相信 ...

  8. .NET(c#)new关键字的三种用法

    前几天去家公司面试,有一道这样的题:写出c#中new关键字的三种用法,思前想后挖空心思也只想出了两种用法,回来查了下msdn,还真是有第三种用法:用于在泛型声明中约束可能用作类型参数的参数的类型,这是 ...

  9. NEW关键字的三种用法

    最近面试中有一道题是写new关键字的几种用法,想了下写下我知道的两种用法 第一种 创建对象.调用构造函数,这就不用讲了 ClassA  A=new ClassA(); 第二种 是作为修饰符,显示隐藏继 ...

随机推荐

  1. nextjs服务端渲染原理

    1. 简单的介绍一下 nextjs是react进行服务端渲染的一个工具,默认以根目录下的pages为渲染路由 比如我在pages目录下创建一个index.js文件,然后export default一个 ...

  2. pyd打包补充

    网上说的将python代码,通过Cython打包成pyd的教程挺多,好处也多,主要有两个: 1.隐藏代码 2.加速运行速度 补充两点: 1.打包脚本配置 __build__.py from distu ...

  3. k8s 内部各个部件运转

    Master节点部署的都是kubernetes的核心模块APIServer提供资源操作的唯一入口,并且提供认证/授权/kubernets的访问控制可以通过kubectl和自己开发的客户端,通过http ...

  4. 左神算法书籍《程序员代码面试指南》——1_08构造数组的MaxTree

    [题目] 将一个没有重复数字的数组中的数据构造一个二叉树 每个节点都是该子树的最大值 [要求] 时间复杂度为O(N)[题解] 使用单调栈,栈的顺序是维持从大到小排序 通过使用单调栈,将数组中中所有数的 ...

  5. request.getSession().getServletContext().getRealPath("upload/" ); 获取不到 tomcat 服务器目录

    上传一个文件,找不到该文件的位置 设置上传的文件是在项目中的话 可以通过查找项目的路径锁定上传的文件路径 解决步骤: 可以通过jsp页面 打印获取项目的物理路径 控制台即可输出项目路径 这只是找了了上 ...

  6. hive作业的优化策略

    Mapreduce自身的特点: 1.IO和网络负载大:优化策略:减少IO和网络负载. 2.内存负载不大.优化策略:增大内存使用率: 3.CPU负载不大.优化策略:增大CPU使用率: (hive的优化应 ...

  7. 如何理解张量tensor

    1 关于张量的四种定义 “张量”在不同的运用场景下有不同的定义. 第一个定义,张量是多维数组,这个定义常见于各种人工智能软件.听起来还好理解.--本文仅解释此种 2 多维数组 从第一个定义:张量是多维 ...

  8. 用惯了jquery, 想用angularjs 还真不好理解

    jquery 比较直白,什么都是操作dom 节点. angularjs 就好比 thinkphp, ci 等框架,有自己约定的格式和方式.需要遵循它的规则,研究中... 比如说我,用了很长事件的jqu ...

  9. Puppet master-agent模型搭建

    Puppet master-agent模型工作过程: 基于ssl xmlrpc进行通信,端口8140/tcp agent:默认每隔30分钟向master发送node name和facts,并请求cat ...

  10. 火狐插件hostadmin

    windows的host文件:  c:\Windows\System32\drivers\etc\hosts 手动修改hosts文件费时又费力,可直接在FF附加组件中搜索hostadmin下载安装: ...