this

this的绑定规则

	函数中的this指向
	普通函数中的this是谁?—window
	对象.方法中的this是谁?-------该方法所属对象
	定时器中的this是谁?—window
	构造函数中的this是谁?—当前的实例对象
	原型对象方法中的this是谁?—实例对象

1.默认绑定

function foo(){
	var a = 1; 
	console.log(this.a) //10 
var a = 10;	
foo();

像这种直接使用而不带任何修饰的函数调用,默认且只能应用默认绑定
默认绑定到window上,严格模式下是undefined

函数独立调用,函数内部的this也是指向window

function fn (){
	console.log(this);  //window
}
fn();
var obj = {
	a = 2;
	foo:function(){
		console.log(this) //这个指向当前的对象 obj
					//函数当作对象的方法来调用时,this指向该函数的对象	
		function test (){
			console.log(this) //window
		}		//这个test函数实在函数内独立调用,所以跟外面没关系,
		test();		//他就指向window
	}
}
obj.foo();

2.隐式绑定

//当函数当作方法来调用,this指向了直接对象,就是谁调用它就this就指向谁
function foo(){
	console.log(this.a)
}
var obj = {
	a:10,
	foo:foo,
	obj2:{
		a:2,
		foo:foo
	}
}

//调用的是全局变量相当于打印window.a 
//但是全局里没有a变量 所以就打印undefined
foo(); //undefined
//obj调用的foo()函数,所以this就直接指向obj
obj.foo(); 	//10
//obj2调用的foo()函数,所以this就直接指向obj2
obj.obj2.foo(); //2

2.1隐式丢失

隐式丢失就是指被绑定的函数丢失了绑定对象,从而默认绑定window

var a = 0 
function foo(){
	console.log(this.a)
}
var obj = {
	a : 1;
	foo: foo
}
var bar = obj.foo(); //帮foo()方法赋值到 bar变量上
bar(); //打印:0   相当于是window.a()	

内置函数setTimeout()hh额setInterval()第一个参数的回调函数中的this指向的是window

setTimeout(function(){
	console.log(this)  //window
},1000)
var a = 10
function foo(){
	console.log(this.a)
}
var obj = {
	a:1,
	foo:foo
}
setTimeout(obj.foo,1000)  //10

3.显示绑定
//call(),apply(),bind()把对象绑定上this上,叫做显示绑定

var a = 0;
function foo(){
	console.log(this.a)
}
var obj = {
	a:2
}
foo() //0
foo.call(obj) //2
foo.apply(obj) //2
var fn = foo.bind(obj)
fn() //2  bind()有个返回值,需要定义一个变脸返回才行

4.new绑定

function foo(){
    this.a = 10;
    console.log(this);
}
foo();                    // window对象
console.log(window.a);    // 10   默认绑定

var obj = new foo();      // foo{ a : 10 }  创建的新对象的默认名为函数名
                          // 然后等价于 foo { a : 10 };  var obj = foo;
console.log(obj.a);       // 10    new绑定

this绑定优先级
new 绑定 > 显示绑定 > 隐式绑定 > 默认绑定

call,apply,bind的区别
call从第二个参数开始所有的参数都是原函数的参数
apply只接受两个参数,且第二个参数必须是数组,这个数组代表原函数的参数列表
bind只有一个参数,且不会立即执行,只是将一个值绑定到函数的this上,并将绑定好的函数返回

总结:

1.如果函数被new 修饰

this绑定的是新创建的对象,例:var bar = new foo(); 函数 foo 中的 this 就是一个叫foo的新创建的对象 , 然后将这个对象赋给bar , 这样的绑定方式叫 new绑定 .

2.如果函数是使用call,apply,bind来调用的

this绑定的是 call,apply,bind 的第一个参数.例: foo.call(obj); , foo 中的 this 就是 obj , 这样的绑定方式叫 显性绑定 .

3.如果函数是在某个 上下文对象 下被调用

this绑定的是那个上下文对象,例 : var obj = { foo : foo }; obj.foo(); foo 中的 this 就是 obj . 这样的绑定方式叫 隐性绑定 .

4如果都不是,即使用默认绑定

例:function foo(){…} foo() ,foo 中的 this 就是 window.(严格模式下默认绑定到undefined).
这样的绑定方式叫 默认绑定 .

面试题:

var x = 10;
var obj = {
    x: 20,
    f: function(){
        console.log(this.x);    // 20
                                // 典型的隐性绑定,这里 f 的this指向上下文 obj ,即输出 20
        function foo(){ 
            console.log(this.x); 
            }
        foo();       // 10
                     //闭包内的this指向的也是window
    }
};
obj.f();            
var x = 10;
var obj = {
    x: 20,
    f: function(){ console.log(this.x); }
};
var bar = obj.f;
var obj2 = {
    x: 30,
    f: obj.f
}
obj.f();    // 20
            //有上下文,this为obj,隐性绑定
bar();      // 10
            // 默认绑定  ( obj.f 只是普通的赋值操作 )
obj2.f();   //30
            //不管 f 函数怎么折腾,this只和 执行位置和方式有关
            
function foo() {
    getName = function () { console.log (1); }; 
            //这里的getName 将创建到全局window上
    return this;
}
foo.getName = function () { console.log(2);};   
        //这个getName和上面的不同,是直接添加到foo上的
foo.prototype.getName = function () { console.log(3);}; 
        // 这个getName直接添加到foo的原型上,在用new创建新对象时将直接添加到新对象上 
var getName = function () { console.log(4);}; 
        // 和foo函数里的getName一样, 将创建到全局window上
function getName () { console.log(5);}    
        // 同上,但是这个函数不会被使用,因为函数声明的提升优先级最高,所以上面的函数表达式将永远替换
        // 这个同名函数,除非在函数表达式赋值前去调用getName(),但是在本题中,函数调用都在函数表达式
        // 之后,所以这个函数可以忽略了
        
        // 通过上面对 getName的分析基本上答案已经出来了

foo.getName ();                // 2
                               // 下面为了方便,我就使用输出值来简称每个getName函数
                               // 这里有小伙伴疑惑是在 2 和 3 之间,觉得应该是3 , 但其实直接设置
                               // foo.prototype上的属性,对当前这个对象的属性是没有影响的,如果要使
                               // 用的话,可以foo.prototype.getName() 这样调用 ,这里需要知道的是
                               // 3 并不会覆盖 2,两者不冲突 ( 当你使用new 创建对象时,这里的
                               // Prototype 将自动绑定到新对象上,即用new 构造调用的第二个作用)
                               
getName ();                    // 4 
                               // 这里涉及到函数提升的问题,不知道的小伙伴只需要知道 5 会被 4 覆盖,
                               // 虽然 5 在 4 的下面,其实 js 并不是完全的自上而下,想要深入了解的
                               // 小伙伴可以看文章最后的链接
                               
foo().getName ();              // 1 
                               // 这里的foo函数执行完成了两件事, 1. 将window.getName设置为1,
                               // 2. 返回window , 故等价于 window.getName(); 输出 1
getName ();                    // 1
                               // 刚刚上面的函数刚把window.getName设置为1,故同上 输出 1
                               
new foo.getName ();            // 2
                               // new 对一个函数进行构造调用 , 即 foo.getName ,构造调用也是调用啊
                               // 该执行还是执行,然后返回一个新对象,输出 2 (虽然这里没有接收新
                               // 创建的对象但是我们可以猜到,是一个函数名为 foo.getName 的对象
                               // 且__proto__属性里有一个getName函数,是上面设置的 3 函数)
                               
new foo().getName ();          // 3
                               // 这里特别的地方就来了,new 是对一个函数进行构造调用,它直接找到了离它
                               // 最近的函数,foo(),并返回了应该新对象,等价于 var obj = new foo();
                               // obj.getName(); 这样就很清晰了,输出的是之前绑定到prototype上的
                               // 那个getName  3 ,因为使用new后会将函数的prototype继承给 新对象
                               
new new foo().getName ();      // 3
                               // 哈哈,这个看上去很吓人,让我们来分解一下:
                               // var obj = new foo();
                               // var obj1 = new obj.getName();
                               // 好了,仔细看看, 这不就是上两题的合体吗,obj 有getName 3, 即输出3
                               // obj 是一个函数名为 foo的对象,obj1是一个函数名为obj.getName的对象
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值