深入了解new的过程,和call,apply,bind的区别
话不多数,直接上代码
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 函数的异步应用