您当前的位置: 首页 >  Java

知其黑、受其白

暂无认证

  • 0浏览

    0关注

    1250博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

JavaScript 中改变 this 的指向

知其黑、受其白 发布时间:2022-10-11 17:56:11 ,浏览量:0

阅读目录
  • 如何灵活的运用 this
    • 改变 this 的指向
    • 常见应用场景
      • 查找数组最大元素
      • 将数组的空元素变为 undefined
      • 调用对象的原生方法
      • 使用 ES6 手写 call、apply、bind

如何灵活的运用 this

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

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

在这里插入图片描述 作为对象方法调用时,this 指向上级对象。

在这里插入图片描述 作为构造函数调用时,this 指向 new 出的对象。 在这里插入图片描述

在函数中,非严格模式下 this 指向全局对象,但是在严格模式下 this 指向 undefined。 在这里插入图片描述 在这里插入图片描述 在这里插入图片描述

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

在这里插入图片描述

改变 this 的指向

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

举个栗子

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

有一个 apple 对象,它有 name 和 color 两个属性,还有一个方法 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 的指向,但它与 call 和 apply 不同的是,它会返回一个函数,而不是立即执行,传参方式与 call 相同。

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

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

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

在这里插入图片描述 index.js





c





	var banana = {
		name: '香蕉',
		color: '黄色'
	}
	var apple = {
		name: '苹果',
		color: '红色',
		fn: function() {
			console.log(`${this.name}是${this.color}的`)
		}
	}
	apple.fn()
	apple.fn.call(banana) //香蕉是黄色的
	var apple = {
		name: '苹果',
		color: '红色',
		fn: function(price, unit) {
			console.log(`${this.name}是${this.color}的,${price}元/${unit}`)
		}
	}
	apple.fn.call(banana, 3.99, '斤') //香蕉是黄色的,3.99元/斤
	apple.fn.apply(banana, [3.99, '斤']) //香蕉是黄色的,3.99元/斤

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





常见应用场景 查找数组最大元素
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 接收的其他参数。

1 若 context 为空值,则默认为 window。

2 将被调用对赋值给 context.fn,此时 context.fn 中可以访问到 context 中的其他属性,context.fn 中的 this 不再指向它的原对象,而是新的对象 context。

3 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 相同,返回结果为一个函数。

关注
打赏
1665558895
查看更多评论
立即登录/注册

微信扫码登录

0.0467s