本栏目详细介绍this指向,记得当时找实习的时候,总是会在简历上加上一句——熟悉Js,例如this指向、call、apply等…
![]() 目录
前言+思考题 记得当时找实习的时候,总是会在简历上加上一句——熟悉Js,例如this指向、call、apply等…
(免费学习推荐:javascript视频教程) 而每次投递简历时我都会经历如下步骤
思考题下面几道题是我在网上搜索出来的热度较高的问题,如果大佬们可以轻松的回答上,并有清晰的思路,不妨直接点个赞吧(毕竟也消耗了不少脑细胞),如果大佬们能在评论处指点一二,就更好了!!! 填空题:
问答题:
代码分析题: var name = 'window'var person1 = {
name: 'person1',
show1: function () {
console.log(this.name)
},
show2: () => console.log(this.name),
show3: function () {
return function () {
console.log(this.name)
}
},
show4: function () {
return () => console.log(this.name)
}}var person2 = { name: 'person2' }person1.show1()person1.show1.call(person2)person1.show2()person1.show2.call(person2)person1.show3()()person1.show3().call(person2)person1.show3.call(person2)()person1.show4()()person1.show4().call(person2)person1.show4.call(person2)()一、this的指向 百度、谷歌上输入“this的指向”关键字,大几千条文章肯定是有的,总不至于为了全方面、无死角的掌握它就要将所有的文章都看一遍吧?所以不如梳理出一个稳固的框架,顺着我们的思路来填充它。 思维导图
本节精华:
分析1、作为对象的方法调用 当函数作为对象的方法被调用时, var obj = {
a: 'yuguang',
getName: function(){
console.log(this === obj);
console.log(this.a);
}};obj.getName(); // true yuguang2、作为普通函数调用 当函数不作为对象的属性被调用,而是以普通函数的方式,this总是指向全局对象(在浏览器中,通常是Window对象) window.name = 'yuguang';var getName = function(){
console.log(this.name);};getName(); // yuguang或者下面这段迷惑性的代码: window.name = '老王'var obj = {
name: 'yuguang',
getName: function(){
console.log(this.name);
}};var getNew = obj.getName;getNew(); // 老王而在ES5的严格模式下,this被规定为不会指向全局对象,而是 3、构造器调用 除了一些内置函数,大部分Js中的函数都可以成为构造器,它们与普通函数没什么不同 构造器和普通函数的区别在于 var MyClass = function(){
this.name = 'yuguang';}var obj = new MyClass();obj.name; // yuguang但是,如果显式的返回了一个object对象,那么此次运算结果最终会返回这个对象。 var MyClass = function () {
this.name = 1;
return {
name: 2
}}var myClass = new MyClass(); console.log('myClass:', myClass); // { name: 2}只要构造器不显示的返回任何数据,或者返回非对象类型的数据,就不会造成上述问题。 4、call或apply调用 跟普通的函数调用相比,用call和apply可以动态的改变函数的this var obj1 = {
name: 1,
getName: function (num = '') {
return this.name + num;
}};var obj2 = {
name: 2,};// 可以理解成在 obj2的作用域下调用了 obj1.getName()函数console.log(obj1.getName()); // 1console.log(obj1.getName.call(obj2, 2)); // 2 + 2 = 4console.log(obj1.getName.apply(obj2, [2])); // 2 + 2 = 45.箭头函数 箭头函数不会创建自己的this,它只会从自己的作用域链的上一层继承this。 因此,在下面的代码中,传递给setInterval的函数内的this与封闭函数中的this值相同: this.val = 2;var obj = {
val: 1,
getVal: () => {
console.log(this.val);
}}obj.getVal(); // 2常见的坑 就像标题一样,有的时候 情况一 var obj = {
name: '1',
getName: function (params) {
console.log(this.name)
}};obj.getName();var getName2 = obj.getName;getName2();这个时候, 情况二 当我们希望自己封装Dom方法,来精简代码时: var getDomById = function (id) {
return document.getElementById(id);};getDomById('p1') //dom节点那么我们看看这么写行不行? var getDomById = document.getElementByIdgetDomById('p1') // Uncaught TypeError: Illegal invocation(非法调用)这是因为:
利用call和apply修正情况二 document.getElementById = (function (func) {
return function(){
return func.call(document, ...arguments)
}})(document.getElementById) // 利用立即执行函数将document保存在作用域中
二、call和apply 不要因为它的“强大”而对它产生抗拒,了解并熟悉它是我们必须要做的,共勉! 思维导图
1.call和apply区别先来看区别,是因为它们几乎没有区别,下文代码实例call和apply都可以轻易的切换。 当它们被设计出来时要做到的事情一摸一样,唯一的区别就在于
因为在所有(非箭头)函数中都可以通过 call是包装在apply上面的语法糖,如果我们明确的知道参数数量,并且希望展示它们,可以使用call。 当使用call或者apply的时候,如果我们传入的第一个参数为null,函数体内的this会默认指向宿主对象,在浏览器中则是 借用其他对象的方法 我们可以直接传null来代替任意对象 Math.max.apply(null, [1, 2, 3, 4, 5]) 2.call和apply能做什么?使用一个指定的 this 值和单独给出的一个或多个参数来调用一个函数——来时MDN
1.调用构造函数来实现继承 通过“借用”的方式来达到继承的效果: function Product(name, price) {
this.name = name;
this.price = price;}function Food(name, price) {
Product.call(this, name, price); //
this.category = food;}var hotDog = new Food('hotDog', 20);2.调用函数并且指定上下文的 此时this被指向了obj function showName() {
console.log(this.id + ':' + this.name);};var obj = {
id: 1,
name: 'yuguang'};showName.call(obj)3.使用call单纯的调用某个函数 Math.max.apply(null, [1,2,3,10,4,5]); // 10
三、模拟实现一个call 先来看一下call帮我们需要做什么? var foo = {
value: 1};function show() {
console.log(this.value);};show.call(foo); //1就像解方程,要在已知条件中寻找突破哦口:
第一版代码 上面提到的3点,仅仅完成了一点,且传入的参数 var foo = {
value: 1};function show() {
console.log(this.value);};Function.prototype.setCall = function (obj) {
console.log(this); // 此时this指向show
obj.func = this; // 将函数变成对象的内部属性
obj.func(obj.value); // 指定函数
delete obj.func // 删除函数,当做什么都没发生~}show.setCall(foo);第二版代码 为了解决参数的问题,我们要能获取到参数,并且正确的传入: var foo = {
value: 1};function show(a, b) {
console.log(this.value);
console.log(a + b);};Function.prototype.setCall = function (obj) {
obj.fn = this; // 将函数变成对象的内部属性
var args = [];
for(let i = 1; i < arguments.length; i++){
args.push('arguments[' + i + ']');
}
eval('obj.fn(' + args + ')'); // 传入参数
delete obj.fn; // 删除函数,当做什么都没发生~}show.setCall(foo, 1, 2); // 1 3此时,我们就可以做到,传入多个参数的情况下使用call了,但是如果你仅想用某个方法呢? 第三版代码 Function.prototype.setCall = function (obj) {
var obj = obj || window;
obj.fn = this;
var args = [];
for(var i = 1, len = arguments.length; i < len; i++) {
args.push('arguments[' + i + ']');
}
var result = eval('obj.fn(' + args +')');
delete obj.fn;
return result;};// 测试一下var value = 2;var obj = { value: 1 };function bar(name, age) {
console.log(this.value);
return {
value: this.value,
name: name,
age: age }}bar.setCall(null); // 2console.log(bar.setCall(obj, 'yuguang', 18));四、bind
提到了call和apply,就绕不开bind。我们试着来模拟一个bind方法,以便加深我们的认识: Function.prototype.bind = function (obj) {
var _this = this; // 保存调用bind的函数
var obj = obj || window; // 确定被指向的this,如果obj为空,执行作用域的this就需要顶上喽
return function(){
return _this.apply(obj, arguments); // 修正this的指向
}};var obj = {
name: 1,
getName: function(){
console.log(this.name)
}};var func = function(){
console.log(this.name);}.bind(obj);func(); // 1这样看上去,返回一个原函数的拷贝,并拥有指定的 this 值,还是挺靠谱的哦~ 写在最后 JavaScript内功基础部分第一篇,总结这个系列是受到了冴羽大大的鼓励和启发,本系列大约会有15篇文章,都是我们在面试最高频的,但在工作中常常被忽略的。
以上就是详解this指向,让你一篇搞懂this、call、apply的详细内容,更多请关注模板之家(www.mb5.com.cn)其它相关文章! |
