荐 如何灵活运用JavaScript中的this
JavaScript中的this
面对对象的语言中,this表示当前对象的一个引用,但在JavaScript中,this不是固定不变的,它会随之执行环境的改变而改变。
一般情况下this指向全局变量window
作为对象方法调用时,this
指向上级对象
作为构造函数调用时,this指向new
出的对象
在函数中,非严格模式下this指向全局对象,但是在严格模式下this指向undefined
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LwMy7ONK-1594614184278)(])
在事件中,this表示接收事件的元素
欢迎访问我的网站: www.dengzhanyong.com
改变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
类型的值时,会自动将其转为对应的包装对象。
常见应用场景
查找数组最大元素
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
上一篇: HTML常用标签(下)
下一篇: 独立出来的几种轮播图写法