当前位置: 移动技术网 > IT编程>开发语言>JavaScript > 荐 如何灵活运用JavaScript中的this

荐 如何灵活运用JavaScript中的this

2020年07月14日  | 移动技术网IT编程  | 我要评论

JavaScript中的this

面对对象的语言中,this表示当前对象的一个引用,但在JavaScript中,this不是固定不变的,它会随之执行环境的改变而改变。

一般情况下this指向全局变量window

作为对象方法调用时,this指向上级对象

作为构造函数调用时,this指向new出的对象

在函数中,非严格模式下this指向全局对象,但是在严格模式下this指向undefined

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LwMy7ONK-1594614184278)(在这里插入图片描述])

在事件中,this表示接收事件的元素

欢迎访问我的网站: www.dengzhanyong.com

改变this的指向

在JavaScript中,我们可以通过callapplybind来改变this的指向,以满足不同的场景需求。

举个栗子

var apple = {
  name: '苹果',
  color: '红色',
  fn: function(){
    console.log(`${this.name}${this.color}的`)
   }
 }
apple.fn()   //苹果是红色的

有一个apple对象,它有namecolor两个属性,还有一个方法fn用来打印出name和color。

如果现在有一个新的对象banana

var banana = {
  name: '香蕉',
  color: '黄色'
}

现在我也想打印出banana的信息,但是我并不想再写一遍fn方法,如果可以直接利用apple的fn方法那就简化了很多。

apple.fn.call(banana)   //香蕉是黄色的

通过call方法可以改变apple.fn中this的指向,指向的对象为接受的第一个参数。我们还可以在后面传入多个参数,就像下面这样:

var apple = {
  name: '苹果',
  color: '红色',
  fn: function(price, unit){
    console.log(`${this.name}${this.color}的,${price}元/${unit}`)
  }
}

apple.fn.call(banana, 3.99, '斤') //香蕉是黄色的,3.99元/斤

apply与call的用法几乎相同,唯一的区别就是传入参数不同,第一个参数同样是目标对象,剩余的参数以一个数组的形式传入,如下:

apple.fn.apply(banana, [3.99, '斤']) //香蕉是黄色的,3.99元/斤

bind的作用也是改变this的指向,但它与callapply不同的是,它会返回一个函数,而不是立即执行,传参方式与call相同。

var fn2 = apple.fn.bind(banana, 3.99, '斤')
fn2() //香蕉是黄色的,3.99元/斤

当第一个参数为nullundefinedNaN空字符串时,默认传入全局对象

如果第一个参数为numberboolean类型的值时,会自动将其转为对应的包装对象。

常见应用场景

查找数组最大元素

var a = [3, 9, 5, 3, 6]
console.log(Math.max.apply(null, a))   //9
console.log(Math.max.apply(undefined, a))   //9
console.log(Math.max.apply(NaN, a))   //9
console.log(Math.max.apply('', a))   //9
console.log(Math.max.call(null, ...a))   //9

将数组的空元素变为undefined

var b = [3, ,8 , , 4, 7]
console.log(Array.apply(null, b))   //[3, undefined, 8, undefined, 4, 7]
console.log(Array.call(null, ...b))   //[3, undefined, 8, undefined, 4, 7]

调用对象的原生方法

Object的hasOwnProperty()方法返回一个布尔值,判断对象是否包含特定的自身(非继承)属性。如果某个对象中重写了hasOwnProperty方法,那我们再使用hasOwnProperty()是无法得到正确的结果的。

var obj = {}
console.log(obj.hasOwnProperty('name'))   //false
obj.hasOwnProperty = function(){
return true
}
console.log(obj.hasOwnProperty('name'))   //true
console.log(Object.prototype.hasOwnProperty.call(obj, 'name'))   //false

在上面的代码中,在obj对象中使用原生的Object.prototype.hasOwnProperty方法可以避开使用被覆盖的hasOwnProperty

对于许多原生的方法,我们都可以使用call、apply、bind来得到同样的结果,他们是等价的,就像下面这样:

[1, 2, 3].slice(0, 1)  //[1]
Array.prototype.slice.call([1, 2, 3], 0, 1)    //[1]

使用ES6手写call、apply、bind

function add(c, d) {
return this.a + this.b + c + d;
}
const obj = { a: 1, b: 2 };
// ES6 call 实现
Function.prototype.es6call = function (context, ...rest) {
  var context = context || window;
  context.fn = this;
  const result = context.fn(...rest);
  delete context.fn;
  return result;
}
console.log(add.es6call(obj, 3, 4));  //10
  • context 代表接收的上下文环境,…rest接收的其他参数
  • 若context 为空值,则默认为window
  • 将被调用对赋值给context.fn,此时context.fn中可以访问到context中的其他属性,context.fn中的this不再指向它的原对象,而是新的对象context。

context.fn(…rest)将其他的参数传入函数中执行得到结果

Function.prototype.es6apply = function(context, arr){
  var context = context || window
  context.fn = this
  const result =  context.fn(...arr)
  delete context.fn
  return result
}
​
console.log(add.es6apply(obj, [3, 4]));  //10

apply的实现与call的实现几乎相同,唯一区别就是接受参数的形式不同,一个是多个参数形式,一个是把多个参数转为一个数组的形式。


Function.prototype.es6bind = function(context, ...rest) {
  var self = this;
  return function fn(...args) {
  var result =  this instanceof fn ? new self(...rest, ...args) : self.apply(context, rest.concat(args))
    return result
  }
}

bind接受参数与call相同,返回结果为一个函数

我的网站:www.dengzhanyong.com

关注我的公众号,不错过每一篇推送

本文地址:https://blog.csdn.net/DengZY926/article/details/107315133

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网