继承的进阶:如何实现new、apply、call、bind的底层逻辑
首先我们从new开始,new关键词的主要作用是什么呢?
就是执行一个构造函数,返回一个实例对象根据构造函数的情况,来确定是否可以接受参数的传递。代码实现如下:
function Person(){
this.name = 'jack';
}
var p = new Person();
console.log(p.name)//jack
上述代码是p通过person这个构造函数实现的一个实例对象
那么new在底层逻辑中是如何实现的呢?
1.创建一个新对象
2.将构造函数的作用域赋给新对象(this指向的新对象)
3.执行构造函数中的代码(为这个新对象添加属性)
4.返回新对象
那么如果把new删除呢?
function person(){
this.name = 'jack'
}
var p = person();
console.log(p)//undefined
console.log(name)//jack
console.log(p.name)//'name'of undefined
上述就是去除了new方法的代码我们可以发现出现了undefined,在Javascript的new方法中this默认指向的是window。
然后我们对上述的代码再次进行改进
function person(){
this.name = ‘jack’;
return = ‘tom’;
}
var p = new person();
console.log§ //{ name://‘jack’}
console.log(p.name)//jack
这里要求构造函数必须是一个构造对象如果返回的不是对象还是按照new的逻辑返回新生成的对象,也就是绑定了最新的this然后再返回出来
所以new关键字执行之后总是会返回一个对象要么是实例对象,要么是return语句指定的对象。
再对call、apply、bind进行讲解
call、apply、bind三者是挂靠在function对象上的三个方法,所以调用这三个方法的必须是一个函数
具体的代码实现如下:
这三个词的任何一个都可以改变函数func的this指向call和apply的区别在于传参的写法不同apply的第二个元素是数组而call从第二个开始就是想func的传参而band又和这两个不同虽然改变了this的指向但不是立即执行而其他两个则是改变之后立刻做出反应
如果还是不太懂的话我用大白话来讲一遍吧:
下面我们用代码实现一下上述所讲的三个方法
let a = {
name:'jack',
getname:function(msg){
return msg + this.name;
}
}
let b={
name:'lily'
}
console.log(a.getname('hello~'));//hello~jack
console.log(a.getname.call(b,'hi~'));//hi~lily
console.log(a.getname.apply(b,['hi~']))//hi~lily
let name = a.getname.bind(b,'hello~');
console.log(name());//hello~lily
运行的控制台结果如下:
下面将会讲述一下这些方法的运用场景:理念相同都是借用方法的思路
在判断数据类型时:
类数组借用方法:
类数组因为不是真正的数组所有没有数组类型上自带的种种方法可以利用一些方法去借用数组的方法
代码实现样例:
获取数组的最大最小值:
可以使用apply来实现,apply直接传递数组作为调用方法的参数也可以减少一步展开数组。
new的实现
代码样例:
说完了new在说一下apply和call的使用方法,代码如下
apply和new都是直接返回结果而bind方法是返回一个函数因此这里直接用eval执行得到结果
bind的实现:
bind的实现思路基本和apply一样但是在最后实现返回结果这里bind不需要执行,因此不再需要用eval而是需要通过返回一个函数的方式将结果返回一个函数的方式将结果返回之后再通过返回一个函数的方式将结果返回之后通过执行这个结果,得到想要的执行结果
总结:
上述文章如果有问题或者想问问题或者想交流技术或者想和作者闲聊可以+QQ:2029788643