面试题:
1、说一下 this 的指向有几种方式及使用场景 (58、小米、货拉拉)
2、 this 指向问题(招银、字阿波波)
3、 箭头函数中 this 的指向(字节)
4、改变 this 指向的方法 call()、apply()、 bind()的作用和区别 ?(字节、网易)
5、箭头函数可以用 call 或者 apply 改变 this 指向吗 ?(百度)
6、 bind 如果第一次传入了 this,我再给 bind 传入一次 this,他执行的是哪个 this (字节)
MDN文档:
“ECMAScript 5 引入了 Function.prototype.bind。调用f.bind(someObject)会创建一个与f具有相同函数体和作用域的函数,但是在这个新函数中,this将永久地被绑定到了bind的第一个参数,无论这个函数是如何被调用的。”
意思是:bind方法就是新创建一个与函数f具有相同函数体和作用域的函数,然后把新函数的this指向永久绑定为bind的第一个参数,无论新函数如何被调用的,新函数的this指向已永久绑定。
<script> function fn() { return this.a } let bb = fn.bind({ a: 'hhhhh' }) console.log(bb()) // hhhhh let cc = bb.bind({ a: 'zzzz' }) console.log(cc()) // hhhhh </script>
7、以下代码输出什么 ?
for (let i = 0; i < 10; i++) {
this.a = i;
this.$nextTick(() => {
console.log(i);
console.log(this.a);
});
}
注意:
1.非严格模式下,this有4种绑定机制(默认、隐式、显式、new)
- 默认就是fn()的形式,无论在哪个位置,只要是fn()都是指向window
- 隐式就是obj.fn的形式,只看fn前面1个,obj1.obj.fn 还是obj在调用而不是obj1
- 显式就是通过call、apply、bind强行改变this的指向
new指向创建的对象
2.this绑定的优先级是new>bind>call(apply)>obj.func()(隐式绑定)>默认绑定
3.this的值要等到代码真正执行时才能确定
1.全局环境输出this,指向window
2.全局函数输出this,指向全局对象
3.对象的方法输出this,指向调用方法的对象
4.DOM事件输出this,指向触发事件的DOM对象
5.构造函数中的this指向new创建的对象 (new关键字做了什么)
function Star() {
console.log(this);
}
new Star();//打印Star,Star函数内部的this指向new创建的实例
在内存中创建一个新的空对象
让this指向这个对象
执行构造函数里面的代码,给这个新对象添加属性和方法
返回这个新对象(所以构造函数里面不需要return)
6.箭头函数中的this,指向定义上下文的this
var o = {
sayHi: () => {
console.log(this);
}
}
o.sayHi();//打印window,注意:对象不能形成自己的作用域,其作用域为全局作用域,因此this指向Window对象
7.立即指向函数中的this,指向window
(function() {
console.log(this);
}());
8.定时器中的this指向window对象
例1.
var name = 'Jay'; function Person(name) { this.name = name console.log(this.name); } var a = Person('Tom') console.log(name); console.log(a); var b = new Person('Michael') console.log(b);
链接:请给出打印出的值:_小红书笔试题_牛客网
来源:牛客网
第一个Tom:因为Person独立调用this指向window,将window.name改成了Tom第二个Tom:全局下的name已改成了Tom
第三个undefined:普通函数没有返回值时返回undefined
第四个Michael:new调用this为当前实例
第五个Person { name: 'Michael' }:构造函数有返回对象以自己为主,没有返回值或者返回值不为对象类型则默认返回创建的实例对象
例2.
var obj = {
a: 1,
b: function() {
alert(this.a)
}
};
var fun = obj.b; //相当于var fun = function(){alert(this.a)};
fun(); //没有谁来调用的时候,this自然指向window
//而window里面没有定义a,所以弹出undefined
//类似题
var user = {
count: 1,
getCount: function() {
return this.count;
}
}
var func = user.getCount
//等价于 var func=function(return this.count)
// 所以this 指向window
//var func =user. getCount()表示调用方法 这个时候才输出1
console.log(func())
//输出undefined
例3.
function a(){ console.log(this); } a.call(null);
function.call(thisArg,args1,args2...)可以调用函数function,并且让函数内部的this指向thisArg,同时传递args1,args2等参数。如果函数处在非严格模式下,且thisArg的值为null或者undefined,则调用时函数内部的this指向window对象
例4.
apply,call,bind的用法和区别(方法劫持)
用途:手动改变this的指向
区别:
- apply和call会使当前函数立即执行,bind会返回一个函数,后续需要时再调用
- call是apply的语法糖,只有传的参数不同,call中要传多个任意参数,apply只可以直接传数组或者类数组
- bind是为函数绑定一个this上下文
规则:
- fn.apply(上下文环境,执行所需数组)
apply可以将一个数组转换为一个参数列表([p1,p2,p3]转换为p1,p2,p3)。如:
var arr=[1,2,3,4]
console.log (Math.max.apply(null,arr))//4Math.max()只能传数字,可以使用apply将数组转为一个一个参数传入
- fn.call(上下文环境,执行所需单个参数)
- fn.bind(上下文环境)
ps:如果上下文的值为null,则使用全局对象代替,相当于没传上下文还用以前的
另外 在严格模式下
- apply(null) 上下文对象就变成null
- apply(undefined)上下文对象就变成undefined,也就是说第一个参数是什么 他的上下文对象就变成什么
"use strict" function sum() { console.log(this) } sum.apply(null) //输出null sum.apply(undefined) //输出undefined sum.apply(1) //输出1 sum.apply("haha") //输出"haha"
function sum() { console.log(this) } sum.apply(null) //输出Window对象 sum.apply(undefined) //输出Window对象 sum.apply(1) //输出Number对象Number {1} sum.apply("haha") //输出String对象String {"haha"}
例5.
var myObject = { foo: "bar", func: function() { var self = this; console.log(this.foo); console.log(self.foo); (function() { console.log(this.foo); console.log(self.foo); }()); } }; myObject.func();//指向myObject对象 // 输出 bar bar undefined bar
方法/函数是由谁(对象) 调用 的,方法/函数内部的 this 就指向谁(该对象);
注意:被谁调用,不是处于谁的作用域
1.第一个this.foo输出bar,因为当前this指向对象myObject。
2.第二个self.foo输出bar,因为self是this的副本,同指向myObject对象。
3.第三个this.foo输出undefined,因为这个IIFE(立即执行函数表达式)中的this指向window。
4.第四个self.foo输出bar,因为这个匿名函数所处的上下文中没有self,所以通过作用域链向上查找,从包含它的父函数中找到了指向myObject对象的self
例6.
var color = 'green';
var test4399 = {
color: 'blue',
getColor: function(){
var color = "red";
alert(this.color);
}
}
var getColor = test4399.getColor;
//相当于var getColor=function {
//var color='red';alert(this.color)}
getColor();//没有谁调用,指向window
test4399.getColor();//this 指向test4399这个对象
//弹出 green blue
例7.
// 在JavaScript的函数中,this始终指向调用者的上下文环境
var len = 117 // 5. 全局作用域中使用 var 定义的变量默认会成为 window 的属性,及 window.len
let func = {
len: 935,
showLen: function () {
console.log(this.len) // 4. this 此时指向的是 window,所以相当于打印 window.len
},
show: function () {
(function (cb) {
cb() // 3. cb 相当于 cb.call() 默认没有传入上下文环境时 this 指向全局的 window 对象
})(this.showLen) // 2. this 是 func 所以传入的是上面定义的 showLen 函数
}
}
func.show() // 1. 相当于 func.show.call(func),此时 this 是 func
//len输出117
例8. 假设document是HTML文档中的一个节点,点击该节点后会发生什么?//输出true
function test() { this.flag = false; this.change = () => { this.flag = true; console.log(button.flag); }; } const button = new test(); document.addEventListener("click", button.change);
链接:假设document是HTML文档中的一个节点,点击该节点后__牛客网
题目中调用button.change,所以去分析change(),而难点就在于 this.flag = true;的this是谁?当看到change是一个箭头函数的this时,就去找外面第一个不是箭头函数的函数,也就是会把this绑定到text上,那this.flag = true;就意味着text()的实例中的flag会变成true,所以button.flag为true
例9. 输出window
var obj = {}; obj.log = console.log; obj.log.call(console,this);
链接:请阅读以下代码var obj =&_用友笔试题_牛客网
obj属性log指向console的log函数
众所周知console的log函数接收一个参数用于打印
第三句代码call使得obj.log函数里的this指向了console,第二个参数作为log函数的参数,所以实际上打印的是call传进去的第二个参数,传啥打印啥
obj.log.call(console,this);等价于obj.log(this);因为call改的this根本没有用到
例10
var uname = "window"; var object = { uname: "object", fun: function() { console.log(this.uname); return function() { console.log(this.uname); } } } object.fun()();
以上程序输出object window
object.fun()()等效于
var fn = object.fun();
fn();
实际上是调用函数两次,第一次是调用object对象的fun函数,第二次是调用fun函数的返回函数。
第一次调用fun函数时,this指向上一级对象,即object对象,因此输出对象object的uname属性值object
第二次调用的返回函数,其this指向window对象,这是因为匿名函数具有全局性,匿名函数的this指向window对象,因此输出结果为window对象的uname属性值window
例11
let a = 'w' let obj = { a: 'o', print: function() { console.log(this.a); }, } let p = obj.print; obj.print(); p();
以上程序输出:o undefined
this指向无法传递,所以函数p的this是指向window,同时因为let声明的变量不会挂载到window上所以是window下的a变量只能是undefined。
obj.print方法this指向的是obj所以输出的是obj里面的变量a的值即o