js this 详解

this详解

 你可能遇到过这样的 JS 面试题:

{

var obj = {

foo: function () {

console.log(this)

}

}

var bar = obj.foo

obj.foo(); // 打印出的 this 是 obj

bar(); // 打印出的 this 是 window

}

 这个原因是因为“Javascript中this永远是指向调用它的对象”

 函数调用

 函数的三种调用方式

func(p1, p2)

obj.child.method(p1, p2)

func.call(context, p1, p2) // 先不讲 apply

 前面两种是常见的调用方式,但是第三种调用形式,才是正常调用形式:

{

func(p1, p2)

// 等价于

func.call(undefined, p1, p2)



obj.child.method(p1, p2)

// 等价于

obj.child.method.call(obj.child, p1, p2)

}

其他两种都是语法糖,可以等价地变为 call 形式:

 至此我们的函数调用只有一种形式:

func.call(context, p1, p2)

这样,this 就好解释了

 this,就是上面代码中的 context。就这么简单。

 this 是你 call 一个函数时传的 context,由于你从来不用 call 形式的函数调用,所以你一直不知道。

先看 func(p1, p2) 中的 this 如何确定:

 当你写下面代码时

{

function func() {

console.log(this)

}

func();

 等价于

func.call(undefined) // 可以简写为 func.call()

}

 按理说打印出来的 this 应该就是 undefined 了吧,但是浏览器里有一条规则:

 如果你传的 context 就 null 或者 undefined,那么 window 对象就是默认的 context(严格模式下默认 context 是 undefined)

 因此上面的打印结果是 window。

 如果你希望这里的 this 不是 window,很简单:

{

func.call(obj) // 那么里面的 this 就是 obj 对象了

}

 再看 obj.child.method(p1, p2) 的 this 如何确定

{

var obj = {

foo: function () {

console.log(this)

}

}

obj.foo()

}

 按照「转换代码」,我们将 obj.foo() 转换为

{

obj.foo.call(obj)

}

好了,this 就是 obj。搞定。

 回到题目:

{

var obj = {

foo: function () {

console.log(this)

}

}

var bar = obj.foo

obj.foo() // 转换为 obj.foo.call(obj),this 就是 obj

bar()

}

/转换为 bar.call(); 由于没有传 context;所以 this 就是 undefined;最后浏览器给你一个默认的 this —— window 对象

语法

{

function fn() { console.log(this) }

var arr = [fn, fn2]

arr[0]() // 这里面的 this 又是什么呢?

}

我们可以把 arr[0]() 想象为arr.0() ,虽然后者的语法错了,但是形式与转换代码里的 obj.child.method(p1, p2) 对应上了,于是就可以愉快的转换了: arr[0](),假想为arr.0(),然后转换为 arr.0.call(arr),那么里面的 this 就是 arr 了:)

总结:

 this 就是你 call 一个函数时,传入的 context。

 如果你的函数调用形式不是 call 形式,请按照「转换代码」将其转换为 call 形式。

 

1 this的四种用法

在Javascript中this总是指向调用它所在方法的对象。因为this是在函数运行时,自动生成的一个内部对象,只能在函数内部使用。

 1.1在一般函数方法中使用 this 指代全局对象

{

function test() {

this.x = 1;

console.log(this.x);

console.log(this);

};

test();

console.log(window.x)

}

 1.2作为对象方法调用,this 指代上级对象

{

function test() {

console.log(this.x);

console.log(this)

}

var o = {};

o.x = 1;

o.m = test;

o.m(); // 1

}

1.3作为构造函数调用,this 指代new 出的对象

{

function test() {

this.x = 1;

console.log(this);

}

var o = new test();

console.log(o.x); // 1

运行结果为1。为了表明这时this不是全局对象,我对代码做一些改变:

var x = 2;

function test2() {

this.x = 1;

console.log(this);

}

var o = new test2();

console.log(x); //2

}

 1.4 apply 调用 ,apply方法作用是改变函数的调用对象,此方法的第一个参数为改变后调用这个函数的对象,this指代第一个参数

{

var x = 0;

function test() {

console.log(this.x);

}

var o = {};

o.x = 1;

o.m = test;

o.m.apply(); //0

//apply()的参数为空时,默认调用全局对象。因此,这时的运行结果为0,证明this指的是全局对象。如果把最后一行代码修改为

o.m.apply(o); //1

}
{

function fn(num) {

console.log("fn: " + num);

// count用于记录fn的被调用次数

this.count++;

console.log(this)

}

fn.count = 0;

var i;

for (i = 0; i < 10; i++) {

if (i > 5) {

fn(i);

}

}

console.log(fn.count); //0

console.log(this.count); //NaN

}

 2.箭头函数的简单讲解

 资料上说的箭头函数内部是没有this的,也就是说,箭头函数里面的this会继承自外部的this,下面有个例子,用来详细说明下:

{

var x = 11;

var obj = {

x: 22,

y: this,//window

say: () => {

console.log(this.x);

}

}

obj.say();

//输出的值为11

console.log(obj.y);

//输出的值为window对象

}

obj对象中的this指代的就是window,也就是全局环境,因为箭头函数中的this就会就近找到上一个对象中this所指代的对象,

 从以上例子可以看出来,obj内部属性y就为obj内部this指代的对象,输出是window。

 看看下面这个例子

{

var a = 11

function test1() {

this.a = 22;

let b = function () {

console.log(this.a);

};

b();

}

var x = new test1();

//输出11

}

 

你可能感兴趣的:(js基本知识,js,es6)