深入了解new的过程,和call,apply,bind的区别

时间:2021-05-03 18:36:49

话不多数,直接上代码

  1 //1、new的过程发生了什么
  2     function create () {
  3         //创建了一个对象
  4         var obj = new Object()
  5         //获取构造函数
  6         //shift用于把数组的第一个元素删除,并且返回第一个元素的值
  7         var Con = [].shift.call(arguments)
  8         //链接到原型
  9         obj.__proto__ = Con.protoptype
 10         //绑定this的指向
 11         let result = Con.apply(obj,arguments)
 12         //返回一个新的对象
 13         return typeof result === 'object' ? result : obj
 14     }
 15     //2、call、apply,bind的区别和用法
 16     var a = 1
 17     var obj = {
 18         a:2,
 19         fn () {
 20             console.log(this)
 21         }
 22     }
 23     //obj.fn.call(obj)
 24     //打印obj
 25     //会立即调用改变this的指向,普通函数this的指向指向调用它的那个对象
 26     //obj.fn.apply(obj)
 27     //f1.call(null,f2)
 28     var a = 1
 29     var obj2 = {
 30         a:2,
 31         fn () {
 32             console.log(this.a)
 33         }
 34     }
 35     //obj2.fn()
 36     //---2
 37     //var fn1 = obj2.fn
 38     //fn1()
 39     //---1
 40     //相信大家会有一点困惑,第一次this就指向它本身,自己调用,第二次this指向window
 41     //如果你传的context就null或者undefined,那么window对象就是默认的context(严格模式context就是undefined)
 42     //这也叫隐式的绑定,如果你希望打印2,修改为fn1.call(obj)
 43     //回调函数this的指向指向window
 44     //构造器模式,new一个函数时候,背地里会将新建的对象连接到prototype里,同时this会被绑定到那个对象上
 45     //call--方法第一个参数是绑定给this的值,后面传入的是一个参数的列表
 46     var obj3 = {
 47         message:'我的名字是:'
 48     }
 49     function getName (firstnmae,lastname) {
 50         console.log(this.message+firstnmae+''+lastname)
 51     }
 52     //getName.call(obj3,'武','泉')
 53     //apply--接受两个参数,第一个是要绑定this的值,第二个是一个参数数组
 54     var arr = [1,2,3,4,5,6]
 55     var max = Math.max.apply(this,arr)
 56     //console.log(max)
 57     //当第一个传入的是this,null,undefined时可以打印的是6
 58     //这里使用call打印的是NaN
 59     //bind--返回的是函数,不会被立即执行,返回的是一个改变了上下文this后的函数
 60     function bindfn (a,b,c) {
 61         console.log(a,b,c)
 62     }
 63     var binffn1 = bindfn.bind(this,'Doc')
 64     //binffn1('A','B','C')
 65     //Doc A B
 66     //binffn1('B','C')
 67     //Doc B C
 68     //说明bind后面的参数作为实参传进去了,后面的参数排队进
 69     //用bind实现函数珂里化
 70     var add = function (x) {
 71         return function(y){
 72             return x+y
 73         }
 74     }
 75     var addTen = add(9)
 76     //console.log(addTen(1))
 77     //10
 78     //低版本里没有bind,那么就自己手写一个
 79     if(!Function.prototype.bind){
 80         Function.prototype.bind = function () {
 81             //保留原函数
 82             var self = this
 83             //保存需要绑定this指向的上下文
 84             var context = [].shift.call(arguments)
 85             //剩余的参数转化为数组
 86             var args = [].slice.call(arguments)
 87             return function () {
 88                 //解释一哈,返回一个新的函数,把context指向self,参数是上边保存的参数,拼接到一起
 89                 self.apply(context,[].concat.call(args,[].slice.call(arguments)))
 90             }
 91         }
 92     }
 93     //[]就和Array.prototype差不多
 94     //console.log([]==Array)
 95     //false
 96     //console.log([] instanceof Array)
 97     //true
 98     //应用场景
 99     //求数组最大最小
100     var arr = [1,2,3,89,46]
101     var max = Math.max.apply(null,arr)//89
102     var min = Math.min.apply(null,arr)//1
103     //将伪数组转化为数组
104     var trueArr = Array.prototype.slice.call(arrLike)
105     //数组追加
106     var arr1 = [1,2,3];
107     var arr2 = [4,5,6];
108     var total = [].push.apply(arr1, arr2);//6
109     // arr1 [1, 2, 3, 4, 5, 6]
110     // arr2 [4,5,6]
111     //判断变量类型
112     function isArray(obj){
113         return Object.prototype.toString.call(obj) == '[object Array]';
114     }
115     isArray([]) // true
116     isArray('dot') // false
117     //利用call和apply做继承
118     function Person(name,age){
119         // 这里的this都指向实例
120         this.name = name
121         this.age = age
122         this.sayAge = function(){
123             console.log(this.age)
124         }
125     }
126     function Female(){
127         Person.apply(this,arguments)//将父元素所有方法在这里执行一遍就继承了
128     }
129     var dot = new Female('Dot',2)

 他说少于150字不允许发。。。

bind返回对应函数, 便于稍后调用; apply, call则是立即调用。

除此外, 在 ES6 的箭头函数下, call 和 apply 将失效, 对于箭头函数来说:

  • 箭头函数体内的 this 对象, 就是定义时所在的对象, 而不是使用时所在的对象;所以不需要类似于var _this = this这种丑陋的写法
  • 箭头函数不可以当作构造函数,也就是说不可以使用 new 命令, 否则会抛出一个错误
  • 箭头函数不可以使用 arguments 对象,,该对象在函数体内不存在. 如果要用, 可以用 Rest 参数代替
  • 不可以使用 yield 命令, 因此箭头函数不能用作 Generator 函数,什么是Generator函数可自行查阅资料,推荐阅读阮一峰Generator 函数的含义与用法Generator 函数的异步应用