本文目录:
- 1.在方法中,this 指的是所有者对象
- 2.单独使用的时候,this 指的是全局对象
- 3.在函数中,this 指的是全局对象,严格模式下,this 是 undefined
- 4.在事件中,this 指的是接收事件的元素
- 5.this指向错乱问题及硬绑定方法
- 6.call()、apply()、bind()的联系和区别
JavaScript this 关键词指的是它所属的对象。
它拥有不同的值,具体取决于它的使用位置:
1.在方法中,this 指的是所有者对象
var person = {
firstName: "Bill",
lastName : "Gates",:
id: 678,
fullName : function() {
return this.firstName + " " + this.lastName;
}
};
本例中,fullName方法的拥有者是person对象,所有方法中的this 指的就是 person 对象
在JS对象中出现的this指向的都是对象本身
2.单独使用的时候,this 指的是全局对象
var x = this;
// [object Window]
在浏览器窗口中,全局对象是 [object Window]
3.在函数中,this 指的是全局对象,严格模式下,this 是 undefined
在 JavaScript 函数中,函数的拥有者默认绑定 this。
因此,在函数中,this 指的是全局对象 [object Window]。
function myFunction() {
return this;
// [object Window]
}
注:在函数中使用时,在严格模式下,this 是未定义的(undefined)。
4.在事件中,this 指的是接收事件的元素
在 HTML 事件处理程序中,this 指的是接收此事件的 HTML 元素
其他形式的事件绑定
function ClickOn(obj){
obj.style.width="200px";
// obj当前点击的标签
}
document.getElementById('i1').onclick = function(){
this.style.width="200px";
// this 代指当前点击的标签
}
注意:
- 箭头函数里面没有自己的this
- 构造函数的this默认为实例对象
- this的绑定和函数的声明位置没有关系,只取决于函数的调用方式,当一个函数被调用时,会创建一个活动记录(有时候也被称为执行上下文)。这个记录会包含函数在哪里调用、传入的参数等信息,this就是这个活动记录的一个属性,会在函数执行的过程中用到。简单一句话就是:谁去调用它,this就指向谁。
下面代码的清楚结果是什么?
function foo() {
console.log(this.a)
}
var obj = {
a: 2,
foo: foo
}
obj.foo()
关注点:谁调用的?谁调用,指向谁
输出结果为:2
function foo() {
console.log(this.a)
}
var obj2 = {
a: 42,
foo: foo
}
var obj1 = {
a: 2
obj2: obj2
}
obj1.obj2.foo()
输出结果为:42
调用foo方法的是obj1.obj2
需要注意的是代码调用和代码使用并不是一回事,以下面的代码为例
function foo() {
console.log(this.a)
}
var obj = {
a: 2,
foo: foo
}
var bar = obj.foo
var a = '我是全局属性a'
bar()
输出结果为:我是全局属性a
原因是?
var bar = obj.foo的foo后面没有加括号,所以不是调用,而是使用代码
function foo() {
console.log(this.a)
}
function deFoo(fn) {
fn()
}
var obj = {
a: 2,
foo: foo
}
var a = '我是全局变量a'
deFoo(obj.foo)
输出结果为:
我是全局变量a
function foo(){
console.log(this.a)
}
var obj = {
a:2,
foo:foo
}
var a= '我是全局变量a'
setTimeout(obj.foo,100)
输出结果为:我是全局变量a
思考一下:结果为什么是‘我是全局变量a’呢?
首先要了解一件事情,this的指向并不是不可改变的,最典型的情景就是像 call() 和 apply() 这样的方法可以将 this 引用到任何对象
call() 和 apply() 方法是预定义的 JavaScript 方法。
它们都可以用于将另一个对象作为参数调用对象方法。
var person1 = {
fullName: function() {
return this.firstName + " " + this.lastName;
}
}
var person2 = {
firstName:"Bill",
lastName: "Gates",
}
person1.fullName.call(person2); // 会返回 "Bill Gates"
5.this指向错乱问题及硬绑定方法
5.1.定时器
使用js中的定时器(setInterval,setTimeout),很容易会遇到this指向的问题。
var name = 'my name is window';
var obj = {
name: 'my name is obj',
fn: function () {
var timer = null;
clearInterval(timer);
timer = setInterval(function () {
console.log(this.name); //my name is window
}, 1000)
}
}
在这里,从this.name可以看出this的指向是window。
如果没有特殊指向,setInterval和setTimeout的回调函数中this的指向都是window。这是因为JS的定时器方法是定义在window下的。
5.2.事件绑定
在事件绑定的函数中有容易this指向发生改变的现象。
为了不让代码中的this指向错乱,我们可以采用硬绑定的形式
function foo(something) {
console.log(this.a, something)
return this.a + something
}
var obj = {
a: 2
}
var bar = function () {
//apply显式的修改掉了this的指向
return foo.apply(obj, arguments)
}
var b = bar(3)
console.log(b)
// 输出结果为: 5(2+3)
setTimeout(bar(4), 100)
// 输出结果为: 6(2+4)
//以上这种形式被称为硬绑定
硬绑定的方法除了apply,常用的还有call和bind
最终总结:
1.看看是不是new去调用一个函数,如果是就指向new创建出来的对象
2.看是不是通过call、apply、bind去绑定的,如foo.call(obj),如果是就指向了括号中的对象
3.函数是否在某个上下文对象中调用?如果是的话,函数就指向那个上下文对象
如,obj.foo(),谁去调用这个函数就指向谁
4.箭头函数中没有自己的this,在它里面使用的this是外部环境的
案例联系:
function identify() {
return this.name.toUpperCase()
}
function speak() {
var greeting = 'hello,我是' + identify.call(this)
console.log(greeting)
}
var p1 = {
name: 'xiaoHong'
}
var p2 = {
name: 'xiaoLi'
}
- identify.call(p1)
输出结果:xiaoHong - identify.call(p2)
输出结果:xiaoLi - speak.call(p1)
思路分析
首先,speak既然call p1了,那么speak里面的this都指向p1了
identify.call(this)就变成了identify.call(p1),
identify也call给p1了,那么identity里的this也都变成了p1
最终输出结果:hello,我是xiaoHong - speak.call(p2)
输出结果:xiaoLi
6.call()、apply()、bind()的联系和区别
希望使用某个上下文调用该函数,请使用 .bind() ,这在事件中很有用。 如果要立即调用函数,请使用.call() 或 .apply(),并修改上下文。
举例说明
假设你的数学老师要求你创建一个库并提交。你写了一个抽象的库,它可以求出圆的面积和周长:
var mathLib = {
pi: 3.14,
area: function(r) {
return this.pi * r * r;
},
circumference: function(r) {
return 2 * this.pi * r;
}
};
提交后,老师调用了它:
mathLib.area(2);
12.56
老师发现他给你要求是 pi 精确到小数点后 5 位数而你只精确到 2 位, 现在由于最后期限已过你没有机会提交库。 这里 JS的 call 函数可以帮你, 只需要调用你的代码如下:
mathLib.area.call({pi: 3.14159}, 2)
它会动态地获取新的 pi 值,结果如下:
12.56636
接下来看示例1
var name = "小王",age = 17
var obj={
name:"小张",
objAge:this.age,
myFun:function(){
console.log(this.name + "年龄" + this.age)
}
}
obj.objAge; //17
obj.myFun() //小张年龄undefined
示例2
var fav = "盲僧"
function shows(){
console.log(this.fav)
}
shows() //盲僧
比较一下这两者this 的差别,第一个打印里面的this 指向obj,第二个全局声明的shows()函数 this 指向的是window ;
如:
var name = "小王",age = 17
var obj={
name:"小张",
objAge:this.age,
myFun:function(){
console.log(this.name + "年龄" + this.age)
}
}
var db = {
name:"德玛",
age:99
}
obj.myFun.call(db); //德玛年龄99
obj.myFun.apply(db); //德玛年龄99
obj.myFun.bind(db)(); //德玛年龄99
以上出了bind 方法后面多了个 () 外 ,结果返回都一致!
由此得出结论,bind 返回的是一个新的函数,你必须调用它才会被执行
2,对比call 、bind 、 apply 传参情况下
var name = "小王",age = 17
var obj={
name:"小张",
objAge:this.age,
myFun: function (city,city2) {
console.log(this.name + "年龄" + this.age + "来自" + city + "去往" + city2)
}
}
var db = {
name:"德玛",
age:99
}
obj.myFun.call(db,'成都','上海'); //德玛 年龄 99 来自 成都去往上海
obj.myFun.apply(db,['成都','上海']); //德玛 年龄 99 来自 成都去往上海
obj.myFun.bind(db,'成都','上海')(); //德玛 年龄 99 来自 成都去往上海
obj.myFun.bind(db,['成都','上海'])(); //德玛 年龄 99 来自 成都,上海去往undefined
微妙的差距!
从上面四个结果不难看出
- call 、bind 、 apply 这三个函数的第一个参数都是 this 的指向对象,第二个参数差别就来了:
- call的参数是直接放进去的,第二第三第n个参数全都用逗号分隔,直接放到后面 obj.myFun.call(db,'成都', ... ,'string' );
- apply的所有参数都必须放在一个数组里面传进去 obj.myFun.apply(db,['成都', ..., 'string' ]);
- bind除了返回是函数以外,它 的参数和call 一样。
当然,三者的参数不限定是string类型,允许是各种类型,包括函数 、 object 等等!