前提
学习本篇前提应具备原型、原型链的相关知识,详情可见【JS 原型与原型链】。
本文为了也检验自己对原型、原型链的掌握程度。 故本文没有实现过程,只有示例和实现结果,如有错误的欢迎留言指正。
1. call
Function.prototype.call 函数,接收一个或多个参数来调用,第一个参数是this。详情可见MDN Call
call使用示例
let obj = {
name: 'hahaha',
Func: function ( num1,num2) {
console.log(this.name, num1,num2)
}
}
let p = { name: 'guoby' }
obj.Func(1,2) // hahaha, 1, 2
obj.Func.call(p,1,2) // guoby, 1, 2
实现MyCall函数
- 让所有函数都有MyCall这个方法,既需要在Function的原型上挂载该函数。
- MyCall 函数第一个值是this非严格模式默认是window。
- 通过传递过来的this去调用 MyCall函数的调用者。
Function.prototype.MyCall = function (context, ...args) {
context = context || window
const fn = Symbol('fn');
context[fn] = this // this指向调用者,即当前作用域this为调用MyCall的函数
let res = context[fn](...args) // this指向调用者,既fn()中的this指向 context
delete context[fn]
return res
}
2. apply
第一个参数是this,和call不同的是 其余参数以一个数组的形式提供的参数。详情可见MDN apply
apply使用示例
obj.Func.apply(p,[1,2,3]) // guoby [1, 2, 3]
实现MyApply
Function.prototype.MyApply = function (context, args) {
context = context || window
const fn = Symbol('fn');
contex[fn] = this // this指向调用者,即当前作用域this为调用MyCall的函数
let res = context.[fn](...args) // this指向调用者,既fn()中的this指向 context
delete context._fn
return res
}
3. bind
bind不立即执行,接受多个参数。返回一个函数。详情可见MDN bind
bind使用示例:
function Func () {
console.log(this)
}
let obj = {
name: 'guoby'
}
let fn = Func.bind(obj,1,2);
// 第一种用法:
fn(2,3) // {name: 'guoby'} [1, 2, 2, 3]
// 第二种用法
new fn(4,5) // Func {} [1, 2, 4, 5]
// 【注意:此时this的指向为所在函数】
实现MyBind
Function.prototype.MyBind = function (context, ...args) {
let that = this;
const MyBindCb = function (...args2) {
let context_ = context
// new调用的情况 即:this.__proto__ == MyBindCb.prototype // true
if(this instanceof MyBindCb) {
context_ = that
}
// todo: 校验args和args2 都没有则 that.apply(context_)
return that.apply(context_,args.concat(args2))
}
return MyBindCb
}
instanceof
instanceof 判断某个对象是不是某个构造函数的实例对象,详情可见MDN instanceof。
使用示例
function Func () {}
let fn = new Func()
fn instanceof Func // true
fn instanceof Object // true
实现MyInstanceof
function MyInstanceof (objInstance, Func) {
// todo: 校验 objInstance, Func 是否有原型
// todo:校验 Func 是否为函数
let objProto = objInstance.__proto__
let FuncP = Func.prototype
while(true) {
if(!objProto) return false
if(objProto == FuncP) return true
objProto = objProto.__proto__ // 指针向下找
}
}
typeof
返回元素的类型,typeof 不能判断对对象的实际类型,详情可见MDN tyoeof
使用示例
typeof 2 // number
typeof '' // string
typeof {} // object
typeof [] // object
typeof null // object
function Func () {}
typeof Func // function
实现MyTypeof
function MyTypeof(context){
return context.constructor.name
} // 对null undefined不好使
// 使用 Object.prototype.toString.call()
function MyTypeof2(context){
return Object.prototype.toString.call(context).slice(8,-1).toLowerCase();
}
new
可参见原型链的这节探索使用new有什么不一样?