您的位置:首页 > 财经 > 产业 > 全景图网页制作工具_免费网页制作系统团队_站内优化主要从哪些方面进行_网站快速推广

全景图网页制作工具_免费网页制作系统团队_站内优化主要从哪些方面进行_网站快速推广

2024/10/31 17:09:52 来源:https://blog.csdn.net/qq_36647492/article/details/143043659  浏览:    关键词:全景图网页制作工具_免费网页制作系统团队_站内优化主要从哪些方面进行_网站快速推广
全景图网页制作工具_免费网页制作系统团队_站内优化主要从哪些方面进行_网站快速推广

前置知识

  • this 关键字
  • js原型及原型链

背景

由于对象的属性可以赋给另一个对象,所以属性所在的当前对象是可变的,即this的指向是可变的。
this的动态切换,固然为 JavaScript 创造了巨大的灵活性,但也使得编程变得困难和模糊。
有时,需要把this固定下来,避免出现意想不到的情况。如果对this不太了解,可以先看一下我另一篇关于 this 的文章

概念

JavaScript 提供了call、apply、bind这三个方法,来切换/固定this的指向。

这三个方法都放在了Function对象的原型对象上,因此所有Function实例对象上都能调用这三个方法,也就是说只有函数才能调用这三个方法。

Function.prototype.call()

函数实例的call方法,可以指定函数内部this的指向(即函数执行时所在的作用域),然后在所指定的作用域中,调用该函数。

语法:func.call(thisValue, arg1, arg2, ...)
第一个参数是this所需要指向的那个对象;后面的参数是函数调用时所需的参数。

call 方法的第一个参数,应该是一个对象。如果参数为空、null、undefined,则默认传入全局对象

var n = 123;
var obj = { n: 456; };function a() {console.log(this.a);
}a.call(); // 123
a.call(null); // 123
a.call(undefined);  // 123
a.call(window); // 123
a.call(obj);  // 123

如果call方法的参数是一个原始值,那么这个原始值会自动转成对应的包装对象,然后传入call方法。

function f() {return this;
};f.call(5); // Number {[[PrimitiveValue]]: 5}

call方法的其中一个使用场景是调用对象的原生方法。

看下面示例:

var obj = {};
obj.hasOwnProperty('toString') // false// 覆盖掉继承的 hasOwnProperty 方法
obj.hasOwnProperty = function () {return true;
};
obj.hasOwnProperty('toString') // trueObject.prototype.hasOwnProperty.call(obj, 'toString') // false

上面代码中,hasOwnPropertyobj对象继承的方法,如果这个方法一旦被覆盖,就不会得到正确结果。
call方法可以解决这个问题,它将hasOwnProperty方法的原始定义放到obj对象上执行,这样无论obj上有没有同名方法,都不会影响结果。

可能最后一行有点绕,这里再啰嗦解释一下:
因为obj对象可能覆盖Object原型上的方法
因此,这里我们可以直接执行原型的方法。然后将函数内部的指向改为obj对象,并传入'toString'参数,这时候其实就等同于上面代码第二行
因为拿第二行来说,我们知道通过obj调用hasOwnProperty,这时候在hasOwnProperty函数内部,this肯定就是obj
因此最后一行的执行结果和第二行是一样的。区别在于,最后一行是直接调用的原始定义方法,不会受后续重写方法的影响

Function.prototype.apply()

apply方法的作用与call方法类似,也是改变this指向,然后再调用该函数。唯一的区别就是,它接收一个数组作为函数执行时的参数。
语法: func.apply(thisValue, [arg1, arg2, ...])

Function.prototype.bind()

概念: bind()方法用于将函数体内的this绑定到某个对象,然后返回一个新函数。

语法: func.bind(thisValue, arg1, arg2, /* …, */ argN)

bind()除了第一个绑定this参数之外,还可以接受更多的参数,将这些参数绑定原函数的参数。

例如func方法有3个参数,那么我们在绑定的时候可以预先传入几个参数,然后我们在后面实际调用新函数的时候,只需要传剩余参数即可。如下所示。

function func(x, y, z) {console.log(this.name, x, y, z);
}var obj = {name: '张三',
};var newFunc = func.bind(obj, 100);
newFunc(200, 300) // 张三 100 200 300

再来看下面这个例子

我们将d.getTime()方法赋给变量print,然后调用print()就报错了。
这是因为getTime()方法内部的this,绑定Date对象的实例,赋给变量print以后,内部的this已经不指向Date对象的实例了。

var d = new Date();
d.getTime() // 1481869925657var print = d.getTime;
print() // Uncaught TypeError: this is not a Date object.

bind()方法可以解决这个问题。

var print = d.getTime.bind(d);
print() // 1481869925657

上面代码中,bind()方法将getTime()方法内部的this绑定到d对象,这时就可以安全地将这个方法赋值给其他变量了。

再来看一个使人困惑的例子

利用bind()方法,可以改写一些 JavaScript 原生方法的使用形式,以数组的slice()方法为例。

var newSlice = Function.prototype.call.bind(Array.prototype.slice);
newSlice([1, 2, 3], 0, 1) // [1]

这段代码可能理解起来有点困难,又是call又是bind的,我们需要拆分出来理解。

首先,这行代码是直接调用了函数原型上的call函数。

然后我们再通过call函数(Function.prototype.call可以看成call) 调用一个bind方法来生成一个新的函数。

这里先将Array.prototype.slice看做是一个对象
然后通过调用bind方法将Array.prototype.slice变成Function.prototype.call方法所在的对象。

如果对上面这句话感到有点困惑的话,看这里~

首先我们来回顾一下bind方法的语法和概念
概念:bind()方法用于将函数体内的this绑定到某个对象,然后返回一个新函数。
语法:func.bind(thisValue)

通过对概念的理解,我们可以对语法做一个推算:
func.bind(thisValue) 就相当于 thisValue.func
其实这就是绑定this的原理: 将func变为了thisValue对象上的一个方法了。这时候func里的this指向,肯定就是指向thisValue对象了。
这只再回头看一下上面那句话,是否会清晰一下

上面看懂之后,调用时就变成了Array.prototype.slice.call

示例就可以写成下面这样

Function.prototype.call.bind(Array.prototype.slice)
// 等同于
Array.prototype.slice.call()
var slice = Function.prototype.call.bind(Array.prototype.slice);
// 这时候 slice 就相当于 Array.prototype.slice.call()
// 因此
slice([1, 2, 3], 0, 1) // [1]
// 等同于
Array.prototype.slice.call([1, 2, 3], 0, 1) // [1]
// 等同于
[1, 2, 3].slice(0, 1) // [1]

call/apply 和 bind的区别

call/apply是立即执行,bind是返回一个函数,后期需要的时候执行。
bind可以先传入部分参数,在执行的时候传入剩余参数;
call/apply因为是立即执行,所以要在调用的时候传入所有参数

参考链接

阮一峰 js教程
MDN官网

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com