// obj.fn()结果打印出;
// Object {x: 2, fn: function}
// 2

var a = obj.fn
a()

// a()结果打印出:
// Window 全局对象
// 1


在上面的例子中,直接运行 obj.fn() ,调用该函数的上一级对象是 obj,所以 this 指向 obj,得到 this.x 的值是 2;之后我们将 fn 方法首先赋值给变量 a,a 运行在全局环境中,所以此时 this 指向全局对象Window,得到 this.x 为 1。

我们再来看一个例子,如果函数被多个对象嵌套调用,this 会指向什么。

var x = 1
var obj = {
x: 2,
y: {
x: 3,
fn: function() {
console.log(this); // Object {x: 3, fn: function}
console.log(this.x); // 3
}
}
}

obj.y.fn();


为什么结果不是 2 呢,因为在这种情况下记住一句话:**this 始终会指向直接调用函数的上一级对象**,即 y,上面例子实际执行的是下面的代码。

var y = {
x: 3,
fn: function() {
console.log(this); // Object {x: 3, fn: function}
console.log(this.x); // 3
}
}

var x = 1
var obj = {
x: 2,
y: y
}

obj.y.fn();


对象可以嵌套,函数也可以,如果函数嵌套,this 会有变化吗?我们通过下面代码来探讨一下。

var obj = {
y: function() {
console.log(this === obj); // true
console.log(this); // Object {y: function}
fn();

    function fn() {
        console.log(this === obj);   // false
        console.log(this);   // Window 全局对象
    }
}

}

obj.y();


在函数 y 中,this 指向了调用它的上一级对象 obj,这是没有问题的。但是在嵌套函数 fn 中,this 并不指向 obj。嵌套的函数不会从调用它的函数中继承 this,当嵌套函数作为函数调用时,其 this 值在非严格模式下指向全局对象,在严格模式是 undefined,所以上面例子实际执行的是下面的代码。

function fn() {
console.log(this === obj); // false
console.log(this); // Window 全局对象
}

var obj = {
y: function() {
console.log(this === obj); // true
console.log(this); // Object {y: function}
fn();
}
}

obj.y();


**情况三:作为构造函数调用**

我们可以使用 new 关键字,通过构造函数生成一个实例对象。此时,**this 便指向这个新对象**。

var x = 1;

function Fn() {
  this.x = 2;
console.log(this); // Fn {x: 2}
}

var obj = new Fn(); // obj和Fn(..)调用中的this进行绑定
console.log(obj.x) // 2


使用`new`来调用`Fn(..)`时,会构造一个新对象并把它(obj)绑定到`Fn(..)`调用中的this。还有值得一提的是,如果构造函数返回了非引用类型(string,number,boolean,null,undefined),this 仍然指向实例化的新对象。

var x = 1

function Fn() {
this.x = 2

return {
x: 3
}
}

var a = new Fn()

console.log(a.x) // 3


因为Fn()返回(return)的是一个对象(引用类型),this 会指向这个return的对象。如果return的是一个非引用类型的值呢?

var x = 1

function Fn() {
this.x = 2

return 3
}

var a = new Fn()

console.log(a.x) // 2


**情况四:call 和 apply 方法调用**

如果你想改变 this 的指向,可以使用 call 或 apply 方法。**它们的第一个参数都是指定函数运行时其中的`this`指向**。如果第一个参数不传(参数为空)或者传 null 、undefined,默认 this 指向全局对象(非严格模式)或 undefined(严格模式)。

var x = 1;

var obj = {
x: 2
}

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

fn.call(obj)
// Object {x: 2}
// 2

fn.apply(obj)
// Object {x: 2}
// 2

fn.call()
// Window 全局对象
// 1

fn.apply(null)
// Window 全局对象
// 1

fn.call(undefined)
// Window 全局对象
// 1


使用 call 和 apply 时,如果给 this 传的不是对象,JavaScript 会使用相关构造函数将其转化为对象,比如传 number 类型,会进行`new Number()`操作,如传 string 类型,会进行`new String()`操作,如传 boolean 类型,会进行new Boolean()操作。

function fn() {
console.log(Object.prototype.toString.call(this))
}

fn.call(‘love’) // [object String]
fn.apply(1) // [object Number]
fn.call(true) // [object Boolean]


call 和 apply 的区别在于,call 的第二个及后续参数是一个参数列表,apply 的第二个参数是数组。参数列表和参数数组都将作为函数的参数进行执行。

var x = 1

var obj = {
x: 2
}

function Sum(y, z) {
console.log(this.x + y + z)
}

Sum.call(obj, 3, 4) // 9
Sum.apply(obj, [3, 4]) // 9


**情况五:bind 方法调用**

调用 f.bind(someObject) 会创建一个与 f 具有相同函数体和作用域的函数,但是在这个新函数中,新函数的 this?**会永久的指向 bind 传入的第一个参数**,无论这个函数是如何被调用的。

var x = 1

var obj1 = {
x: 2
};
var obj2 = {
x: 3
};

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

var a = fn.bind(obj1);
var b = a.bind(obj2);

fn();

这里分享一份由字节前端面试官整理的「2021大厂前端面试手册」,内容囊括Html、CSS、Javascript、Vue、HTTP、浏览器面试题、数据结构与算法。全部整理在下方文档中,共计111道

HTML

  • HTML5有哪些新特性?

  • Doctype作?? 严格模式与混杂模式如何区分?它们有何意义?

  • 如何实现浏览器内多个标签页之间的通信?

  • ?内元素有哪些?块级元素有哪些? 空(void)元素有那些??内元 素和块级元素有什么区别?

  • 简述?下src与href的区别?

  • cookies,sessionStorage,localStorage 的区别?

  • HTML5 的离线储存的使用和原理?

  • 怎样处理 移动端 1px 被 渲染成 2px 问题?

  • iframe 的优缺点?

  • Canvas 和 SVG 图形的区别是什么?

JavaScript逐点突破系列之this是什么,看完不迷茫,学习前端开发经验

JavaScript

CodeChina开源项目:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】

  • 问:0.1 + 0.2 === 0.3 嘛?为什么?

  • JS 数据类型

  • 写代码:实现函数能够深度克隆基本类型

  • 事件流

  • 事件是如何实现的?

  • new 一个函数发生了什么

  • 什么是作用域?

  • JS 隐式转换,显示转换

  • 了解 this 嘛,bind,call,apply 具体指什么

  • 手写 bind、apply、call

  • setTimeout(fn, 0)多久才执行,Event Loop

  • 手写题:Promise 原理

  • 说一下原型链和原型链的继承吧

  • 数组能够调用的函数有那些?

  • PWA使用过吗?serviceWorker的使用原理是啥?

  • ES6 之前使用 prototype 实现继承

  • 箭头函数和普通函数有啥区别?箭头函数能当构造函数吗?

  • 事件循环机制 (Event Loop)

JavaScript逐点突破系列之this是什么,看完不迷茫,学习前端开发经验