思维导图
call,apply,bind 都可以改变 this 的指向
一、call 格式 [function].call([this], [param]...),一句话概括:call()
将函数的 this
指定到 call()
的第一个参数值和剩余参数指定的情况下调用某个函数或方法。
思考
1. 热身题1
function fn(a, b) {
console.log(this, a, b)
}
var obj = {
name: '林一一'
}
fn.call(obj, 20, 23) // {name: "林一一"} 20 23
fn.call(20, 23) // Number {20} 23 undefined
fn.call() //Window {0: global, window: …} undefined undefined | 严格模式下为 undefined
fn.call(null) //Window {0: global, window: …} undefined undefined | 严格模式下为 null
fn.call(undefined) //Window {0: global, window: …} undefined undefined | 严格模式下为 undefined
2. 热身题 2
var obj1 = {
a: 10,
fn: function(x) {
console.log(this.a + x)
}
}
var obj2 = {
a : 20,
fn: function(x) {
console.log(this.a - x)
}
}
obj1.fn.call(obj2, 20) //40
二、apply 和 call 基本一致
两者唯一不同的是:apply 的除了一个this指向的参数外,第二个参数是数组[arg1, arg2...],call的第二参数是列表(arg1, arg2...)
var name = '二二'
var obj = {
name: '林一一',
fn: function() {
return `${this.name + [...arguments]}`
}
}
obj.fn.apply(window, [12, 23, 34, 56]) // "二二12,23,34,56"
面试题
1. 模拟实现内置的 call(),apply()方法。
- call 的模拟实现
Function.prototype.myCall = function (context, ...args){
context = context || window
// 这里的 this 是指向 fn 的,通过 this 就可以获取 fn,context 是我们的 obj,可以直接给 obj 添加一个函数属性
context.fn = this
delete context.fn(...args)
return
}
var name = '二二'
var obj = {
name: '林一一',
}
function fn() {
console.log(this.name, ...arguments)
}
fn.myCall(null)
fn.myCall(obj, 12, 23, 45, 567)
- apply 的模拟实现
Function.prototype.myApply = function (context, args){
context = context || window
context.fn = this
delete context.fn(args)
return
}
2. call 和 apply 区别
var name = '二二'
var obj = {
name: '林一一'
}
function fn(){
console.log(this.name, ...arguments)
}
fn.apply(obj, [12, 34, 45, 56]) //fn(12, 23, 45, 56) 林一一 12 34 45 56
三、bind
- 返回一个新函数,这个新函数执行时的
this
才指定到bind
的第一个参数 bind
的剩余参数,传递给新的函数- 返回后的新函数是自我调用的
小思考
1. 上面说的这个新函数是啥?
一个小栗子
var name = '二二'
var obj = {
name: '林一一'
}
function fn(){
return `${this.name} ` + [...arguments]
}
let f = fn.bind(obj, 12, 23, 45, 67, 90)
f() // "林一一 12,23,45,67,90"
2. bind 是怎么实现拷贝 fn 的?
面试题
1. bind() 和 call()、apply() 的区别
2. 模拟实现内置的 bind() 方法。
下面的代码来自 JavaScript深入之bind的模拟实现
Function.prototype.bind2 = function (context) {
if (typeof this !== "function") {
throw new Error("Function.prototype.bind - what is trying to be bound is not callable");
}
var self = this;
var args = Array.prototype.slice.call(arguments, 1);
var fNOP = function () {};
var fBound = function () {
var bindArgs = Array.prototype.slice.call(arguments);
return self.apply(this instanceof fNOP ? this : context, args.concat(bindArgs));
}
fNOP.prototype = this.prototype;
fBound.prototype = new fNOP();
return fBound;
}
四、思考题
1. 求数组中的最大值和最小值
-
let arr = [12, 45, 65, 3, 23, 11, 76, 8, 9, 56, 70] let max = Math.max(...arr) // 76 let min = Math.min(...arr) // 3
-
let arr = [12, 45, 65, 3, 23, 11, 76, 8, 9, 56, 70] let list = arr.sort(function(a, b) { return b - a }) let max = list[0] // 76 let min = list[list.length - 1] // 3
-
let arr = [12, 45, 65, 3, 23, 11, 76, 8, 9, 56, 70] let max = Math.max.apply(null, arr) // 76 let min = Math.max.apply(null, arr) // 3
2. 如何判断一个数组
let arr = []
Object.prototype.toString.call(arr)
3.Object.prototype.toString.call() 为什么可以用来判断类型
Object.prototype.toString.call('str') // "[object String]"
Object.prototype.toString.call(123) // "[object Number]"
Object.prototype.toString.call({}) // "[object Object]"
Object.prototype.toString.call([]) // "[object Array]"
Object.prototype.toString.apply({}) // "[object Object]"
Object.prototype.toString.apply([]) // "[object Array]"
var f = Object.prototype.toString.bind({})
f() // "[object Object]"
var fn = Object.prototype.toString.bind([])
fn() // "[object Array]"
4.使用 call() 实现将类数组转化成数组
let array = [12, 23, 45, 65, 32]
function fn(array){
var args = [].slice.call(arguments)
return args[0]
}
fn(array) // [12, 23, 45, 65, 32]
参考
JavaScript深入之call和apply的模拟实现
JavaScript深入之bind的模拟实现
MDN bind
结束
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!