作者 | Jeskson
掘金 | https://juejin.im/user/5a16e1f3f265da43128096cb
2020年01月10日
前言,为什么要学习在掌握JavaScript中的this,call,apply,因为面试官会问啊!所以我们 必须掌握才能答啊!那么this是什么,Function.prototype.call和
Function.prototype.apply这两个方法又是如何使用在JavaScript中的呢。
学习掌握this是必须的,我们常常在编写JavaScript中的代码时,会常用到它。
this的指针作用域,在全局环境中执行this,表示Global对象,在浏览器中表示window对象;当通过new运算符来调用函数时,函数被当做为一个构造函数,this的指向构造函数创建出来的对象;当在函数的执行环境中使用this时,情况有些不同,如函数没有作为一个非window对象的属性,那么只是定义了在这个函数,不管这个函数是不是定义在另一个函数中,其函数中的this仍表示为window对象;如果函数表示作为一个非window对象的属性,则表示函数中的this就代表为 这个对象。
如截图情况下,在全局执行环境中使用this,表示Global对象,在浏览器中表示为window对象。
-
function A(){
-
//在A函数中定义一个B函数
-
function B(){
-
console.log(
this);
//Window
-
console.log(
typeof
this);
//object
-
console.log(
this ===
window);
//true
-
}
-
//在A函数内部调用B函数
-
B();
-
}
-
//调用A函数
-
A();
在函数执行环境中使用this时,如果函数没有明显的作为非window对象的属性,而只是定义了函数,不管这个函数是不是定义在另一个函数中,这个函数中的this仍然表示window对象。
-
//定义一个对象obj,添加属性name,添加方法objFun
-
var obj = {
-
name:
'dada',
-
objFun:
function(){
-
console.log(
this);
// Object {name: "dada"}
-
console.log(
typeof
this);
//object
-
console.log(
this ===
window);
//false
-
console.log(
this.name);
//dada
-
}
-
};
-
-
//调用obj对象的方法
-
obj.objFun();
//this 绑定到当前对象,也就是obj对象
-
//定义一个对象obj,添加属性name,添加方法objFun
-
var obj = {
-
name:
'dada',
-
objFun:
function(){
-
console.log(
this);
//window
-
console.log(
typeof
this);
//object
-
console.log(
this ===
window);
//true
-
console.log(
'dada的,名字'+
this.name+
'大帅哥');
-
}
-
};
-
-
var test = obj.objFun;
-
test();
可以看出函数内部中this值不是静态的,是动态的,可以改变的,每次调用一个函数时,它总是在重新求值。函数内部中的this值,实际上是由函数被调用的父作用域提供,依赖实际函数的语法。
-
// 第一种情况
-
-
-
//调用obj对象的方法
-
obj.objFun();
//this 绑定到当前对象,也就是obj对象
-
-
-
// 第二种情况
-
-
-
var test = obj.objFun;
-
test();
-
var test = obj.objFun
-
// 这里没有调用函数
-
test()
-
// 这里调用了函数
-
-
-
// test不是一个对象的引用,所以this值代表全局对象。
当通过new运算符来调用函数时,函数被当做一个构造函数,this指向构造函数创建出来的对象。
new创建出来了一个构造函数,这个时候this的值,指向构造函数创建出来的对象。
-
var name =
'dada';
-
function A(){
-
console.log(
this.name);
-
}
-
-
A();
// dada
-
-
var B =
new A();
//undefined (因为B并没有name属性)
-
VM162:
3 dada
-
VM162:
3
undefined
-
undefined
-
var name =
'windowdada';
-
var obj = {
-
name:
'objdada',
-
objB: {
-
name:
'objBdada',
-
bFun:
function(){
-
console.log(
this.name);
-
}
-
}
-
};
-
-
-
var test = obj.objB.bFun();
-
-
-
var test2 = obj.objB.bFun;
-
test2();
-
-
-
var test3 = obj.objB;
-
-
-
var test4 = test3.bFun;
-
test4();
注意()的近邻的左边,如果这个的左边是一个引用,那么传递给调用函数的this值为引用所属的这个对象,否则this指向为全局对象。
-
var test = obj.objB.bFun();
-
// ()左边是bFun引用,它指向objB这个对象,所有打印出objBdada
-
var test2 = obj.objB.bFun;
-
test2();
-
// ()的左边为test2,它不是某个对象的引用,所以是全局对象
-
// 打印出 objBdada
-
var test4 = test3.bFun;
-
test4();
-
-
-
// 同理这个也是
JavaScript中this的原理
-
var name =
'windowDada';
-
var obj = {
-
name:
'dada',
-
foo:
function () {
-
console.log(
this.name);
-
}
-
};
-
-
-
var foo = obj.foo;
-
-
-
// 写法一
-
obj.foo()
-
-
-
// 写法二
-
foo()
-
VM593:
5 dada
-
VM593:
5 windowDada
这个时候我相信你已经看懂了。this指向的是函数运行时所在的环境,对于obj.foo()来说,foo运行在obj环境中,所以这个时候的this指向为obj这个对象,对于foo()来说,foo运行是全局环境,这个this的指向为全局环境。(你会问为什么呢?一个指向obj这个对象,一个运行环境为全局环境,这里可以运用()左边方法)
对呀为什么呢?函数的运行环境是怎么决定在哪种情况的?
为什么obj.foo()的环境就在obj这个环境中,而作为
var foo = obj.foo,foo()的运行环境就变成了全局的执行环境呢?
this的指向设计,跟内存的数据结构有关。
-
var obj = {
-
name:
'dada'
-
};
当一个对象赋值给一个变量obj的时候,JavaScript引擎会在内存里,先生成一个对象为 { name: 'dada' },然后才把这个对象的内存地址赋值给这个变量 obj。
我们说过了很多很多遍了,都知道这个变量obj就是一个地址,这个时候如果要读 obj.foo,那么引擎就会从这个变量 obj中拿内存地址,然后再从这个地址 读取原始对象,返回它的foo属性。
注意:原始的对象(开始创建的对象 { name: 'dada' })以字典结构保存的,每个属性名都对应一个属性描述对象。foo属性的值保存在属性描述对象的value属性里面。
this指包含它的函数作为方法被调用时所属的对象。
this,第一包,含它的函数,第二,作为方法被调用时,第三,所属的对象。
-
function da(){
-
console.log(
this);
//window
-
}
-
da();
会调用我,我就是谁的,谁最后调用我,我就是谁的。
testFunda()函数是在全局中被window对象所调用的,this的指向为window对象,而nameda变量在testFunda函数中,window对象中没有这个变量,所以打印不出来。
注意()的左边为testFunda
而testFunda()函数是在全局中被window对象所调用的哦!
因此this的指向就是window对象哦!
-
var namedada =
'dada'
-
function testFundada () {
-
var namedada=
"hello dada!";
-
console.log(
this.namedada);
-
}
-
testFundada();
-
VM717:
4 dada
看这个代码当然打印出的是dada啦,因为从全局调用,全局中有这个属性,就打印这个属性。
this被包含中一个函数中,但是这个函数被另个函数包含的情况下,这个this的指向为顶部的函数。
-
var obj={
-
a:
"da",
-
b:
function(){
-
var a=
"dada";
-
console.log(
this.a);
-
}
-
};
-
obj.b();
-
VM726:
5 da
this被包含在函数b()中,因为是被obj对象所调用的,所以这个this属于这个obj对象,打印出来的就是da这个字符串了。
谁最后调用我,我就属于谁!
-
var obj = {
-
a:
1,
-
b:{
-
fn:
function(){
-
console.log(
this.a);
//undefined
-
}
-
}
-
};
-
obj.b.fn();
-
-
-
VM730:
5
undefined
对象obj是在window上定义的,所以如下显示:
obj.b.fn()=window.obj.b.fn()
谁先调用我不算,谁最后调用我才算,window,那么this不是指向全局的对象了吗,但是最后的是被fn()调用,()左边为b对象,所以this就指向这个b对象了,因为函数中没有这个变量,所以为undefined。
出一道考题
结果是啥?我知道为2,你知道吗?那看看执行结果吧!
-
var obj = {
-
name:
1,
-
b:{
-
name:
2,
-
fn:
function(){
-
var name =
3
-
console.log(
this.name);
-
}
-
}
-
};
-
obj.b.fn();
函数情况,属性的值为一个函数
var obj = { foo: function () {} };
在JavaScript引擎中会将函数单独保存在内存中,再将函数的地址赋值给foo属性的value属性。
-
{
-
foo: {
-
[[value]]: 函数的地址
-
...
-
}
-
}
-
var f =
function () {};
-
var obj = {
f: f };
-
-
-
// 单独执行
-
f()
-
-
-
// obj 环境执行
-
obj.f()
-
var fda =
function () {
-
console.log(
'da');
-
};
-
-
-
var objDada = {
f: fda };
-
-
-
// 单独执行
-
fda()
-
-
-
// objDada 环境执行
-
objDada.fda()
-
VM858:
2 da
环境的考虑,在JavaScript中运行在函数体内部,引用当前环境的其他变量。在JavaScript中,由于函数可以在不同的运行环境执行,就要一种机制,使能够在函数体内部获取当前的运行环境。
this的出现,目的在于就是指代函数当前的运行环境。
this 指代全局对象
-
function test(){
-
this.x =
1;
-
alert(
this.x);
-
}
-
test();
// 1
this 指代上级对象
-
function test(){
-
alert(
this.x);
-
}
-
var o = {};
-
o.x =
1;
-
o.m = test;
-
o.m();
// 1
this 指代 new 出的对象
-
var x =
3;
-
-
-
function test(){
-
this.x =
1;
-
}
-
-
-
var o =
new test();
-
-
-
alert(x);
// 3
-
-
-
alert(o.x);
// 1
函数的不同使用场合,this 有不同的值,this是函数运行时所在的环境对象。
call的用法
call(thisObj,arg1,arg2,arg...)
调用一个对象的方法,以另一个对象替换当前对象,call方法用来代替另一个对象调用一个方法,该方法可以将一个函数对象的上下文改变为由this obj指定的新对象。
call方法的参数,如果是不传,或是null,undefined的情况下,函数中的this指向就是指window对象,如果传递的是另一个函数的函数名,函数中的this指向就是这个函数的引用,如果参数传递的是基本类型数据时,函数中的this指向就是其对应的 包装对象了,如果参数传递的是一个对象时,函数中的this就指向这个对象。
一个函数的函数名,函数名是引用,所以指向是指这个函数的引用
一个对象,所以this就指向这个对象
基本类型数据,就指向这个包装对象
Function.prototype.call(thisArg[,arg1[,arg2, ...]])
当以thisArg和可选择的arg1,arg2等等作为参数在一个func对象上调用call方法。
-
var da = {
-
name:
"da",
-
sayHello:
function (age) {
-
console.log(
"hello, i am ",
this.name +
" " + age +
" years old");
-
}
-
};
-
-
-
var jeskson = {
-
name:
"jeskson",
-
};
-
-
-
da.sayHello(
12);
-
VM891:
4 hello, i am da
12 years old
-
undefined
-
da.sayHello.call(jeskson,
13);
-
VM891:
4 hello, i am jeskson
13 years old
-
undefined
在JavaScript中,call和apply作用是一样的
为了改变某个函数运行时的上下文(context)而存在的,就是为了改变函数体内部this的指向。
每个函数都包含两个非继承而来的方法:
call()和apply()
apply的用法
apply(thisObj,argArray)
apply方法应用于某一个对象的一个方法
用另一个对象替换当前对象。
区别:参数书写方式不同
call() 方法分别接受参数。
apply() 方法接受数组形式的参数。
-
Math.max(
1,
2,
3);
// 会返回 3
-
-
-
Math.max.apply(
null, [
1,
2,
3]);
// 也会返回 3
-
-
-
Math.max.apply(
Math, [
1,
2,
3]);
// 也会返回 3
-
-
-
Math.max.apply(
" ", [
1,
2,
3]);
// 也会返回 3
-
-
-
Math.max.apply(
0, [
1,
2,
3]);
// 也会返回 3
-
call(thisObj, arg1, arg2, arg3, arg4);
-
apply(thisObj, [args]);
-
-
-
thisObj:
-
-
-
call和
apply第一个参数是一样的
-
该参数将替代
Function类里面的this对象
-
-
-
arg1,arg2....
-
-
-
是一个个的参数
-
-
-
args
-
一个数组或类数组,是一个参数列表
JavaScript 严格模式
如果 apply() 方法的第一个参数不是对象,它将成为被调用函数的所有者(对象)。
在“非严格”模式下,它成为全局对象。
参考:
http://www.ruanyifeng.com/blog/2018/06/javascript-this.html
最后
欢迎加我微信(xiaoda0423),拉你进技术群,长期交流学习...
欢迎关注「达达前端」,认真学前端,做个有专业的技术人...
在博客平台里,未来的路还很长,也希望自己以后的文章大家能多多支持,多多批评指正,我们一起进步,一起走花路。
非常感谢读者能看到这里,如果这个文章写得还不错,觉得「达达」我有点东西的话,觉得我能够坚持的学习,觉得此人可以交朋友的话, 求点赞???? 求关注❤️ 求分享???? 对暖男我来说真的
非常有用!!!
推荐阅读:
2019年的每一天日更只为等待她的出现,好好过余生,庆余年 | 掘金年度征文
一篇文章带你了解JavaScript中的变量,作用域和内存问题
一篇文章带你了解JavaScript中的语法,数据类型,流程控制语句以及函数
感谢阅读,原创不易,喜欢就点个[在看] or [转发朋友圈],这是我写作最大的动力。
意见反馈
若本号内容有做得不到位的地方(比如:涉及版权或其他问题),请及时联系我们进行整改即可,会在第一时间进行处理。
这是一个有质量,有态度的公众号
点关注,有好运
转载:https://blog.csdn.net/qq_36232611/article/details/103929527