// this是什么
// 全局环境中的this
// 函数中的this
// 方法中的this
// 事件中的函数中的this
// 构造函数中this
// call和apply
// bind
// 箭头函数中的this
// 严格模式下的一些状况数组
js中的this关键字是包含它的函数做为方法被调用时所属的对象。浏览器
看似很抽象的一句话,但实际理解起来比较困难,咱们能够分3部分来理解它!
一、包含它的函数。二、做为方法被调用时。三、所属的对象。app
首先咱们先来看一下js中非严格模式下的this分别都是什么函数
在全局执行上下文中(在任何函数体外部)this 都指代全局对象。this
// 在浏览器中, window 对象同时也是全局对象: console.log(this === window); // true a = 37; console.log(window.a); // 37 this.b = "MDN"; console.log(window.b) // "MDN" console.log(b) // "MDN"
绝大多数状况下,函数的调用方式决定了this的值。prototype
在严格模式和非严格模式之间也会有一些差异。code
function f1(){ return this; } //在浏览器中: f1() === window; //在浏览器中,全局对象是window
然而,在严格模式下,this将保持他进入执行上下文时的值,因此下面的this将会默认为undefined。对象
function f2(){ "use strict"; // 这里是严格模式 return this; } f2() === undefined; // true
自执行函数执行,方法中的this通常都是window继承
var obj = { fn: (function() { // this -> window })() }; ~function() { // this -> window }()
咱们说定义在对象内的函数叫作方法,而这个方法执行的时候,它的this就是它的调用者事件
var obj = { fn: function () { console.log(this); } }; obj.fn();
此时fn方法的调用者为obj,因此fn中的this就是obj对象;
但咱们把这个方法赋值给一个自由变量的时候
var f1 = obj.fn; f1();
此时f1执行,实际是obj.fn执行,但f1的调用者其实是 window, window.f1() 因此fn中的this是window
下面再看一个例子,
咱们调用数组上的slice方法,
[].slice(); // this -> [] [].__proto__.slice(); // this -> [].__proto__ Array.prototype.slice(); // this -> Array.prototype
三种调用的slice方法是同样的,但调用的方式不一样,里面的this也不一样
给元素的某个事件绑定了一个方法,当事件触发,函数执行的时候,绑定的这个方法中的this通常是当前操做的这个DOM元素
'二般'状况下
IE6~8下,若是咱们使用DOM2事件绑定,方法执行的时候,里面的this不是当前元素,而是window
ele.attachEvent('onclick', function() { console.log(this); // window });
构造函数执行的时候,函数体中的this都是当前实例;
function Fn() { // this -> 当前Fn的实例 // this.name 是给当前实例设置私有属性 this.name = '1000phone' } var f = new Fn();
当一个函数在其主体中使用 this 关键字时,能够经过使用函数继承自Function.prototype 的 call 或 apply 方法将 this 值绑定到调用中的特定对象。
var school = {name: '1000phone'}; function sum(num1, num2) { this.total = num1 + num2; } sum(20, 30); // this -> window sum.call(school, 20, 30);
首先让 sum 中的this指向call方法中的第一个参数,而后执行sum这个函数
此时 sum 中的 this -> school num1 -> 20 num2 -> 30
参数位置是固定的,若是第一个参数不是 school
sum.call(20, 30);
这时候 sum 的this 是 20,num1 -> 30 num2 -> undefined
若是咱们一个参数都不传
sum.call();
sum 的 this -> window num1 = num2 = undefined
至关于 sum 直接执行,不传参
sum();
但若是第一个参数为null或者undefined
那么就表明没有this,函数中的this依然是window
apply语法与做用,和call相似,只有一个区别,apply传入一组参数
sum.call(school, 20, 30); sum.apply(school, [20, 30]);
apply的语法要求写成一个数组,但实际和call同样,也是一项一项的给形参赋值的
~function () { console.log(this); }.call(school);
此时 自执行函数中的this被call指向为 school
Array.prototype.slice.call(arguments);
此时slice方法执行的时候中的this将再也不是 Array.prototype,而是arguments
call和apply以前的规则,遇到call/apply时,都将以用户自主指向的this为主
ECMAScript 5 引入了 Function.prototype.bind。调用f.bind(someObject)会建立一个与f具备相同函数体和做用域的函数,可是在这个新函数中,this将永久地被绑定到了bind的第一个参数,不管这个函数是如何被调用的。
var school = {name: '1000phone'}; function sum(num1, num2) { this.total = num1 + num2; } sum.call(school, 20, 30);
this -> school 而且执行sum
sum.bind(school, 20, 30);
虽然改变了this指向,但并无执行sum,它是预先处理this和实参,不会当即执行,
一般咱们让它在某个特定条件,才会被触发 IE6~8不兼容
例如咱们有个需求,一秒后执行sum,此时须要定时器,执行sum时,sum中this指向school,而且传参。
setTimeout(sum, 1000);
咱们一秒后执行sum函数
但此时sum中的this是window
setTimeout(sum.call(school, 20, 30), 1000);
此时实现了this的指向而且传了参数,但sum当即执行了,不是一秒后
setTimeout(function() { sum.call(school, 20, 30); }, 1000);
咱们能够达到一秒后执行sum,this指向为shool,而且传参,执行,但代码并不理想,咱们能够使用bind预处理可以达到咱们的目的
setTimeout(sum.bind(school, 20, 30), 1000);
var obj = { fn: function() { setTimeout(function() { // this -> window }, 1000); var that = this; setTimeout(function() { // that -> obj }, 1000); setTimeout(function() { // this -> obj }.bind(this), 1000); setTimeout(() => { // this -> obj }, 1000); } };
在箭头函数中,this与封闭词法上下文的this保持一致,也就是说箭头函数中继承了词法做用域的this
非严格模式下,不明确执行主体,浏览器认为执行主体默认为window,因此this是window
严格模式下,执行主体不明确,this是undefined
'use strict' ~function(){ // this -> undefined }(); fn() // undefined window.fn() // window fn.call() // undefined fn.call(window) // window fn.call(null) // null fn.call(undefined) // undefined
apply同call
能够理解为含有this的函数的调用者。而且this和函数在哪执行的,以及定义的位置没有直接关系。
欢迎来喷!