本文最最核心的一句话就是:this
是在函数调用的时候确定的,一定要牢牢记住,其次,在函数执行过程中,this
一旦被确定,就不可更改了。
var a = 10;
var obj = {
a: 20
}
function fn(){
this= obj; // 这句话试图修改this,运行后会报错
console.log(this.a);
}
fn();
this
是什么
重点:this
是一个对象,是对象和函数之间达成关联关系的纽带,是在函数调用的时候确定。
怎么确定this
的指向
因为this
是在函数调用的时候确定的,所以this
的指向是很灵活的,所以很多人对this
的指向总是似懂非懂。那么这里可以告诉大家一个套路,也是本文唯一的套路,按照这个套路走,以后this
的问题再也难不倒你了。
当你不能确定this
指向哪里的时候,尝试把函数的调用转换为 call/apply
的形式,call/apply
的第一个参数就是this
的指向!
call/apply
手动指定this
call/apply
可以自行手动设置this
的指向。所有的函数都具有着两个方法,它们除了参数略有不同,其功能完全一样。它们的第一个参数都为this
将要指向的对象。call/apply
的具体使用这里就不讲了,如果不熟悉call/apply
的用法 送你传送门
function fn(param) {
console.log(this.a,param);
}
var obj = {
a: "我是this的属性a"
}
fn.call(obj,"我是参数param"); // 我是this的属性a 我是参数param
-
call/apply
第一个参数如果传入的是简单数据类型,会被自动包装为对象function f(){ console.log(this) } f.call(10); // Number {10} f.call(true); // Boolean {true} f.call("str"); // String {"str"}
-
call/apply
第一个参数如果没传,或者传入的是null/undefined
的时候,this
的指向跟是否在严格模式下有关。-
非严格模式下,
this
指向全局对象(浏览器是window
)。function f(){ console.log(this) } f.call(); // Window {postMessage: ƒ,...} f.call(null); // Window {postMessage: ƒ,...} f.call(undefined); // Window {postMessage: ƒ,...}
-
严格模式下,
this
指向null/undefined
"use strict" function f(){ console.log(this) } f.call(); // undefined f.call(null); // null f.call(undefined); // undefined
-
几个栗子
只要掌握call/apply
,结合是否严格模式,你就会发现虚无缥缈的this
已经有迹可循了,下面例子中的函数调用代码都可以通过转换的call
模式代码直接替换。
-
纯粹的函数调用
// 非严格模式 var x = 1; function test() { console.log(this.x); } // 在心里将test()翻译为call模式,test.call(),非严格模式 // 所以this===window,所以输出window.x test(); // 1 // 严格模式 "use strict" var x = 1; function test() { console.log(this.x); } // 在心里将test()翻译为call模式,test.call(),严格模式 // 所以this===undefined,所以输出window.x test(); // Uncaught TypeError: Cannot read property 'x' of undefined
-
作为对象方法的调用
function test() { console.log(this.x); } var obj = { x:3, m:test }; // 在心里将test()翻译为call模式,obj.m.call(obj),这时this===obj,所以输出obj.x obj.m(); // 3
- 作为构造函数调用,
this
就指向构造出来的新对象
function Test() { this.x = 3; } // 在心里将test()翻译为call模式 // var obj = {}; Test.call(obj); // 这时this===obj,所以输出obj.x var obj = new Test(); obj.x; // 3
- 作为构造函数调用,
-
通过
call/apply
改变this
指向,将类数组对象转换为数组,function exam(a, b, c, d, e) { // 先看看函数的自带属性 arguments 什么是样子的 console.log(arguments); // 使用call/apply将arguments转换为数组, 返回结果为数组,arguments自身不会改变 var arg = [].slice.call(arguments); console.log(arg); } exam(2, 8, 9, 10, 3); // { '0': 2, '1': 8, '2': 9, '3': 10, '4': 3 } // [ 2, 8, 9, 10, 3 ] // 也常常使用该方法将DOM中的nodelist转换为数组 // [].slice.call( document.getElementsByTagName('li') );
-
根据自己的需要灵活修改
this
指向var foo = { name: 'joker', showName: function() { console.log(this.name); } } var bar = { name: 'rose' } foo.showName.call(bar);
总结
我们可以将平时通过括号、通过.
、通过new
去使用函数的方式,看做是call/apply
的语法糖,是简写版,想要深入理解函数的调用,就要学好call
。
关于this
的部分已经总结完了,希望这篇文章有助于你准确的理解this
关键字,能够真正学到东西。
参考
this 的值到底是什么?一次说清楚
你怎么还没搞懂 this?
JS 的 new 到底是干什么的?
Javascript 的 this 用法
全方位解读this
====================================================================================================
作者:星木
欢迎任何形式的转载,但请务必注明出处。
限于本人水平,如果有不当之处,还请不吝赐教。