关于this

来源:互联网 发布:常熟淘宝培训南天老师 编辑:程序博客网 时间:2024/05/03 11:41

使用this可以减少传入上下文对象,可以隐式传递一个对象引用。使API简洁而复用,可以自动引用合适的上下文对象。


【要注意的几个点】

1. this不一定指向自身;2. this不一定指向函数作用域(因为作用域无法通过js代码访问,它存在js引擎内部);3. this是在运行时(函数被调用时)绑定的,不是编写代码时绑定。this的绑定取决于函数的调用位置,不是函数声明的位置;4. 不能通过this来引用一个词法作用域内部的东西

【找this的指向】

分析调用栈(为了到达当前执行位置所调用的所有函数),找到当前正在执行的函数的前一个调用,即调用栈的第二个元素。因为函数被调用时,会创建一个活动记录(执行上下文)。该活动记录包括(函数的调用栈、传入的参数、函数的调用方法……)

[方法]:在代码前插入一条debugger语句,在开发者工具中查看call stack中的第二个元素,就是this的调用位置.
function first(){    //当前调用栈first    //当前的调用位置是全局作用域    console.log("first");    second();//second的调用位置}function second(){    //当前调用栈first->second    //当前的调用位置是first    console.log("second");    third();//third的调用位置}function third(){    //当前调用栈first->second->third    //当前的调用位置是second    console.log("third");}//first的调用位置first();//firstsecondthird

【四条this规则】:

1.默认绑定(绑定到全局对象),但严格模式下this会绑定到undefin
ed:
【例子】:不带任何修饰的函数调用

function example(){    console.log(this.a);}var a="karine";example(); //karine

2.隐式绑定
(在一个对象内部包含一个指向函数的属性,通过该属性间接地引用函数,从而把this间接地绑定到该对象上。)

function example(){    console.log(this.a);}var obj={    a:"karine",    example:example};obj.example(); //karine

在对象属性引用链中,只有最顶层(最后一层)会影响调用位置。

function example(){    console.log(this.a);}var obj1={    a:"karine",    example:example};var obj2={    a:"wu",    obj1:obj1};obj2.obj1.example(); //karine

当函数引用有上下文对象时,函数里的this绑定在这个上下文对象上。
但是这种情况可能会出现“隐式丢失”,即丢失绑定的对象,应用默认绑定(全局对象/undefinded):

1. 将函数引用赋值给一个新变量,然后执行。var obj3 = obj1.example; obj3(); //全局or undefined实际上obj3引用的是example函数本身,因此this还是指向全局/undefined2. 或者是调用回调函数的函数修改了thisfunction test(fn){    fn();}test(obj1.example);  //全局or undefined实际上,参数传递也是一种赋值,只不过是隐式赋值。所以道理同上。也会指向全局。

3.显式绑定
(在对象上强制调用函数,可以使用call(对象)、apply(对象)方法,会把形参里的对象绑定到this上,接着在调用函数时指定这个this。如果传入的参数为原始值(string、number、boolean),该原始值会自动转为其对象形式(new String()、new Number()、new Boolean()),这通常被称为“装箱”)

function example(){    console.log(this.a);}var obj = {    a:"karine"};example.call(obj); //karineexample.apply(obj);//karinevar o = example.bind(obj);o(); //karine“硬绑定”bind 的this不会被显示or隐式绑定修改。

4.new绑定
在js中,构造函数只是使用new操作符是被调用的普通函数而已,不属于某个类,也不会实例化一个类。使用new调用函数时,会自动执行以下操作:

1.创建一个全新的对象2.该对象会被执行[[prototype]]连接3.该对象会绑定到函数调用的this4.若函数没有返回其他对象,new表达式中的函数调用会自动返回该对象。
function examplea){    this.a=a;}var obj4 = new example(“karine”);console.log(obj4.a);//“karine”

【四种this绑定方法的优先级】

new绑定 > 显式绑定 >隐式绑定 > 默认绑定

【例外】:
1.null、undefined作为this的绑定对象传入call、apply、bind时,会被忽略,实际应用的是默认绑定(全局对象)

function example(){    console.log("a:"+this.a);}var a = "karine";example.call(null); //a:karine

传入null的情况:
(1)使用apply来展开一个数组
(2)使用bind进行柯里化

function example(a,b){    console.log("a:"+a+“,b:”+b);}//使用apply来展开一个数组example.apply(null,[2,3]); //a:2,b:3//使用bind进行柯里化(预先设置一些参数)var o = example.bind(null,2); o(3);//a:2,b:3

若想避免不必要的this绑定,可以使用ES6的…操作符来代替apply()

example.apply(null,[2,3]) ===  example(…[2,3])

为了安全,若想忽略this绑定,可以给this传入一个空的非委托对象Φ (“Object.create(null)”),不会产生任何副作用,因为this会限制在这个空对象中,不会对全局对象产生任何影响。
Object.create(null)和{}很像,但是不会创建object.prototype,所以比{}“更空”

var Φ = Object.create(null);example.apply(Φ,[2,3]); //a:2,b:3var o = example.bind(Φ,2); o(3); //a:2,b:3

2.间接引用(经常在赋值时发生),会应用默认绑定。

3.ES6中 “=>”定义的箭头函数不使用this的四种标准规则。而是根据外层作用域来决定this。箭头函数的绑定无法修改。

function example(){    return(a)=>{        console.log(this.a);    }}var obj1={a:2};var obj2={a:3};var test = example.call(obj1);test.call(obj2); //2

由于example()的this绑定到obj1,所以test中引用箭头函数的this也会绑定到obj1。


总结】:

1.找到this的调用位置
2.根据四条规则判定this的绑定对象:

(1)new:绑定到新创建的对象(2)call、apply、bind:绑定到指定的对象(3)上下文对象:绑定到该上下文对象(4)默认:全局或者undefined(严格模式下)

3.箭头函数根据当前的词法作用域来决定this
4.有些调用可能无意中使用默认规则,可以使用一个空对象Object.create(null)忽略this绑定,来保护全局对象

原创粉丝点击