前端八股总结-函数、对象和this

Last updated on November 3, 2024 pm

记录一下一些常见场景

(崩溃了,怎么就是看不懂🥹小小this赶紧让我拿下)

this部分参考总结于嗨,你真的懂this吗? · Issue #6 · YvetteLau/Blog

一、this的绑定规则

(1)默认绑定

默认绑定,在不能应用其它绑定规则时使用的默认规则,通常是独立函数调用

  • 在非严格模式下,函数内的 this 指向全局对象(浏览器中是 window,Node.js 中是 global),除非该函数是作为对象的方法调用。
  • 在严格模式下,如果函数是直接调用(不通过对象调用),this 将会是 undefined

浏览器中,使用 var 定义(let不行)的全局变量(如 name)会被添加到 window 对象上。

在 Node.js 中,使用 var 定义的全局变量不会自动添加到 global 对象上。相反,它们只能在当前模块的作用域中访问。

  • global.name = ‘YvetteLau’;只有这样的显示定义才被视为定义

(2)隐式绑定

函数的调用是在某个对象上触发的,即调用位置上存在上下文对象。

1
2
3
4
5
6
7
8
9
function sayHi(){
console.log("hello,",this.name);
}
let person={
name: "Yaoyao",
sayHi: sayHi,
}
let name="Shenshen";
person.sayHi(); //Hello,Yaoyao.

对象属性链中只有最后一层会影响到调用位置:

1
2
3
4
5
6
7
8
9
10
11
12
function sayHi(){
console.log("hello,",this.name);
}
let person1={
name: "Yaoyao",
sayHi: sayHi,
}
let person2={
name: "Shenshen",
friend: person1,
}
person2.friend.sayHi(); //Hello,Yaoyao.

不是通过对象来进行调用仍旧是默认指向!!!

1
2
3
4
5
6
7
8
9
10
function sayHi(){
console.log("hello,",this.name);
}
let person={
name: "Yaoyao",
sayHi: sayHi,
}
var name="Shenshen";
let Hi=person.sayHi;
Hi();

在上面的例子中,输出的是Shenshen。因为Hi绑定在sayHi上,调用时和person没有关系

下一个例子:(隐形绑定的丢失会发生在回调函数中)(在浏览器运行)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
function sayHi(){
console.log("hello,",this.name);
}
let person1={
name: "Yaoyao",
sayHi: function(){
setTimeout(function(){
console.log('Hello,',this.name); //setTimeout的回调函数中,this使用的是默认绑定
})
}
}
let person2={
name: "Shenshen",
sayHi: sayHi
}
var name="Shanshan";
person1.sayHi(); //Hello, Shanshan
setTimeout(person2.sayHi,1000); //Hello, Shanshan
setTimeout(function(){
person2.sayHi();
},1000); //Hello, shenshen

(在node中运行时就算显式指定global.name的值还是会输出undefined,不知道为什么)

(3)显式绑定

显式绑定的丢失:

1
2
3
4
5
6
7
8
9
10
11
12
function sayHi(){
console.log('Hello,', this.name);
}
var person = {
name: 'YvetteLau',
sayHi: sayHi
}
var name = 'Wiliam';
var Hi = function(fn) {
fn();
}
Hi.call(person, person.sayHi);

这时候,fn是person.sayHi,将this绑定到了Hi的this,但是执行fn的时候相当于直接调用了sayHi方法,此时隐式绑定也丢了,对应的是默认绑定。

解决方法是在调用fn的时候也硬绑定

1
2
3
var Hi = function(fn) {
fn.call(this);
}

如果我们将null或者是undefined作为this的绑定对象传入call、apply或者是bind,这些值在调用时会被忽略,实际应用的是默认绑定规则。

(4)new绑定

使用new来调用函数会自动执行下面的操作:

1、创建一个新对象

2、将构造函数的作用域赋值给新对象(即this指向这个新对象)

3、执行构造函数中的代码

4、返回新对象

1
2
3
4
5
function sayHi(name){
this.name=name;
}
var Hi=new sayHi("Yaoyao");
console.log(Hi.name); //Yaoyao

(5)绑定优先级

new绑定>显式绑定>隐式绑定>默认绑定

(6)箭头函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
var obj = {
hi: function(){
console.log(this);
return ()=>{
console.log(this);
}
},
sayHi: function(){
return function() {
console.log(this);
return ()=>{
console.log(this);
}
}
},
say: ()=>{
console.log(this);
}
}
let hi = obj.hi(); //输出obj对象————①
hi(); //输出obj对象————②
let sayHi = obj.sayHi();
let fun1 = sayHi(); //输出window————③
fun1(); //输出window————④
obj.say(); //输出window————⑤

①:通过对象调用函数,属于隐式调用。this指向obj

②:箭头函数是从上一个作用域继承this,所以这时指向的是obj

③:这是上面的隐式绑定丢失的情况,this指向window

④:这一步执行的是箭头函数,继承上一个作用域,this指向window

⑤:当前代码块中obj中不存在this,因此再向上找就找到了window

如果这样去显式绑定:(箭头函数不能显式绑定)

1
2
3
let sayHi=obj.sayHi();
let fun1=sayHi.bind(obj);
fun1();

(7)例题

1、
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
var number = 5;
var obj = {
number: 3,
fn: (function () {
var number;
this.number *= 2;
number = number * 2;
number = 3;
return function () {
var num = this.number;
this.number *= 2;
console.log(num);
number *= 3;
console.log(number);
}
})()
}
var myFun = obj.fn;
myFun.call(null);
obj.fn();
console.log(window.number);

输出结果分别为10、9、3、27、20

2、
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var obj = {
a: 'obj',
foo: function () {
console.log('foo:', this.a)
return function () {
console.log('inner:', this.a)
}
}
}
var a = 'window'
var obj2 = { a: 'obj2' }

obj.foo()()
obj.foo.call(obj2)()
obj.foo().call(obj2)

①:分别打印出的是obj.a和window.a

②:分别打印的是obj2.a和window.a

③:分别打印的是obj.a和obj2.a

3、
1
2
3
4
5
6
7
8
9
10
11
12
13
14
var obj = {
a: 1,
foo: function (b) {
b = b || this.a
return function (c) {
console.log(this.a + b + c)
}
}
}
var a = 2
var obj2 = { a: 3 }

obj.foo(a).call(obj2, 1)
obj.foo.call(obj2)(1)

①:传入foo的参数为a=2,也就是说b=2;call方法将this绑定到obj2,this.a=3,此时c=1

②:foo绑定至obj2,此时没有传入参数,b=this.a=obj2.a=3,return匿名函数中的this.a指向window对象a=2,传入的参数c=1。


前端八股总结-函数、对象和this
http://example.com/2024/11/03/前端八股总结-函数、对象和this/
Author
Yaodeer
Posted on
November 3, 2024
Licensed under