}
obj.fn()
// 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();
// Window 全局对象
// 1
a();
// Object {x: 2}
// 2
b();
// Object {x: 2}
// 2
a.call(obj2);
// Object {x: 2}
// 2
在上面的例子中,虽然我们尝试给函数 a 重新指定 this 的指向,但是它依旧指向第一次 bind 传入的对象,即使是使用 call 或 apply 方法也不能改变这一事实,即永久的指向 bind 传入的第一次参数。
情况六:箭头函数中this指向
值得一提的是,从ES6 开始新增了箭头函数,先来看看MDN 上对箭头函数的说明
An arrow function expression has a shorter syntax than a function expression and does notbind its own
this
,arguments
,super
, ornew.target
. Arrow functions are always anonymous. These function expressions are best suited for non-method functions, and they cannot be used as constructors.
这里已经清楚了说明了,箭头函数没有自己的this
绑定。箭头函数中使用的this
,其实是直接包含它的那个函数或函数表达式中的this
。在前面情况二中函数嵌套函数的例子中,被嵌套的函数不会继承上层函数的 this,如果使用箭头函数,会发生什么变化呢?
var obj = {
y: function() {
console.log(this === obj); // true
console.log(this); // Object {y: function}
var fn = () => {
console.log(this === obj); // true
console.log(this); // Object {y: function}
}
fn();
}
}
obj.y()
和普通函数不一样,箭头函数中的 this 指向了 obj,这是因为它从上一层的函数中继承了 this,你可以理解为箭头函数修正了 this 的指向。所以箭头函数的this不是调用的时候决定的,而是在定义的时候处在的对象就是它的this。
换句话说,箭头函数的this看外层的是否有函数,如果有,外层函数的this就是内部箭头函数的this,如果没有,则this是window。
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数前端工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新
如果你觉得这些内容对你有帮助,可以添加V获取:vip1024c (备注前端)
总结
秋招即将开始,校招的朋友普遍是缺少项目经历的,所以底层逻辑,基础知识要掌握好!
而一般的社招,更是神仙打架。特别强调,项目经历不可忽视;几乎简历上提到的项目都会被刨根问底,所以项目应用的技术要熟练,底层原理必须清楚。
这里给大家提供一份汇集各大厂面试高频核心考点前端学习资料。涵盖 HTML,CSS,JavaScript,HTTP,TCP协议,浏览器,Vue框架,算法等高频考点238道(含答案)!
资料截图 :
CodeChina开源项目:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】
高级前端工程师必备资料包
一个人可以走的很快,但一群人才能走的更远。如果你从事以下工作或对以下感兴趣,欢迎戳这里加入程序员的圈子,让我们一起学习成长!
AI人工智能、Android移动开发、AIGC大模型、C C#、Go语言、Java、Linux运维、云计算、MySQL、PMP、网络安全、Python爬虫、UE5、UI设计、Unity3D、Web前端开发、产品经理、车载开发、大数据、鸿蒙、计算机网络、嵌入式物联网、软件测试、数据结构与算法、音视频开发、Flutter、IOS开发、PHP开发、.NET、安卓逆向、云计算
5a8b90918f35c830c299df8.png)
CodeChina开源项目:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】
高级前端工程师必备资料包
一个人可以走的很快,但一群人才能走的更远。如果你从事以下工作或对以下感兴趣,欢迎戳这里加入程序员的圈子,让我们一起学习成长!
AI人工智能、Android移动开发、AIGC大模型、C C#、Go语言、Java、Linux运维、云计算、MySQL、PMP、网络安全、Python爬虫、UE5、UI设计、Unity3D、Web前端开发、产品经理、车载开发、大数据、鸿蒙、计算机网络、嵌入式物联网、软件测试、数据结构与算法、音视频开发、Flutter、IOS开发、PHP开发、.NET、安卓逆向、云计算