1.应用场景
new、apply、call、bind都作用在函数上并且会改变函数this的指向,通俗地讲是“借用其他人的方法”
b借用a的方法:
let a = {
name:'wyy',
getName:function(msg){
return msg+this.name
}
}
let b = {
name:'cyt'
}
console.log(a.getName("hello~"));
console.log(a.getName.call(b,'hi~'));
console.log(a.getName.apply(b,['hi~']));
let say = a.getName.bind(b,'hi~')
console.log(say());
call和apply的区别在于参数的形式,apply是以数组的形式进行传参
fun.call(thisArg,p1,p2......)
fun.apply(thisArg,[p1, p2,.......])
fun.bind(thisArg,p1,p2.......)、
- 判断数据类型
- 类数组借用方法
- 获取数组的最大值、最小值
- 继承
2.手写实现
(1)new方法(只有function才此方法)
- 创建一个新对象
- 将构造函数作用域赋值给新对象(让构造函数的this指向这个新对象)
- 执行构造函数(为新对象添加属性)
- 返回新对象
new关键字执行之后总是会返回一个对象,要不是新对象,要不就是return语句指定的对象。
function _new(ctor, ...args){
if(typeof ctor !== 'function'){
throw 'ctor is must a function'
}
let obj = new Object()
// 改变实例对象的指向,指向构造函数的原型链
obj.__proto__ = Object.create(ctor.prototype)
let res = ctor.apply(obj,...args)
let isObject = typeof res === 'object'&&res !== null
let isFunction = typeof res === 'function';
// return返回的是新创建的实例对象或者是函数指定的return对象
return isObject||isFunction ? res:obj
}
(2)call方法手写实现
Function.prototype.call = function(context,...args){
var context = context || window;
context.fn = this;
// 直接执行函数,eval()输入参数是字符串
var result = eval('context.fn(context.fn(...args))')
delete context.fn
return result
}
(3)apply方法手写实现(传的参数没有扩展符)
Function.prototype.apply = function(context,args){
var context = context || window;
context.fn = this;
// 直接执行函数,eval()输入参数是字符串
var result = eval('context.fn(context.fn(...args))')
delete context.fn
return result
}
(4)bind方法手写实现
// bind方法返回的是一个函数
Function.prototype.bind = function (context, ...args) {
if (typeof this !== 'function') {
throw new Error('this must be a function')
}
var self = this;
var fbound = function () {
self.apply(this instanceof self ? this : context,
args.concat(Array.prototype.slice.call(arguments)))
}
if (this.prototype) {
fbound.prototype = Object.create(this.prototype)
}
return fbound
}