mc-congxueda

导航

< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5
统计
 
            function Test(){
                console.log(this)
            }
            Test();//打印window
            var t=new Test()//打印Test(){}

首先我们要明白上面这个this指向问题,

普通函数调用,this指向window,

而通过new来实例化一个构造函数的对象,则this指向函数。

 

 

1.call、apply和bind 的相同点和不同点

 相同点:call、apply和bind都是JS函数的公有的内部方法,他们都是重置函数的this,改变函数的执行环节。
 不同点:bind是创建一个新的函数,而call和aplay是用来调用函数;call和apply作用一样,只不过call为函数提供的参数是一个个地罗列出来,而apply为函数提供的参数是一个数组。
 
 

2.call的用途。

首先,在函数调用的时候,我们都习惯直接调用,比如说function test(){};test();其实这并不是函数调用的本质,本质是test.call();test()只不过是本质的语法糖,它只能调用,而不能改变函数的执行环境。如下所示。

            function test(){
                console.log("hello world");
            }
            //函数的一般调用
            test();
            //函数调用的本质
            test.call()

那么call是如何改变函数的执行环境的?如下所示:

 

复制代码
            //这个myName变量相当于给window这个对象添加了一个myName属性
             var myName="yyl"
            function test(){
                //此时的this就是指window
                console.log(this.myName)//打印yyl
            }
            test()
            var obj={myName:"hhh"}
            test.call(obj)//打印hhh
复制代码

 

 

这也就解释了我们之前写的那篇原型中,子函数要想继承父函数需要在子函数中写{Father.call(this)},这个this指向的是Son函数,那么就改变了Father的this指向,将其指向到Son函数中,也就实现了Son函数的实例调用Father的属性。如下所示。

            function Father() {
                this.health = "very good"
            }
            function Son() {
                Father.call(this);
            }
            var son = new Son();
            console.log(son.health)//打印very good

 

当然,这样写也可以。

            function Father() {
                this.health = "very good"
            }
            function Son() {}
            var son = new Son();
            Father.call(son);
            console.log(son.health)//打印very good

 

3.apply的用途。

apply除了后面的参数形式与call有区别,其他都一样。比如上面所有用到call的地方都可以用apply来代替。千万不要小看了这个这个参数形式,有些情况下就只能用apply不能用call,比如使用Math.max去获取数组(这个数组有很多元素)的最大值时,若是用call,需要将数组的所有元素陈列出来,而使用apply直接写一个数组就可以。如下: 

 

            var arr=[1,3,2,6,4];
            //1.普通调用方法,是下面这个call方法的语法糖
            console.log(Math.max(1,2,3,6,4))//打印6
            //调用的实质
            console.log(Math.max.call(null,1,2,3,6,4));//打印6
            //使用apply方法
            console.log(Math.max.apply(null,arr));//打印6

4.bind的用途。

直接上代码:

             var myName="yyl";
             function test1(){
                 console.log(this.myName);
             }
             test1();//打印yyl
             var obj={myName:"hhh"}
             var test2=test1.bind(obj);
             test2();//打印hhh

可以看出bind与call的唯一区别就是call直接改变函数test的指向,而bind是生成了一个新函数test2,该函数改变了指向。

 

来自转载

call、apply、bind的实现

call实现

1. 给函数的原型中添加方法

 

复制代码
Function.prototype.mycall = function() {
    console.log(123);
}
 
function num() {
    console.log('测试创建的函数是否包含mycall的方法');
}
function foo() {
    console.log('测试创建的函数是否包含mycall的方法');
}
 
num.mycall() //123
foo.mycall() //123
复制代码

2. mycall函数中获取当前调用的方法,(Fn.mycall)调用的方法是隐式绑定,所以直接使用this就可以获取了

 

Function.prototype.mycall = function() {
    console.log(this); 
}
...
...
num.mycall() //[Function: num]
foo.mycall() //[Function: foo]

 

3.  此时函数已经拿到了后面只需要修改它的this指向就可以了,既然上面已经确定了是隐式绑定那只需要修改"."前面的参数就可以实现动态绑定this了。

复制代码
Function.prototype.mycall = function(thisArg) {
    let fn = this
    thisArg.fn = fn;
    thisArg.fn();
}
 
function num() {
    console.log(this);
}
function foo() {
    console.log(this);
}
 
num.mycall({}) //{ fn: [Function: num] }
foo.mycall([123]) //[ 123, fn: [Function: foo] ]
复制代码

4. 现在基本的this自定义绑定已经实现了,但是还有三个大的问题。

  1. thisArg.fn = fn;这段代码给this增加了fn函数(调用mycall的函数)。
  2. 当传入非对象类型无法绑定为this。
  3. 无法传入参数
复制代码
Function.prototype.mycall = function(thisArg = window, ...args) { //获取自定义this及参数
    let fn = this
 
    thisArg = (thisArg !== null && thisArg !== undefined) ? Object(thisArg) : window; //对传人的this做对象转化,为null或者undefined改为window,
    thisArg.fn = fn;
    let result = thisArg.fn(...args); 
 
    delete thisArg.fn //删除fn
    return result //返回函数
}
 
function num() {
    console.log(this);
}
function foo() {
    console.log(this);
}
 
num.mycall({})
foo.mycall(123)
复制代码

 

 

apply实现

复制代码
Function.prototype.mycall = function (thisArg = window, args = []) { //获取自定义this及参数
    let fn = this
 
    thisArg = (thisArg !== null && thisArg !== undefined) ? Object(thisArg) : window; //对传人的this做对象转化,为null或者unified改为window,
    thisArg.fn = fn;
 
    if (!(args instanceof Array)) throw new SyntaxError("传入的参数类型不是数组"); //确保参数为数组类型
    let result = thisArg.fn(...args);
 
    delete thisArg.fn //删除fn
    return result //返回函数
}
 
function num() {
    console.log(this);
}
function foo(str) {
    console.log(this, str);
}
 
num.mycall({}, [])
foo.mycall('aaa', ['pxq'])
复制代码

 

bind的实现

复制代码
Function.prototype.mybind = function (thisArg = window, ...args) { //获取自定义this及参数
    let fn = this;
    thisArg = (thisArg !== null && thisArg !== undefined) ? Object(thisArg) : window;
 
    return function(...argsArray) {
        thisArg.fn = fn
        let result = thisArg.fn(...args, ...argsArray);
 
        delete thisArg.fn
        return result
    }
}
 
function num (num1, num2) {
    console.log(this, num1, num2);
}
 
function foo () {
    console.log(this);
}
 
var newNum = num.mybind({}, 10)
newNum(20)
 
var newFoo = foo.mybind([]);
newFoo() 
 
 
复制代码

 

 

 

 

 

 

 

posted on   MC~大叔  阅读(1574)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
 
点击右上角即可分享
微信分享提示