做者 | Jesksonjavascript
掘金 | https://juejin.im/user/5a16e1...css
2020年01月10日html
前言,为何要学习在掌握JavaScript中的this,call,apply,由于面试官会问啊!因此咱们 必须掌握才能答啊!那么this是什么,Function.prototype.call和前端
Function.prototype.apply这两个方法又是如何使用在JavaScript中的呢。java
学习掌握this是必须的,咱们经常在编写JavaScript中的代码时,会经常使用到它。面试
this的指针做用域,在全局环境中执行this,表示Global对象,在浏览器中表示window对象;当经过new运算符来调用函数时,函数被当作为一个构造函数,this的指向构造函数建立出来的对象;当在函数的执行环境中使用this时,状况有些不一样,如函数没有做为一个非window对象的属性,那么只是定义了在这个函数,无论这个函数是否是定义在另外一个函数中,其函数中的this仍表示为window对象;若是函数表示做为一个非window对象的属性,则表示函数中的this就表明为 这个对象。sql
如截图状况下,在全局执行环境中使用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/blo...
最后
在博客平台里,将来的路还很长,也但愿本身之后的文章你们能多多支持,多多批评指正,咱们一块儿进步,一块儿走花路。
很是感谢读者能看到这里,若是这个文章写得还不错,以为「达达」我有点东西的话,以为我可以坚持的学习,以为此人能够交朋友的话, 求点赞???? 求关注❤️ 求分享???? 对暖男我来讲真的
很是有用!!!
推荐阅读:
2019年的每一天日更只为等待她的出现,好好过余生,庆余年 | 掘金年度征文
一篇文章带你了解JavaScript中的变量,做用域和内存问题
一篇文章带你了解JavaScript中的语法,数据类型,流程控制语句以及函数
感谢阅读,原创不易,喜欢就点个[在看] or [转发朋友圈],这是我写做最大的动力。
意见反馈
若本号内容有作得不到位的地方(好比:涉及版权或其余问题),请及时联系咱们进行整改便可,会在第一时间进行处理。
这是一个有质量,有态度的公众号
点关注,有好运