js中this的指向

    与其他语言相比,函数的 this 关键字在 JavaScript 中的表现略有不同,此外,在严格模式非严格模式之间也会有一些差别。在绝大多数情况下,函数的调用方式决定了this的值。this不能在执行期间被赋值,并且在每次函数被调用时this的值也可能会不同

全局上下文

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

console.log(this);// Window


var name = "Thresh";
console.log(window.name);// Thresh

函数上下文

在函数内部,this的值取决于函数被调用的方式。

因为下面的代码不在严格模式下,且 this 的值不是由该调用设置的,所以 this 的值默认指向全局对象。

function f1(){
    return this;

}//在浏览器中:f1() === window;  

然而,在严格模式下,this将保持他进入执行上下文时的值,所以下面的this将会默认为undefined

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

}
console.log(f2());// undefined

所以,在严格模式下,如果 this 没有被执行上下文(execution context)定义,那它将保持为 undefined

当函数作为对象里的方法被调用时,它们的 this 是调用该函数的对象。

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

var man = {
    name:"李狗蛋",
    fn:function(){
        console.log(this.name);  //李狗蛋
    }
}
man.fn();


下面来道笔试题

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

没错,最终输出的都是全局的 10

这里再次强调一点,this的指向在函数创建的时候是决定不了的,在调用的时候才能决定,谁调用的就指向谁,一定要搞清楚这个。

这道题是不是挺简单的,让我们提升点难度吧

function foo(){
    console.log(this.a)
}
var a = 3;
var obj = {
    a: 2,
    foo: foo
};
obj.foo(); // 输出2,因为是obj调用的foo,所以foo的this指向了obj,而obj.a = 2

如果存在多次调用,对象属性引用链只有上一层或者说最后一层在调用位置中起作用,如:

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

这里有一个最常见的this绑定问题就是被隐式绑定的函数会丢失绑定对象,我们把上面的题目稍微修改下

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

这里的答案是32因为barobj.foo的一个引用,但是实际上,它引用的是foo函数本身,因此此时的bar()其实是一个不带任何修饰的函数调用,因此应用了默认绑定

为了让this确认指向,可以利用call、apply、bind、new绑定等

apply方法

/*定义一个人类*/
function Person(name, age) {
    this.name = name;
    this.age = age;
}
/*定义一个学生类*/
function Student(name, age, grade) {
    Person.apply(this, arguments);
    this.grade = grade;
}
//创建一个学生类
var student = new Student("lisi", 18, "一年级");
alert("name:" + student.name + "\n" + "age:"

+ student.age + "\n" + "grade:" + student.grade);
//name:lisi age:18 grade:一年级

分析: Person.apply(this,arguments);

this:在创建对象在这个时候代表的是student

arguments:是一个数组,也就是[“lisi”,”18”,”一年级”];

也就是:student去执行Person这个类里面的内容,Person这个类里面存在this.name等之类的语句,这样就将属性创建到了student对象里面

Studen函数里面可以将apply中修改成如下:

Person.call(this,name,age);

call与apply方法的异同

call()

function.call(obj[,arg1[, arg2[, [,.argN]]]]])

· 调用call的对象必须是个函数function

· call的第一个参数将会是function改变上下文后指向的对象,也就是上面例子里的小刚,也就是上上面例子里的老婆大人,如果不传,将会默认是全局对象window 

· 第二个参数开始可以接收任意个参数,这些参数将会作为function的参数传入function

· 调用call的方法会立即执行

apply()

function.apply(obj[,argArray])

call方法的使用基本一致,但是只接收两个参数,其中第二个参数必须是一个数组或者类数组,这也是这两个方法很重要的一个区别

bind方法

ECMAScript 5 引入了 Function.prototype.bind。调用f.bind(someObject)会创建一个与f具有相同函数体和作用域的函数,但是在这个新函数中,this将永久地被绑定到了bind的第一个参数,无论这个函数是如何被调用的。

function f() {
    return this.a;
}
var g = f.bind({a: "花花"});
console.log(g()); // 花花
var h = g.bind({a: 'yoo'}); // bind只生效一次!
console.log(h()); // 花花

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值