// 1. call的使用
function person1() {
console.log(this.name)
}
var egg1 = {
name: 'call1的实现'
}
person1.call(egg1) // -- call的实现
// 2. call相当于
var egg2 = {
name: 'call2的实现',
person2: function() {
console.log(this.name) // this 指向调用它的对象
}
}
egg2.person2() // -- call的实现
// 3. 给函数添加原型对象
function person3(a,b,c) {
console.log(this.name)
console.log(a,b,c)
}
var egg3= {
name: 'call3的实现'
}
// 3.1 this 隐式绑定
// 隐式绑定
// (1) 如果函数调用时,前面存在调用它的对象,那么this就会隐式绑定到这个对象上
// (2) 如果函数调用前存在多个对象,this指向距离调用自己最近的对象
// 扩展函数,使函数拥有一个名为 newCall 的原型对象
Function.prototype.newCall1 = function( obj ) {
console.log( this )
}
// 这个时候 newCall 里的this因为隐式绑定指向的是person 函数
person3.newCall1( egg3 ) // --ƒ person() { console.log(this.name) }
// 3.2 硬绑定this
Function.prototype.newCall2 = function( obj ) {
obj.p = this // 给 obj 形参添加一个方法(this指向的函数)
obj.p(); // 调用这个函数 这个时候 this 指向的就是形参 obj
delete obj.p // 因为添加方法等于改写了函数的属性,所以要把这个方法删除掉
}
person3.newCall2( egg3 ) // --call的实现
// 3.3 处理第一个以外的参数
Function.prototype.newCall3 = function( obj ) {
obj.p = this
var newArguments = []
// 这个时候参数位置不对称,所以需要将除了第一个参数以外的参数另外保存起来
// 让参数回归到正常的序号
for ( var i=1; i < arguments.length; i++ ) {
newArguments.push( arguments[i] )
}
console.log(newArguments)
// obj.p(); // -- undefined undefined undefined 内部执行的是不带参数的函数
obj.p(newArguments); // -- ['参数1', '参数2', '参数3'] undefined undefined 这是因为数组本身就是一个参数
delete obj.p
}
person3.newCall3( egg3, '参数1', '参数2', '参数3', ) // --call的实现
// 3.4 参数传递的问题
Function.prototype.newCall4 = function( obj ) {
obj.p = this
var newArguments1 = []
var newArguments2 = []
for ( var i=1; i < arguments.length; i++ ) {
newArguments1.push( arguments[i] ) // -- newArguments1=['参数1', '参数2', '参数3']
newArguments2.push( "arguments["+ i +"]" ) // --newArguments1=['arguments[1]', 'arguments[2]', 'arguments[3]']
}
// eval 函数会执行括号里的语句
// 字符串加法会隐式调用toString()方法,
// 所以"obj.p("+newArguments1+')' = "obj.p(参数1, 参数2, 参数3)'
// eval("obj.p("+newArguments1+')') --参数1 is not defined
// 所以"obj.p("+newArguments2+')' = "obj.p(arguments[1], arguments[2], arguments[3])'
eval("obj.p(" + newArguments2 + ')') // --参数1 参数2 参数3
delete obj.p
}
person3.newCall4( egg3, '参数1', '参数2', '参数3', ) // call的实现 --参数1 参数2 参数3
// 3.5当第一个参数为null的时候
Function.prototype.newCall5 = function( obj ) {
var obj = obj || window // 没有这个运算的话 代码会报错
obj.p = this
var newArguments2 = []
for ( var i=1; i < arguments.length; i++ ) {
newArguments2.push( "arguments["+ i +"]" )
}
eval("obj.p(" + newArguments2 + ')')
delete obj.p
}
person3.newCall5( null, '参数1', '参数2', '参数3', ) // --参数1 参数2 参数3
// 4. 函数返回值
function person4(a,b,c) {
return {
name:this.name,
a: a, b: b, c: c
}
}
var egg4 = {
name: 'call的实现',
p:function(){
console.log('zijide p')
}
}
Function.prototype.newCall6 = function( obj ) {
var obj = obj || window
obj.p = this
var newArguments2 = []
for ( var i=1; i < arguments.length; i++ ) {
newArguments2.push( "arguments["+ i +"]" )
}
eval("obj.p(" + newArguments2 + ')')
delete obj.p
}
var bibi = person4.newCall6( egg4, '参数1', '参数2', '参数3', )
console.log(bibi) // --undefined
// 最终版
// 只需要将eval() 执行的结果保存到一个变量中,并返回这个变量就可以了
Function.prototype.newCall7 = function( obj ) {
var obj = obj || window
obj.p = this
var newArguments2 = []
for ( var i=1; i < arguments.length; i++ ) {
// newArguments2.push( "arguments["+ i +"]" )
newArguments2.push( arguments[i] )
}
// var result = eval("obj.p(" + newArguments2 + ')')
var result = obj.p(...newArguments2)
delete obj.p
return result
}
var bibi2 = person4.newCall7( egg4, '参数1', '参数2', '参数3', )
console.log(bibi2) // --{name: 'call的实现', a: '参数1', b: '参数2', c: '参数3'}
注意: 这样的写法会到一个问题,如果 egg 里有一个名为 p 的属性,这样执行会将 egg 里的属性 p 删掉
再附上一个朋友的写法,对比之下,我傻的很-_-!