• JS中bind,call,apply以及new的用法与实现


    JS中bind,call,apply以及new的用法与实现

    春招冲刺01.16日 - 01

    1. 什么是bind,call,apply

      
    bind,call,apply是JavaScript中Function对象自带的三个方法,用于改变函数体内部的 this 指向,也就是函数调用时的上下文(context)。

    bind,call,apply三者都可以利用后续参数传参。其中bind不会立即调用,而是返回对应的绑定函数,其内的this指向为创建它时传入bind的 第一个参数,而传入bind的第二个及以后的参数作为 原函数的参数 来调用原函数。

    bind(thisArg[, arg1[, arg2[, ...]]])

    apply、call则是立即调用,改变的this指向他们的第一个参数,apply的第二个参数是一个参数数组,call的第二个及其以后的参数都是数组里面的元素。

    call ( thisArg, arg1, arg2, ... )
    apply ( thisArg ,[argArray] )

    2. call的应用与实现

    在call的语法call ( thisArg, arg1, arg2, ... )中,thisArg的传递情况有:

    • null,undefined或不传 此时指向window
    • 传递另一个函数B的函数名,函数中的this指向B的引用
    • 传递字符串、数值或布尔类型等基础类型,函数中的this指向其对应的包装对象,如 String、Number、Boolean
    • 传递一个对象,函数中的this指向这个对象

    常用方法:

    function pChain (){
            this.name="pChainRoot";
            this.nameprint=function(){
                console.log('打印的名字是',this.name);
            }
        }
    
    var newname={name:"PChainChild"};
    var PChain=new pChain();
    PChain.nameprint.call(newname);  //PChainChild
    PChain.nameprint();              //pChainRoot
    

    模拟实现:

    Function.prototype.myCall = function (thisArg,...args){
            
            //thisArg为调用mycall方法的函数的this指向
            var thisArg = thisArg || window
            
            //将this赋给thisArg的fn属性
            //此处this指代调用myCall的function
            thisArg.fn = this;  
            
            var result = thisArg.fn(args);
            delete thisArg.fn;
            return result;
    
        }
        PChain.nameprint.myCall(newname);  //pChainChild
    

    3. apply的应用与实现

    apply与call的作用是一样的,不过二者接收参数的方法不一样,apply要求将call的剩余参数存储在一个数组中。
    当明确知道参数数量时用 call ,而不确定的时候用 apply,并将把参数 push 进数组传递进去,使函数内部也通过 arguments 这个数组来遍历所有的参数。
    常用方法:

    function pChain2 (name1,name2){
        this.name1=name1;
        this.name2=name2;
        this.nameprint=function(){
            console.log('打印的名字是',this.name1+'与'+this.name2);
        }
    }
    function pChainChild2 (){
            this.name1="PChainChild1";
            this.name2="PChainChild2";
            var PChain2 = new pChain2("pChainRoot1","pChainPoot2");
    
            //call的传参方法
            PChain2.nameprint.call(this,name1,name2);  //PChainChild1与PChainChild2
    
            PChain2.nameprint();      //pChainRoot1与pChainPoot2
            
            //apply的传参方法
            PChain2.nameprint.apply(this,[name1,name2]);  //PChainChild1与PChainChild2
    }
    
    pChainChild2();
    

    模拟实现:

    Function.prototype.myApply = function(thisArg){
            //thisArg为调用mycall方法的函数的this指向
            var thisArg = thisArg || window
            
            //将this赋给thisArg的fn属性
            //此处this指代调用myCall的function
            thisArg.fn = this;  
            
            var result;
            if (arguments[1]) {
    	        result = thisArg.fn(arguments[1]);
            } else {
            	result = thisArg.fn();
            }
            delete thisArg.fn;
            return result;
        }
    

    4. bind的应用与实现

    bind是在es5中扩展的方法(IE6,7,8不支持),但是返回值是函数。

    常用方法:

    var bar= function () {
        console.log(this.x);
    }
    var foo = {
        x:3
    }
    
    bar(); //undefined
    
    bar.bind (foo) (); //3
    

    要注意的是多次 bind() 是无效的。

    var foo2 = {
        x:5
    }
    bar.bind (foo).bind (foo2) (); //3
    

    模拟实现:

    Function.prototype.myBind=function(){
            var _this = this;
            var context = [].shift.call(arguments);// 保存需要绑定的this上下文
            var args = [].slice.call(arguments); //剩下参数转为数组
            
            return function(){
                _this.apply(context, [].concat.call(args, [].slice.call(arguments)));
            }
        }
    

    5. new的应用与实现

    在学习了原型与原型链 -> 12.29part2 之后,我们知道new在构建过程中,会发生的步骤为:

    • 生成新的对象
    • 新对象的__proto__属性指向构造函数的原型对象
    • 绑定this,将构造函数的作用域赋值给新对象
    • 返回新对象

    因此手动模拟new关键字只需要实现上述四个步骤即可

    function myNew(fn, ...args) {
            const obj = {};
    
            //绑定原型链
            obj.__proto__ = fn.prototype;
    
            // 改变this指向
            let result = fn.apply(obj, args)
            
            // return result
            // 确保new出来的是一个对象
            return typeof result === "object" ? result : obj
        }
  • 相关阅读:
    iOS开发之窥探UICollectionViewController(三) --使用UICollectionView自定义瀑布流
    iOS开发之窥探UICollectionViewController(二) --详解CollectionView各种回调
    iOS开发之窥探UICollectionViewController(一) -- Ready Your CollectionViewController
    iOS开发之SQLite--C语言接口规范(五)——iOS开发使用SQLite实例
    iOS开发之SQLite--C语言接口规范(四) —— Result Values From A Query
    iOS开发之SQLite--C语言接口规范(三)——Binding Values To Prepared Statements
    iOS开发之SQLite-C语言接口规范(二) —— Prepared Your SQL Statements
    iOS开发之SQLite-C语言接口规范(一)——Ready And Open Your SQLite
    iOS开发之ImageView复用实现图片无限轮播
    iOS开发之多图片无缝滚动组件封装与使用
  • 原文地址:https://www.cnblogs.com/banshanliang/p/14297837.html
Copyright © 2020-2023  润新知