欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Js基础之this指向问题

程序员文章站 2024-03-23 21:57:22
...

一、为什么要用this

能够隐式的传递对象引用,更加简洁。

二、this指向规则和词法作用域

词法作用域:作用域由函数书写代码时决定(定义时上下文)

this指向规则:不指向函数词法作用域,不指向函数本身,由函数调用时的位置决定(运行时上下文,类似于动态作用域)

三、this指向规则

this的指向规则如下四条,优先级为:new +构造函数 > 显式绑定 > 隐式绑定 > 默认

1.默认(独立调用)

独立函数调用情况下,this指向全局变量或undefined。

(1)函数在非严格模式下,this指向全局变量

(2)函数在严格模式下(use strict),this 指向undefined

2.隐式绑定

(1)调用位置有上下文对象的,this绑定在上下文对象上

(2)调用位置有多个链式上下文对象的,this绑定在就近的对象上

注意:隐式绑定可能会出现this的隐式丢失,原因如下:

var f = function () {
  console.log(this.x);
}

var x = 1;
var obj = {
  f: f,
  x: 2,
};

// 单独执行
f() // 1

// obj 环境执行
obj.f() // 2

Js基础之this指向问题Js基础之this指向问题

 

(上例和图片来自http://www.ruanyifeng.com/blog/2018/06/javascript-this.html

由以上例子能够看出,当定义一个对象,并在对象中定义函数的过程是先开辟一个内存存储函数,然后将地址传递给对象的foo。当调用foo()时,是直接调用全局中的foo函数;当调用obj.foo()时是访问obj.foo存储的地址,此时this指向obj。

若再次定义var a = obj.foo;即将地址传给了全局的a,此时调用a()相当于直接调用全局中的函数,此时this指向全局变量(非严格模式下)造成this的隐式丢失

在回调函数和参数传递(隐式赋值)时,容易发生this的隐式丢失。

隐式丢失的解决办法:

(1)var self = this

(2)硬绑定(bind)

(3)箭头函数(ES6)

3.显式绑定

显式的绑定this指向可以采用call()、apply()和硬绑定bind()

call()和apply()的作用完全一样,只是参数传递方式不一样

(1)函数.call ( this新指向,数据1,... ,数据n)

将函数中的this指向新指向,并向该函数传递数据1-n

(2)函数.apply(this新指向,数组或类数组) 其中数组或类数组为:[数据1,... ,数据n]

将函数中的this指向新指向,并向该函数传递数组 [数据1,...,数据n]

call()和apply() 的用法:

  • 劫持别人的方法
var foo = {
  name:"mingming",
  logName:function(){
    console.log(this.name);
  }
}
var bar={
  name:"xiaowang"
};
foo.logName.call(bar);//xiaowang
  • 实现继承
function Animal(name){   
  this.name = name;   
  this.showName = function(){   
    console.log(this.name);   
  }   
}   
 
function Cat(name){  
  Animal.call(this, name);  
}   
 
var cat = new Cat("Black Cat");   
cat.showName(); //Black Cat
  • 强制改变this指向
window.id="window";
document.querySelector('#test').onclick = function(){
  console.log(this.id);//test
  var fun = function(){
    console.log(this.id);
  }
  fun();//window
  fun.call(this);//test
}

(3)硬绑定bind(未完)

bind()是ES5新增(IE6,7,8不支持)

var  新函数 = 旧函数.bind(this新指向,数据1,... ,数据n)

bind() 作用和前两个相同,即改变this指向

call()和apply()在改变指向以后立即执行改变后的函数,而bind()却返回一个改变后的新函数。

注意:call(),apply()和bind() 在非严格模式下,第一个参数为null或者undefined时this会自动替换为指向全局对象

4.new+构造函数

在传统面向对象语言中,构造函数是类的特殊函数

在JavaScript中,构造函数只是能够使用new操作符调用的普通函数,他不属于某个类,也不能实例一个类

当使用new 来调用构造函数时,自动执行一下操作:

(1)创建一个新的对象

(2)对新对象执行 [[原型]] 连接

(3)把新对象绑定到函数的this

(4)若函数没有返回其他对象,则函数自动返回这个新对象

四、ES6改进(箭头函数)

箭头函数的this不按照以上四条规则,而是按照词法作用域由外部作用域决定this指向

箭头函数能够通过call、apply、bind 改变this指向,但只能改变一次

参考资料:

http://www.ruanyifeng.com/blog/2018/06/javascript-this.html

 https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Function/bind