您的位置:首页 > Web前端 > JavaScript

javascript中的“this”总结

2017-05-22 13:08 155 查看

javascript中的“this”

星期五的下午和同学ci完菠菜面,顺便买了6块钱的菠萝回宿舍开始“搞代码”这是在此博客写的第一篇文章,以前在wordpress写的文章有时间再转过来。大一大二没有写博客的习惯,倒是从大一折腾微信公众号,闲下来写写关于摄影的想法,经常拍了作品也往里放。大二下学期开始决心转计算机,还年轻梦想还是要有的,也谓之“不忘初心”。在学计算机的这一年中对我影响很大的是感悟出的一些学习方法和对知识的思考。我觉得和学本专业物理有所不同的是,对计算机知识的掌握程度不能出现“差不多理解了,似乎是这样的”。对接触到的本领域的知识要深度理解掌握,用起来才游刃有余。学计算机后对独立思考和总结开始重视了,继续加油,坚持把写博客当作一种对知识的巩固和深理解。

这一篇主要总结一下this:

- 调用位置

- 绑定规则

- 优先级

- 绑定例外

- 如何判断this

this是什么?

this是Javascript语言的一个关键字。

它代表函数运行时,自动生成的一个内部对象,只能在函数内部使用。

this既不指向函数自身也不指向函数的词法作用域,this的绑定在调用时发生,不在词法阶段产生,this指向什么只取决于函数在哪里被调用;

绑定规则:

一、默认绑定:

函数独立调用:函数直接调用不带任何修饰时,此时将应用默认绑定;

例如:

function foo(){
console.log(this.a);//输入1,此时this指向全局对象;
}
var a=1;
foo();


二、 隐式绑定:

var obj={
a:3,
foo:foo
}
function foo(){
console.log(this.a);
}
obj.foo();


foo函数的this,绑定到对象obj,obj对象中上下文调用了foo;

因此this.a===obj.a;

在隐式绑定时,要注意隐式丢失的情况:

隐式丢失1:

var obj={
a:3,
foo:foo
}
function foo(){
console.log(this.a);
}
var a=1;
var b=obj.foo;
b();


结果输出1,this指向了全局对象; 虽然b是obj.foo的一个引用,但是它引用的是foo函数本身,因此函数b()实际上是一个不带任何修饰的独立函数调用,因此应用了默认绑定;

隐式丢失2:

var obj={
a:3,
foo:foo
}
function b(fn){
fn();
}
function foo(){
console.log(this.a);
}
var a=1;
b(obj.foo);


结果输出1,this指向全局对象;参数传递是一种赋值行为,隐式赋值,所有传入的函数,也是foo函数本身;

隐式丢失3:

和情形2一样,只不过是把函数传入内置函数;

function foo(){
console.log(this.a);
}
var obj={
a:2,
foo:foo
}
var a=1;
setTimeout(obj.foo,1000);


三、 显式绑定:

每个函数都包含两个非继承来的方法:apply()、call();这两个函数的用途都是在特定的作用域中调用函数,实际上等于设置函数体内this对象的值

这两个方法可以接受两个参数,第一个是一个对象;通过foo.apply(obj)和foo.call(obj)方法将函数foo的this绑定到对象obj上。

例如:

function foo(){
console.log(this.a);
}
var obj={
a:2,
}
var a=1;
foo.apply(obj);


输出结果为2.

bind()方法会创建一个新函数,称为绑定函数.当调用这个绑定函数时,绑定函数会以创建它时传入bind方法的第一个参数作为this,传入bind方法的第二个以及以后的参数加上绑定函数运行时本身的参数按照顺序作为原函数的参数来调用原函数.

例如下面函数:

function foo(something){
console.log(this.a,something);
return this.a+something;
}
var obj={
a:2
};

var bar=foo.bind(obj);
var b=bar(3);
console.log(b);


首先要清楚:bar是一个新函数,是foo.bindd(obj)运行时产生的;

然后思考函数的内容和参数分别是什么?

它的内容和参数仍然和foo一样,只是里面的this对象指向obj;所以运行bar(3)时,结果是this.a+3,即2+3=5;

API调用的“上下文”也是一种显式绑定实现方式;

例如数组的迭代方法中的forEach();这种方法没有返回值,它接受两个参数:要在每一项上运行的函数,该函数运行的作用域。

函数传入3个三个参数:数组的值item、数组位置index、数组对象本身。

var num=[1,3,3,4,6,2,2];
var obj={
id:"owesome"
}
function foo(el){
console.log(this.id,el);
}
num.forEach(foo,obj);


输出结果:

owesome 1

owesome 3

owesome 4

owesome 6

owesome 2

硬绑定:解决绑定丢失问题

function foo(){
console.log(this.a);
}
var obj={
a:2,
}
var a=1;
var b=function(){
foo.apply(obj);
}
b();
setTimeout(b,100);
bar.call(window);


输出结果都是2;

四、new绑定

先思考下面代码,重点思考new的真正含义

function foo(){
this.a=2;
}
foo.b=3;
var bar=new foo();
console.log(bar.a);
console.log(bar.b);


输出结果:2,undefined

new 构造函数只是一些使用new操作符时被调用的函数,它们并不属于某一个类,也不会实例化一个类,甚至都不能说他们是一个特殊的函数类型。他们只是被new操作符调用的普通函数而已;

针对上述代码,new foo();只是创建了一个新对象,这个新对象绑定到foo()调用中的this上。

四种绑定的优先级(new绑定>显式绑定>隐式绑定>默认绑定)

当某一个调用位置可以应用多种绑定时,this到底绑定到哪里呢?

显示绑定优先于隐式绑定:

口说无凭,将隐式绑定和显式绑定加在同一个函数调用上做个实验试下:

function foo(){
console.log(this.a);
}
var obj_1={
a:1,
foo:foo
}
var obj_2={
a:2,
foo:foo
}
obj_1.foo.apply(obj_2);


结果输出2,证明显式绑定优先于隐式绑定;

new绑定优先于隐式绑定:

function foo1(a){
this.a=a;
}
var obj1={
a:1,
}
var foo2=foo1.bind(obj1);
var obj2=new foo2(2);
console.log(obj2.a);


输出结果为2,foo1.bind(obj1)的作用是将foo的this硬绑定给obj对象,并且将这个硬绑定后的foo函数当返回值赋值给foo2。

当obj2=new foo1(2)的作用是将以下函数的this对象复制给obj2。(这里我本人理解为对象的复制,不知道是否正确,我还没好好研究对象拷贝)

function foo(){
this.a=2;
}


如何判断this

step1: 函数是否在new中调用,如果是,this绑定的是新创建的对象;var a=new foo();

step2: 函数是否通过call、apply或者硬绑定调用,如果是,this绑定的是call、apply、bind

参数里面指定的对象;var a=call(obj)

step3: 函数是否在上下文调用中被绑定,如果是this绑定到上下文对象 var a=obj.foo();

step4: 以上都不是,则使用默认绑定,在严格模式下,绑定到undefined,否则绑定到全局对象。

var bar=foo();

绑定例外:

这块儿自己还没弄明白,待更新;
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  javascript