this学习笔记

结论:this 的指向,是在调用函数时根据执行上下文所动态确定的。

执行上下文:

每次当控制器转到可执行代码的时候,就会进入一个执行上下文。执行上下文可以理解为当前代码的执行环境,它会形成一个作用域。JavaScript中的运行环境大概包括三种情况。

  • 全局环境:JavaScript代码运行起来会首先进入该环境
  • 函数环境:当函数被调用执行时,会进入当前函数中执行代码
  • eval(不建议使用,可忽略)

 

1 默认绑定规则

全局下默认指向window

console.log(this === window);//true
//console.log({} === {});//false,因为比较的是地址


//函数的独立调用,函数定义在window下
function test(){
    console.log(this === window);//true
}
test();//等价于window.test();

2 隐式绑定规则

谁调用就指向谁

var a = 0;
var obj = {
    a:2.
    foo:function test(){
        console.log(this);//obj.foo();中this指向obj
        function test(){
            console.log(this);//每个函数执行会产生自身对应的this,两个函数的this是不同的,但指向可能会相等
        }
        test();//函数的独立调用,所以这里this指向window
    }
}

函数立即执行

function test(){
    console.log(this);
}
test();//window
//等价于
(function(){
    console.log(this);//window
})();
//或者等价于
(function(){
    console.log(this);//window
}());

闭包

var a = 0;
var obj = {
    a:2.
    foo:function (){
        function test(){
            console.log(this);
        }
        return test;
        //闭包易于理解的定义:当函数执行时,导致函数被定义,并抛出(return)
    }
}
obj.foo()();//obj.foo()等价于test,所以这个语句等价于test(),结果参考函数立即执行,为window

2.1 例外

2.1.1 变量赋值(隐式丢失)

var a = 0;
function foo(){
    console.log(this);
}

var obj = {
    a:2,
    foo:foo
}

var bar = obj.foo;//等价于foo
//方法被重写/赋值时,会存在隐式丢失
bar();//在这里函数才开始执行,本质上是函数独立调用,指向window

2.1.2 参数赋值

var a = 0;
function foo(){
    console.log(this);
}

function bar(fn){
    fn();
}

var obj = {
    a:2,
    foo:foo
}
//预编译的过程中,实参被赋值为形参;(值的拷贝的过程,浅拷贝)
bar(obj.foo);//window

 2.2 改变this指向

var a = 0;
function foo(){
    console.log(this);
}

var arr=[1,2,3];

//api 接口中指明的;
//回调函数是这里的子函数
arr.forEach(function(item,idx,arr){
    console.log(this);
},obj)//这里的obj指明了this是什么,如果没有则指向window
arr.sort(function(a,b){
    console.log(this);
    return a-b;
})

//父函数是有能力决定子函数的this指向的
var obj = {
    a:2,
    foo:foo
}

3 显式绑定:call apply bind

var a = 0;
function foo(a,b,c){
    console.log(a,b,c);
    console.log(this);
}

var obj = {
    a:2,
    foo:foo
}

var bar = obj.foo;//等价于foo
//方法被重写/赋值时,会存在隐式丢失
//bar();//window

obj.foo(1,2,3);
bar.call(obj,1,2,3);//call(绑定对象,参数1,参数2,参数3,...)
bar.apply(obj,[1,2,3]);//apply(绑定对象,数组)
bar.bind(obj)(1,2,3);//bind不会直接执行,返回一个函数,要执行再加一个();

 其他各种情况:

var a = 0;
function foo(a,b,c){
    console.log(this);
}

var obj = {
    a:2,
    foo:foo
}

var bar = obj.foo;//等价于foo
//方法被重写/赋值时,会存在隐式丢失
//bar();//window

obj.foo(1,2,3);
bar.call(1,2,3);//this为Number{1}这个对象
bar.call(false,2,3);//this为Boolean{false}这个对象
bar.call(undefined,2,3);//不是对象,绑定失败,默认绑定window
bar.apply(null,[1,2,3]);//不是对象,绑定失败,默认绑定window
bar.bind(obj)(1,2,3);//bind不会直接执行,返回一个函数,要执行再加一个();

4 new 绑定

function Person(){
    //var this  = {};
    //this.a = 1;
    //return this;
    return 1;
}
//如果构造函数中return了引用值,则this指向这个引用值,但ES6规定构造函数一般不主动设定返回值
var person = new Person();//this指向构造函数实例化后的对象
console.log(person);

var obj = {
    a:1
};

//立即执行函数+call
(function(){
    console.log(this);
}).call(obj)//obj
//无意义

5 优先级

new>显式>隐式>默认

6 例子

var name = '222';
var a = {
    name:'111',
    say:function(){
        console.log(this.name);
    }
}

var fun = a.say;
fun();//window//222
a.say();///a//111

7 箭头函数的this

箭头函数的this指向是由外层作用域(父环境)决定的,它自身不存在this

所有绑定规则不适用于箭头函数

  • 默认绑定规则(独立调用)对箭头函数无效
  • 显式绑定规则对箭头函数无效
  • 隐式绑定规则对箭头函数无效
  • 箭头函数不能作为构造函数,所以new规则也不能应用于箭头函数

8 复杂的例子

var name = 'window'
var obj1 = {
    name:'1',
    fn1:function(){
	console.log(this.name)
    },
    fn2:()=> console.log(this.name),
    fn3:function(){
	return function(){
	    console.log(this.name)
	}
    },
    fn4:function(){
	return ()=>console.log(this.name)
    }
}
var obj2 = {
    name:'2'
};

obj1.fn1();//1
obj1.fn1.call(obj2);//2

obj1.fn2();//1->error   window->correct
obj1.fn2.call(obj2);//1->error   window->correct

obj1.fn3()();//window
obj1.fn3().call(obj2);//2
obj1.fn3.call(obj2)();//window

obj1.fn4()();//window->error 1->correct
obj1.fn4().call(obj2);//window->error 1->correct
obj1.fn4.call(obj2)();2
function Foo(){
    getName = function(){alert(1);};
    return this;
}
Foo.getName = function (){alert(2);};
Foo.prototype.getName = function(){alert(3);};
var getName = function(){alert(4);};
function getName(){alert(5);}

//请写出以下输出结果

Foo.getName();//2
getName();//4
Foo().getName();4->error 1->correct
//因为Foo函数里的getName方法没有使用var,所以是全局方法,所以window下的getName被改变了
getName();//4->error 1->correct

new Foo.getName();//1   2
new Foo().getName();//1    2
new new Foo().getName();//1    2

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值