之前很久的时间,因为研究不深,对于this的值一直模模糊糊,不是很清楚,最近有空做了一些研究,终于彻底弄明白了this到底为何物。

首先, 先抛出一个定论:”在Javascript中,this关键字永远都指向函数(方法)的所有者”。

全局上下文

在全局上下文中(在任何函数体外部),this指代全局对象,无论是否在严格模式下。

(注:全局对象没有名称,视具体的js环境而定义,在浏览器环境下为window)

console.log(this.document === document);  //true

//在浏览器中,全局对象为window对象
console.log(this === window) //true this.a = 37;
console.log(window.a); // =>37

函数上下文

在函数内部,this的值取决于函数如何调用。

直接调用

function f1() {
return this;
} f1() === window; // => true function makeNoSense(x) {
this.x = x;
} makeNoSense(5);
x;// x 已经成为一个值为 5 的全局变量

在上面的例子中,this的值不是由函数调用设定。因为代码不是在严格模式下执行,this 的值总是一个对象且默认为全局对象。

function f2(){
"use strict"; // 这里是严格模式
return this;
} f2() === undefined; // true

在严格模式下,this 是在进入运行环境时设置的。若没有定义,this的值将维持undefined状态。同时它也能设置成任意值,比如 null 或者42 或者“I am not this”。

对象方法中的this

在以对象的方法的方式调用函数时,他们的this是调用该函数的对象。

下面的例子中,当o.f()被调用时,函数内的this将绑定到o对象。

var o = {
prop: 37,
f: function() {
return this.prop;
}
}; console.log(o.f()); // logs 37

注意,在何处或者如何定义调用函数完全不会影响到this的行为。在上一个例子中,我们在定义o的时候为其成员f定义了一个匿名函数。但是,我们也可以首先定义函数然后再将其附属到o.f。这样做this的行为也一致:

var o = {prop: 37};

function independent() {
return this.prop;
} o.f = independent; console.log(o.f()); // logs 37

这说明this的值只与函数 f 作为 o 的成员被调用有关系。

类似的,this 的绑定只受最靠近的成员引用的影响。在下面的这个例子中,我们把一个方法g当作对象o.b的函数调用。在这次执行期间,函数中的this将指向o.b。事实上,这与对象本身的成员没有多大关系,最靠近的引用才是最重要的。

o.b = {
g: independent,
prop: 42
};
console.log(o.b.g()); // logs 42

原型链中的 this

相同的概念在定义在原型链中的方法也是一致的。如果该方法存在于一个对象的原型链上,那么this指向的是调用这个方法的对象,表现得好像是这个方法就存在于这个对象上一样。

var o = {
f : function(){
return this.a + this.b;
}
};
var p = Object.create(o);
p.a = 1;
p.b = 4; console.log(p.f()); //

在这个例子中,对象p没有属于它自己的f属性,它的f属性继承自它的原型。但是这对于最终在o中找到f属性的查找过程来说没有关系;查找过程首先从p.f的引用开始,所以函数中的this指向p。也就是说,因为f是作为p的方法调用的,所以它的this指向了p。这是JavaScript的原型继承中的一个有趣的特性。

构造函数中的 this

当一个函数被作为一个构造函数来使用(使用new关键字),它的this与即将被创建的新对象绑定。

call 和 apply

当一个函数的函数体中使用了this关键字时,通过所有函数都从Function对象的原型中继承的call()方法和apply()方法调用时,它的值可以绑定到一个指定的对象上。

function add(c, d){
return this.a + this.b + c + d;
} var o = {a:1, b:3}; // The first parameter is the object to use as 'this', subsequent parameters are passed as
// arguments in the function call
add.call(o, 5, 7); // 1 + 3 + 5 + 7 = 16 // The first parameter is the object to use as 'this', the second is an array whose
// members are used as the arguments in the function call
add.apply(o, [10, 20]); // 1 + 3 + 10 + 20 = 34

使用 call 和 apply 函数的时候要注意,如果传递的 this 值不是一个对象,JavaScript 将会尝试使用内部 ToObject 操作将其转换为对象。因此,如果传递的值是一个原始值比如 7 或 'foo' ,那么就会使用相关构造函数将它转换为对象,所以原始值 7 通过new Number(7)被转换为对象,而字符串'foo'使用 new String('foo') 转化为对象,例如:

function bar() {
console.log(Object.prototype.toString.call(this));
} bar.call(7); // [object Number]

bind 方法

ECMAScript 5 引入了 Function.prototype.bind。调用f.bind(someObject)会创建一个与f具有相同函数体和作用域的函数,但是在这个新函数中,this将永久地被绑定到了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

DOM事件处理函数中的 this

当函数被用作事件处理函数时,它的this指向触发事件的元素(一些浏览器在动态添加监听器时不遵守这个约定,除非使用addEventListener 这句不太确定翻译的是否正确)。

// 被调用时,将关联的元素变成蓝色
function bluify(e){
console.log(this === e.currentTarget); // 总是 true // 当 currentTarget 和 target 是同一个对象是为 true
console.log(this === e.target);
this.style.backgroundColor = '#A5D9F3';
} // 获取文档中的所有元素的列表
var elements = document.getElementsByTagName('*'); // 将bluify作为元素的点击监听函数,当元素被点击时,就会变成蓝色
for(var i=0 ; i<elements.length ; i++){
elements[i].addEventListener('click', bluify, false);
}

对象方法中内建函数中this

对象方法中内建函数中this绑定到全局对象上。这属于 JavaScript 的设计缺陷,正确的设计方式是内部函数的 this 应该绑定到其外层函数对应的对象上,为了规避这一设计缺陷,聪明的 JavaScript 程序员想出了变量替代的方法,约定俗成,该变量一般被命名为 that(self)。

var point = {
x : 0,
y : 0,
moveTo : function(x, y) {
var that = this;
// 内部函数
var moveX = function(x) {
that.x = x;
};
// 内部函数
var moveY = function(y) {
that.y = y;
}
moveX(x);
moveY(y);
}
};
point.moveTo(1, 1);
point.x; //==>1
point.y; //==>1

JS中this的值到底为何?的更多相关文章

  1. 图文结合深入理解 JS 中的 this 值

    图文结合深入理解 JS 中的 this 值 在 JS 中最常见的莫过于函数了,在函数(方法)中 this 的出现频率特别高,那么 this 到底是什么呢,今天就和大家一起学习总结一下 JS 中的 th ...

  2. js中以键值对的形式当枚举

    js中以键值对的形式当枚举var Penum= { B: "姓名", C: "所属居委", D: "证件号", E: "性别&qu ...

  3. 图文结合深入理解JS中的this值

    文章目录 Js 中奇妙的this值 1. 初探this 2. this指向总结 2.1 普通函数调用 2.2 对象的方法调用 2.3 构造函数调用 2.4 利用call,apply,bind方法调用函 ...

  4. 页面上有两个元素id相同,js中如何取值

    页面上有两个table,id都是”cont2",现要在js中取到这两个table,改变样式. js实现: var tab2=document.all.cont2(1);var  tab=do ...

  5. asp.net通过后台代码给前台设置css样式,下拉列表在js中的取值

    后台根据不同的用户登陆隐藏或显示前台div标签 前台: 将div声明成服务器端控件 <div id="div1" runat="server">.. ...

  6. Js 中的原始值和引用值

    最近遇写 node.js 时到一个问题,把对象当赋值给数组成员时总是出错,比如下面的代码, var Arr = new Array(); var Obj = new Object(); for(var ...

  7. input框中的value值到底是什么

    value 属性为 input 元素设定值. 对于不同的输入类型,value 属性的用法也不同: type="button", "reset", "s ...

  8. js中的bool值转换及"&&" 、"||"、 "!!"详解

    bool值转换 数据类型 bool值转化 undefined undefined 转化为 false Object null 转化为false,其他为 true Boolean false 转化为 f ...

  9. 关于js中的取值问题

    像这样是获取不到值的,弹出的消息是 underfined:<html><style type="text/css">input { border: 1px ...

随机推荐

  1. Fake chat script for website download

    Are you searching for free fake webchat script then you are at the right place go get download your ...

  2. recovery编译问题汇总

    1.修改支持USB大容量存储 (1).首先需要查看手机lun位置 手机链接电脑,打开cmd命令行,依次输入以下命令: adb shell find /sys -name "lun" ...

  3. Python Day 01

    What is variables? 一段命名的内存空间 变量即在程序运行过程中,它的值是允许改变的量 1.变量命名: 合法: 显式.通俗易懂. nums_of_jay_gf = 19 NumsOfJ ...

  4. win10 内测14352 加入了容器 和docker新功能,想体验的赶快升级

    原来只在server2016上有,现在加入到win0内测版了windows 容器提供了两种级别的隔离技术,分别是Windows Server container  和Hyper-V Container ...

  5. java 中关于synchronized的通常用法

    package j2se.thread.test; /*** * synchronized(class)很特别,它会让另一个线程在任何需要获取class做为monitor的地方等待. * class与 ...

  6. js2

    1.JS的三种输出方式: alert("");console.log("");document.write(""); 2.流程控制语句: a ...

  7. Ubuntu下mysql-server的安装

    (1)更新 #apt-get update (2)安装 #apt-get install mysql-server 出现窗口设置"root"用户的密码为"456456&q ...

  8. NLog的使用

    1.项目添加NLog的项目引用: 2.将工程的framework框架改为3.5或4.0,将配置文件[NLog.config]拷贝至运行的bin/(release/debug)路径下 3.项目中代码使用 ...

  9. The Pragmatic Programmer Quick Reference Guide

    1.关心你的技艺 Care About Your Craft 如果不在乎能否漂亮地开发出软件,你又为何要耗费生命去开发软件呢? 2.思考!你的工作 Think! About Your Work 关掉自 ...

  10. [Python]命令行进度条

    关键点是输出'\r'这个字符可以使光标回到一行的开头,这时输出其它内容就会将原内容覆盖. import time import sys def progress_test(): bar_length= ...