js 【详解】函数中的 this 指向

简介: js 【详解】函数中的 this 指向

this 在各个场景中取什么值,是在函数执行的时候确认的,不是在函数定义的时候确认的。

普通函数中,无调用对象 —— 指向 window

  • 在非严格模式下,this 指向全局对象 window
  • 在严格模式下,this 为undefined
function fun() {
    console.log(this); // 打印 window 对象
    console.log(this.name); // 打印 "全局的name属性"
}

var name = "全局的name属性";

fun();      

通过 bind 绑定 —— 指向第一个参数

this 指向 bind 方法的第一个参数(对箭头函数无效)

function fn() {
  console.log(this);
}

const fn1 = fn.bind({ x: 200 });
fn1(); // 打印 { x: 200 }

通过 call 和 apply 调用 —— 指向第一个参数

this 指向call和apply方法的第一个参数(对箭头函数无效)

function fn() {
  console.log(this);
}

fn.call({ x: 100 }); // 打印 { x: 100 }
var some_obj = {
  name: 'Ninja',
  say: function(who){
    return 'Haya ' + who + ', I am a ' + this.name;
  }
};

> some_obj.say('Dude');
"Haya Dude, I am a Ninja"

> var my_obj = {name: 'Scripting guru'};

> some_obj.say.call(my_obj, 'Dude');
"Haya Dude, I am a Scripting guru"

调用 say() 函数的对象方法 call() 时传递了两个参数:对象 my_obj 和字符串 ‘Dude’ 。

当say() 被调用时,其中的 this 被自动设置成了my_obj 对象的引用。

因而,this.name返回的不再是Ninja,而是Scripting guru。

函数作为对象方法被调用 —— 指向对象

this 指向该对象

function fun() {
    console.log(this);  // 打印 obj2  对象
    console.log(this.name);  // 打印 "vae"
}

var obj2 = {
    name: "vae",
    sayName: fun
};

var name = "全局的name属性";

//以方法的形式调用,this是调用方法的对象
obj2.sayName();

函数作为实例方法被调用 —— 指向实例

this 指向实例

 // 创建一个构造函数,专门用来创建Person对象
 function Person(name, age, gender) {
   this.name = name;
   this.age = age;
   this.gender = gender;
   this.sayName = function() {
     console.log(this.name); // 打印 "孙悟空"
   };
 }

let per = new Person("孙悟空", 18, "男");
per.sayName() 

如果构造函数返回一个对象,则该对象将作为整个表达式的值返回,而传入构造函数的this将被丢弃。

箭头函数中的 this —— 指向外层的 this

继承外层函数的 this (使用 call , bind , apply 都无法改变 this 的指向

经典问题如下:

var greeter = {
  default: "Hello ",
  greet: function (names){
    names.forEach(function(name) {
      console.log(this.default + name); //此时的this是全局的window,不能读取对象的属性default
    })
  }
}
console.log(greeter.greet(['world', 'heaven']))

传统的解决方案——将this赋值给一个临时变量,然后在回调函数中访问:

var greeter = {
  default: "Hello ",
  greet: function (names){
    let that = this
    names.forEach(function(name) {
      console.log(that.default + name);
    })
  }
}
console.log(greeter.greet(['world', 'heaven']))

箭头函数可直接解决此问题——this继承外层函数调用的this绑定,此时的this是对象greeter

var greeter = {
  default: "Hello ",
  greet: function (names){
    names.forEach(name=> {
      console.log(this.default + name); //该子程序可以使用词法'this'
    })
  } 
}
console.log(greeter.greet(['world', 'heaven']))

  • this 都指向当前对象 zhangsan

类的静态方法中的 this —— 指向类

// class 相关的 this
class Foo {
    f1() { console.log('this1', this) }
    f2 = () => { console.log('this2', this) }
    f3 = () => { console.log('this3', this) }
    static f4() { console.log('this4', this) }
}
const f = new Foo()
f.f1() // 打印 this1 f  实例方法中的this 指向 实例
f.f2() // 打印 this2 f  箭头函数中的this 指向外层 -- 也是实例
f.f3.call(this) // 打印 this3 f  call 无法改变箭头函数的this指向,所以还是实例
Foo.f4() // 打印 this4 Foo  类的静态方法中的this指向类

自测题 1

答案:

1
undefined
  • User.getCount() 是执行对象方法,this 指向该对象,其 count 属性值为 1
  • func() 是普通函数,无调用对象,this 指向 window , 因全局没有 count 变量,window.count 为 undefined

自测题 2

const obj = {
  f1() {
    const fn = () => {
      console.log(this);
    };
    fn();
    fn.call(Window);
  },
  f2: () => {
    function fn() {
      console.log(this);
    }
    fn();
    fn.call(this);
  },
};

obj.f1();
obj.f2();

答案:

obj对象
obj对象
Window对象
Window对象
  • 普通函数无调用对象,指向 Window
  • 箭头函数指向外层 this
  • call 无法改变箭头函数的 this 指向
目录
相关文章
|
12天前
|
JavaScript 前端开发 Java
[JS]同事:这次就算了,下班回去赶紧补补内置函数,再犯肯定被主管骂
本文介绍了JavaScript中常用的函数和方法,包括通用函数、Global对象函数以及数组相关函数。详细列出了每个函数的参数、返回值及使用说明,并提供了示例代码。文章强调了函数的学习应结合源码和实践,适合JavaScript初学者和进阶开发者参考。
24 2
[JS]同事:这次就算了,下班回去赶紧补补内置函数,再犯肯定被主管骂
|
11天前
|
前端开发 JavaScript 开发者
除了 Generator 函数,还有哪些 JavaScript 异步编程解决方案?
【10月更文挑战第30天】开发者可以根据具体的项目情况选择合适的方式来处理异步操作,以实现高效、可读和易于维护的代码。
|
25天前
|
JavaScript 前端开发
JavaScript 函数语法
JavaScript 函数是使用 `function` 关键词定义的代码块,可在调用时执行特定任务。函数可以无参或带参,参数用于传递值并在函数内部使用。函数调用可在事件触发时进行,如用户点击按钮。JavaScript 对大小写敏感,函数名和关键词必须严格匹配。示例中展示了如何通过不同参数调用函数以生成不同的输出。
|
27天前
|
存储 JavaScript 前端开发
JS函数提升 变量提升
【10月更文挑战第6天】函数提升和变量提升是 JavaScript 语言的重要特性,但它们也可能带来一些困惑和潜在的问题。通过深入理解和掌握它们的原理和表现,开发者可以更好地编写和维护 JavaScript 代码,避免因不了解这些机制而导致的错误和不一致。同时,不断提高对执行上下文等相关概念的认识,将有助于提升对 JavaScript 语言的整体理解和运用能力。
|
2月前
|
JavaScript 前端开发 安全
JavaScript函数详解
JavaScript函数的详细解析,包括函数的定义和调用方式(如一般格式、匿名函数、构造函数、自调用函数、箭头函数和严格模式)、函数参数(arguments对象、可变参数、默认参数值)、闭包的概念和应用实例。
JavaScript函数详解
|
1月前
|
JavaScript 前端开发
js教程——函数
js教程——函数
32 4
|
1月前
|
存储 JavaScript 前端开发
js中函数、方法、对象的区别
js中函数、方法、对象的区别
16 2
|
1月前
|
JavaScript 前端开发 Java
【javaScript数组,函数】的基础知识点
【javaScript数组,函数】的基础知识点
23 5
|
1月前
|
JavaScript 前端开发
Node.js 函数
10月更文挑战第5天
22 3
|
1月前
|
前端开发 JavaScript
探索JavaScript函数基础
探索JavaScript函数基础
18 3