聊聊JavaScript中的this

this

在这里插入图片描述

一、上几道题开开胃

1 🤔

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

var say = obj.say;

obj.say();  
say();  

在这里插入图片描述
答案

a
undefined


在对象里面调用被声明成独立的全局引用 是不一样的

obj.say(); 就是在 obj 对象里面查找 say 函数,执行环境是 obj 对象,this 指向 objthis.name 就是 obj 里面的 name

var say = obj.say; 这时候 say 被声明成全局函数,在全局作用域下没有 name 这个变量,输出 undefined;如果在全局下给 name 赋值一个值,say() 就指向那个值了


注:这类题对应下文中【二、理解两种函数调用的写法差异】,是阮一峰教程中的经典例子


2 🤨

var a = 1;

function foo(){
    console.log(this.a)
}

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

obj.foo();

在这里插入图片描述
答案

2

foo 是在 obj 里被调用的,foo 的地址被指向 obj"foo" 属性,即 foo 函数的环境就是 obj 对象


3 😤

var length = 10;

function fn () {
    console.log(this.length);
}
 
var obj = {
    length: 5,
    method: function (fn) {
        fn();
    }
};
 
obj.method(fn);

在这里插入图片描述
答案

10


在外面的全局变量 length10,在 obj 对象里面的 length5

这里 fn 是被当做 method 的参数传入的,但是调用它的不是 obj 对象,而是 window,所以输出全局变量 10

如果把 obj 改造成加上 call 的绑定 this,输出的结果就不一样了

var obj = {
    length: 5,
    method: function (fn) {
        // 在这里用call 将 this 指向 obj 自己
        fn.call(this);
    }
};

输出对象内部的 5


二、理解两种函数调用的写法差异

from 阮一峰的网络日志

学懂 JavaScript 语言,一个标志就是理解下面两种写法,可能有不一样的结果。

var obj = {
  foo: function () {}
};

var foo = obj.foo;

// 写法一
obj.foo()

// 写法二
foo()

这两种写法的结果是不一样的

对于obj.foo()来说,foo运行在obj环境

对于foo()来说,foo运行在全局环境


三、this 是什么

this 是 JavaScript 中的一个关键字

被运用于函数体内,依赖于函数调用的上下文条件,与函数被调用的方式有关

this 的指向,完全是由函数被调用的调用者来决定的

this 是在运行时绑定,而与编写时的绑定无关

this 可以说是一种简洁函数表达,优化值的传递的一种方法,不可能每次都给函数具体的传值参数,会有很多隐式的引用形式的数据,用 this 表达更简洁

🧁 this 指向的就是函数运的执行环境

在这里插入图片描述

JavaScript 允许在函数体内部,引用当前环境的其他变量。

所以需要有一种机制,能够在函数体内部获得当前的运行环境(context)。

所以,this 就出现了,它的设计目的就是在函数体内部,指代函数当前的运行环境


稍微地总结一下:

  1. 独立函数调用时,this 指向全局对象(window);如果使用严格模式,this 绑定至 undefined
  2. 函数 this 是指向调用者

四、几种不同函数不同的 this 指向

一共6种函数

1️⃣普通函数

//定义
function fn(){
	console.log('hello js');
}

//调用
fn();
fn.call();

this 指向 window


2️⃣对象的方法

//定义
var ob = {
    say: function(){
        console.log('hello js');
    }
}

//调用
ob.say();

this 指向对象


3️⃣构造函数

//定义
function Run(){};

//调用
var a = new Run();

this 指向(a)实例对象


4️⃣绑定事件函数

//定义
btn.onclick = function(){};

//调用
点击就可以调用这个函数

this 指向函数的调用者(btn对象)


5️⃣定时器函数

//定义
setInterval(function(){}, 1000);

//调用
函数是定时器自动1秒钟调用一次

this 指向 window


6️⃣立即执行函数

//定义
(function(){
    console.log('hello js');
})();

//调用
立即执行函数是自动调用

this 指向 window


五、箭头函数中的 this

箭头函数使得 this“动态”变成“静态”(固定)

箭头函数体内的 this 对象,就是 定义 时所在的对象,而不是 使用 时所在的对象。

普通函数的 this,是运行时的对象。


一个例子

var id = 10;

// 普通函数
function foo() {
  setTimeout(function() {
    console.log(this.id);
  }, 100);
}

// 箭头函数
function foo1() {
  setTimeout(() => {
    console.log(this.id);
  }, 100);
}

foo();  // 10
foo1();  // 10

当没有其他条件值的参与的时候,调用两个函数。

普通函数的 this 在运行时绑定,定时器的 this 指向 window,即全局变量 id = 10

箭头函数的 this 在定义时绑定,定义时在函数作用域内找不到 id,跳到外层找到全局变量 id = 10


现在我们加上 call 绑定

var id = 10;

// 普通函数
function foo() {
  setTimeout(function() {
    console.log(this.id);
  }, 100);
}

// 箭头函数
function foo1() {
  setTimeout(() => {
    console.log(this.id);
  }, 100);
}

var obj = {
    id: 100
}

foo.call(obj);  // 10
foo1.call(obj);  // 100

把两个函数绑定给了 obj 对象

对于箭头函数,让 this 绑定了定义时所在的作用域 – obj,所以输出的 idobj 对象里的 100

普通函数,运行时定时器还是在全局作用域上,输出的还是全局变量 id = 10


六、apply call bind 的用法

apply

调用一个具有给定 this 值的函数,改变函数的 this 指向

以数组(伪数组)的形式传递

function.apply(thisArg, [argsArray])
  • thisArg:在 func 函数运行时使用的 this

  • argsArray:一个数组或者类数组对象,其中的数组元素将作为单独的参数传给 func 函数

具体写

var f = function() {
    console.log(this.x)
}

var x = 1;

f(); // 1   全局变量 x 的1

var b = {
    x: 2,
    y: 4,
    z: 8
}

f.apply(b, [x]);   // 2

this 绑到第一个参数上,一般以对象的形式传输

把参数用得更透彻一些

var array = ['a', 'b'];
var elements = [0, 1, 2];
array.push.apply(array, elements);

// array: ["a", "b", 0, 1, 2]

求数组最大值 最小值

Math.max 不能对数组进行操作,只能加上…

var arr = [1, 3, 13, 34, 6];
var max = Math.max(...arr);
console.log(max)  // 34

使用 apply

var arr = [1,3,13,34,6];
var max = Math.max.apply(Math, arr);
var min = Math.min.apply(Math, arr);
console.log(max, min);

call

调用函数,改变函数内的 this 指向

call 的主要作用可以实现继承

接受的是参数列表

function.call(thisArg, arg1, arg2, ...)
  • thisArg:在 function 函数运行时使用的 this 值。
  • arg1, arg2, …:指定的参数列表。

一个简单的例子,打印名字

var name = "none";

function identify() {
    return this.name.toUpperCase();
}

var me = {
    name: "Kyle"
};

var you = {
    name: "Reader"
};

identify();  // "NONE"
identify.call(me); // "KYLE"
identify.call(you); // "READER"

bind

不会调用函数,改变函数内部 this 指向,且会产生一个新的函数

function.bind(thisArg, arg1, arg2...)
  • thisArg:在 function 函数运行时指定的 this

  • arg1, arg2:传递的其他参数

具体写

关于定时器中的 this 指向

var name = 1;

var myObj = {
    name: 2,
    showName: function () {
        console.log(this.name);
    }
}

setTimeout(myObj.showName, 1000) // 输出1

定时器上下文中的 this 会被设置为全局 window

(如果是严格模式,会被设置为 undefined

所以输出的 this.name 是全局的 name,与 myObj 对象无关了

通过 bind 改变 this 绑定,绑定到 myObj 对象上

setTimeout(myObj.showName.bind(myObj), 1000)

总结

相同点:

  • 都可以改变函数内部的 this 指向

不同点:

  • call 和 apply 会调用函数,并且改变函数内部的 this 指向
  • call 和 apply 传递的参数不一样,call 传递单个参数,apply 传递数组形式
  • bind 不会调用函数,可以改变函数内部的 this 指向
  • bind 会产生一个新的函数

主要应用场景:

  • call 经常做继承
  • apply 跟数组有关系,借助于数学对象
  • bind 用于定时器内部指向
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值