/**
* @author haiyuan.wang
* @date 2021.04.01
* @vision 1.0
*
* @description call 方法主要的作用是改变函数的执行环境
* @example fn.call(thisArg, arg1, arg2, ...)
* @param {Object} thisArg 必选的。运行时的 this 值,非严格模式下,null 和 undefined 会自动指向 window
* @param {*} arg1, arg2, ... 可选的。执行过程中要传入的参数
*/
// 第一个例子,使用 call 方法调用父构造方法,实现继承
// 基类 Goods
function Goods(goods, amount, price) {
this.goods = goods
this.amount = amount
this.price = price
}
// 子类,继承基类的属性
function Fruit(goods, amount, price) {
Goods.call(this, goods, amount, price)
}
let fruit = new Fruit('orange', 100, 50)
console.log('fruit :>> ', fruit); // Fruit { goods: 'orange', amount: 100, price: 50 }
// 第二个例子,使用 call 调用函数的,并且指定上下文的 this
let tempObj = {
language: 'JavaScript',
}
function getLanguage() {
return this.language
}
console.log(getLanguage.call(tempObj)); // JavaScript
// 实现一个自己的 call 方法
;(function() {
if(!Function.prototype.myCall) { // 给 Fuction 类的原型上加 myCall 属性
Function.prototype.myCall = function myCall(context, ...args) {
let fn = this; // 谁调用myCall谁就是this,所以this就是原函数
console.log(fn); // getLanguage 函数
if(typeof fn !== 'function') throw TypeError `${fn} is not a funtion` // 如果不是函数,抛出一个类型错误
let key = Symbol('key')
if (typeof context === 'undefined' || context === null) { // 判断是否是undefined和null
context = window
}
context[key] = fn // 将 fn 挂在到 context 的属性上,通过 context.fn() 这种形式调用,就实现了改变this(谁调用fn,谁就是this)
let result = context[key](...args)
delete context[key]
return result
}
}
})()
console.log(getLanguage.myCall(tempObj)); // JavaScript
// console.log(/sdf/.myCall(tempObj)); // /sdf/.myCall is not a function
// 复杂数据类型 Object: Date regExp function Array
// 基本数据类型: string number Boolean null undefined