1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        原生JS基礎(chǔ)鞏固

        共 4288字,需瀏覽 9分鐘

         ·

        2021-01-17 04:34

        原生js基礎(chǔ)鞏固

        原型和原型鏈函數(shù)柯里化call/apply實(shí)現(xiàn)bind模擬實(shí)現(xiàn)最優(yōu)繼承instanceof實(shí)現(xiàn)

        原型和原型鏈

        提到j(luò)s,原型和原型鏈?zhǔn)且?guī)避不過(guò)的,這之中存在幾個(gè)容易混淆的概念,理解這些概念后,原型和原型鏈也就理解了。話不多說(shuō),先看一張?jiān)玩準(zhǔn)疽鈭D。

        原型鏈?zhǔn)疽鈭D

        圖片來(lái)源

        名詞解釋

        構(gòu)造函數(shù)

        簡(jiǎn)單來(lái)說(shuō),構(gòu)造函數(shù)本質(zhì)就是一個(gè)函數(shù)而已,不同的是它可以用來(lái)創(chuàng)建對(duì)象(使用new操作符調(diào)用)

        function Person(){} ? ?這段代碼中Person就是構(gòu)造函數(shù)

        實(shí)例

        使用構(gòu)造函數(shù)創(chuàng)建出來(lái)的對(duì)象

        let p=new Person() 這段代碼中的p就是構(gòu)造函數(shù)Person的一個(gè)實(shí)例

        原型對(duì)象

        原型對(duì)象本質(zhì)是一個(gè)對(duì)象,它的constructor屬性指向創(chuàng)建該實(shí)例的構(gòu)造函數(shù)。這里Person.prototype就是原型對(duì)象,Person.prototype.constructor屬性指向構(gòu)造函數(shù)Person。實(shí)例p可以通過(guò)__proto__屬性訪問(wèn)其原型對(duì)象

        查找機(jī)制

        上述原型對(duì)象Person.prototype也有自己的原型對(duì)象,就是Object.prototype。換句話說(shuō),Person.prototype是Object.prototype的一個(gè)實(shí)例。自身沒(méi)有的屬性,會(huì)去原型上查找,這個(gè)查找過(guò)程就是原型鏈查找,上述藍(lán)線就是一整條原型鏈。

        驗(yàn)證

        原型鏈各個(gè)概念關(guān)系驗(yàn)證示意圖

        函數(shù)柯里化

        柯里化是指的是將接受多個(gè)參數(shù)的函數(shù)變換成接受一個(gè)單一參數(shù)的函數(shù),如果其他的參數(shù)是必要的,返回接受余下的參數(shù)且返回結(jié)果的新函數(shù)。

        example

        核心是所有參數(shù)的保留和第一個(gè)參數(shù)與后續(xù)參數(shù)的拆分

        function?add(...args)?{

        ????const?iterator?=?(...rest)?=>?{
        ????????args?=?[...rest,?...args];
        ????????return?iterator;
        ????};

        ????iterator.toString?=?()?=>?args.reduce((a,?b)?=>?a?+?b);
        ????return?iterator;
        }

        //?注意觀察調(diào)用方式的區(qū)別
        add(1,?2)(3)(4);//10
        add(1)(2)(3)(4);//10
        add(1,2,3,4);//10

        call/apply實(shí)現(xiàn)

        在實(shí)際開(kāi)發(fā)中,call,和apply常用來(lái)改變this指向,這里簡(jiǎn)單模擬一下它們的內(nèi)部實(shí)現(xiàn)

        example

        //先來(lái)個(gè)簡(jiǎn)單的例子感受一下
        var?stu?=?{
        ??name:"tom",
        ??age:?18,
        };

        function?say()?{
        ??console.log(`my?name?is?${this.name},${this.age}?years?old`);
        }

        say.call(stu);?//?my?name?is?tom,18?years?old

        功能點(diǎn):

        say函數(shù)中的this指向由window變?yōu)閟tu

        say函數(shù)依然執(zhí)行了

        why?

        仔細(xì)看看上述的兩個(gè)功能點(diǎn)是如何實(shí)現(xiàn)的?其實(shí)很簡(jiǎn)單,只要把say函數(shù)作為對(duì)象stu的一個(gè)內(nèi)置方法即可

        //改寫后如下
        var?stu?=?{
        ??name:?"tom",
        ??age:?18,
        ??say()?{
        ????console.log(`my?name?is?${this.name},${this.age}?years?old`);
        ??}

        };

        //調(diào)用
        stu.say()?//my?name?is?tom,18?years?old

        這樣并沒(méi)有結(jié)束,stu多了一個(gè)冗余方法,顯然不合適,應(yīng)該刪除掉

        call模擬實(shí)現(xiàn)

        ??//call_v1
        ??Function.prototype.call?=?function?(context)?{
        ????//這里的context相當(dāng)于上述stu
        ????//這里的this指向目標(biāo)調(diào)用函數(shù),相當(dāng)于上述say
        ????//這里可以理解為為stu添加say方法
        ????context.fn?=?this;
        ????context.fn()//相當(dāng)于執(zhí)行stu.say()
        ????delete?context.fn//刪除冗余方法,相當(dāng)于delete?stu.say

        ??}

        ??//call_v2

        ??//下面加入傳參處理,默認(rèn)上下文處理和返回值處理
        Function.prototype.call?=?function?(context?=?window,?...args)?{

        ??//context=window?設(shè)置默認(rèn)上下文為window

        ??context.fn?=?this;
        ??let?result?=?context.fn(...args)//處理傳參
        ??delete?context.fn
        ??return?result?//返回值

        }

        apply模擬實(shí)現(xiàn)

        這個(gè)和call基本一樣,區(qū)別在于傳參是數(shù)組形式

        Function.prototype.apply=?function?(context?=?window,?args=[])?{

        ??//context=window?設(shè)置默認(rèn)上下文為window

        ??context.fn?=?this;
        ??let?result?=?context.fn(...args)//處理傳參
        ??delete?context.fn
        ??return?result?//返回值

        }

        bind模擬實(shí)現(xiàn)

        bind的作用和call/apply類似,都可以改變this指向,不同的是,bind執(zhí)行后返回的是一個(gè)函數(shù),并不會(huì)自己調(diào)用。mdn上這樣解釋:bind()方法創(chuàng)建一個(gè)新的函數(shù),在bind()被調(diào)用時(shí),這個(gè)新函數(shù)的this被bind的第一個(gè)參數(shù)指定,其余的參數(shù)將作為新函數(shù)的參數(shù)供調(diào)用時(shí)使用。

        example

        var?stu?=?{
        ??name:"tom",
        ??age:?18,
        };

        function?say()?{
        ??console.log(`my?name?is?${this.name},${this.age}?years?old`);
        }

        var?bindSay=say.bind(stu);?
        bindSay();//?my?name?is?tom,18?years?old

        bind模擬實(shí)現(xiàn)

        /**
        ?*?改變this指向
        ?*?返回一個(gè)函數(shù)
        ?*?可傳參
        ?*?柯里化
        ?*/



        Function.prototype.bind?=?function?(context,?...args)?{

        ??if?(typeof?this?!==?"function")?{
        ????throw?new?Error("Function.prototype.bind?-?what?is?trying?to?be?bound?is?not?callable");
        ??}

        ??let?self?=?this
        ??let?MiddleFn?=?function?()?{?}
        ??let?BindFn?=?function?(...rest)?{
        ????return?self.apply(this?instanceof?BindFn???this?:?context,?args.concat(rest));
        ??}

        ??MiddleFn.prototype?=?this.prototype
        ??BindFn.prototype?=?new?MiddleFn()
        ??return?BindFn;
        }

        最優(yōu)繼承

        function?Person(name)?{
        ????this.name?=?name;
        }

        Person.prototype.say=function(){
        ????console.log(`My?name?is?${this.name}`)
        }

        function?Student(name)?{
        ????Person.call(this,?name)
        }

        //?Object.create方法創(chuàng)建一個(gè)新對(duì)象,使用現(xiàn)有的對(duì)象來(lái)提供新創(chuàng)建的對(duì)象的__proto__
        Student.prototype=Object.create(Person.prototype);
        //?修正構(gòu)造函數(shù)指向?Person=>Student
        Student.prototype.constructor=Student;

        var?stu=new?Student("tom");

        stu.say()//My?name?is?tom

        instanceof實(shí)現(xiàn)

        typeof 可用于判斷基本類型值,instanceof操作符用于判斷具體的引用類型

        function?_instanceof(left,?right)?{

        ????//如果是基本數(shù)據(jù)類型,返回false??
        ????//?typeof?null?是object?,要處理這種情況?
        ????if?(typeof?(left)?!==?"object"?||?left?==?undefined)?{
        ????????return?false;
        ????}

        ????//?獲取原型對(duì)象
        ????//?舉個(gè)例子:Object.getPrototypeOf([])===[].__proto__??true
        ????let?prototype?=?Object.getPrototypeOf(left);

        ????while?(true)?{

        ????????//一直按著原型鏈查找??找到頂層還找不到,返回null

        ????????if?(prototype?===?null)?{
        ????????????return?false;
        ????????}

        ????????//?如果left?right?原型對(duì)象一樣?返回true
        ????????if?(prototype?==?right.prototype)?{
        ????????????return?true;
        ????????}

        ????????//?不滿足條件的??繼續(xù)查找
        ????????//一直到???Object.getPrototypeOf(Object.getPrototypeOf({}))?null
        ????????prototype?=?Object.getPrototypeOf(prototype);


        ????}

        }




        瀏覽 44
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        評(píng)論
        圖片
        表情
        推薦
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            久cao在线| 欧美巨大性爽性爽巨大 | 亚洲国产毛片在线探花 | 考逼视频网站 | 国产无遮挡呻吟吸乳视频 | 少妇一次50分钟高潮 | 成人无码mv色情在线观看视频an 日韩福利视频 | 国产九色91 回来了 | 9l视频白拍9色9l视频 | 夜夜爽夜夜操 |