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 指向
目录
相关文章
|
5天前
|
JavaScript
js export 对外输出常量、变量和函数
js export 对外输出常量、变量和函数
12 5
|
4天前
|
JavaScript
js函数封装 —— 金额添加千分位分隔符
js函数封装 —— 金额添加千分位分隔符
10 2
|
4天前
|
JavaScript 前端开发 网络架构
JavaScript编码之路【对象的增强、ES6新特性之函数的默认值设置 、rest参数 (剩余参数)、拓展运算符、对象与数组的解构赋值】
JavaScript编码之路【对象的增强、ES6新特性之函数的默认值设置 、rest参数 (剩余参数)、拓展运算符、对象与数组的解构赋值】
7 1
|
9天前
|
JavaScript 前端开发
JavaScript作用域关乎变量和函数的可见范围。
【6月更文挑战第27天】JavaScript作用域关乎变量和函数的可见范围。全局作用域适用于整个脚本,局部作用域限于函数内部,而ES6引入的`let`和`const`实现了块级作用域。全局变量易引发冲突和内存占用,局部作用域在函数执行后消失,块级作用域提高了变量管理的灵活性。作用域关键在于组织代码和管理变量生命周期。
17 1
|
1天前
|
JavaScript
js 延时执行代码的最佳实践 —— 自定义 sleep 函数
js 延时执行代码的最佳实践 —— 自定义 sleep 函数
2 0
|
2天前
|
JavaScript
js 高频实用函数封装汇总(持续更新)
js 高频实用函数封装汇总(持续更新)
5 0
|
3天前
|
JavaScript
js 数组移除指定元素【函数封装】(含对象数组移除指定元素)
js 数组移除指定元素【函数封装】(含对象数组移除指定元素)
4 0
|
3天前
|
JavaScript
js 调试 —— 断点(含进入函数、条件断点等)
js 调试 —— 断点(含进入函数、条件断点等)
8 0
|
3天前
|
JavaScript
JS【详解】函数.bind()
JS【详解】函数.bind()
4 0
|
3天前
|
JavaScript 前端开发