• 从this 到call 到new 到原型链


    1、总结特点:

    首先this就是指代的运行环境,其次容易搞混的xx的函数都转换成函数地址和代码块就好懂多了
    在看了这么多之后,自己的总结:
    this作用域这块大概是谁调用这个函数,函数里的this就指向谁,如果是两套a.b.c() 那么指向是离函数c()最近的b里面,如果是var f=b.c 这样就只是简单生搬了c里面的内容和b没什么关系。
    bind就是F是Function   F.call(obj,参数)
    实际上就是obj.F,
    obj内部写了一F的方法,让F可以访问obj内部的东东
    A.call(B)就是B.A 这样a可以访问b里的东西,a里的this也指向了B 
    (可以理解成var a={a里面原来的东西+函数B},a.B就和最正常的例子一样了-.-)
    1 参 https://www.cnblogs.com/pssp/p/5216085.html (函数的this是谁调用它 的时候才确定的)
    2 参https://www.ruanyifeng.com/blog/2018/06/javascript-this.html(没什么关系那里,但是理解了)
    这样是最标准的,安乐的this环境,一定是对象里的函数~ 
    var obj={
        var a=1;
        function:{ 。。。this.a 。}
    }
    3 参 https://blog.csdn.net/dizuncainiao/article/details/109990791 这个写的不好大概看看就行 但不知道为啥忽然就懂了
    这里更详细了一下apply的妙用性原理
    上面2这篇文章ok,但是这人其他的比如他引用的那个call文章不行(?)

    2、对于call apply这一块

    括号里面的第一个参数会反客为主,因为最前面的参数是函数,函数只有被调用的份儿

    var list1 = [0,1,2];
    var list2 = [3,4,5];
    [].push.apply(list1,list2);
    
    console.log(list1);// >>> [0,1,2,3,4,5]
    (1)[].push只是相当于调用了数组的方法,就像是Array.prototype.push一样(重点还是在push)
    (2)上面的代码就是list1.push(list2的具体参数)
    list1.push(参数就是list2因为apply整的解构
    (3)不过es6下『...』的出现也能做到同样的事情了
    ES6 写法: list1.push(...list2)(等同于上面的代码)
    (4)此外 let max = Math.max.apply(null, array);如传入的是null或者undefined那么自动会变成window.xxx

    3、new的时候发生了什么?

    直接看MDN说的:

    new 关键字会进行如下的操作:

    1. 创建一个空的简单JavaScript对象(即{});
    2. 为步骤1新创建的对象添加属性__proto__,将该属性链接至构造函数的原型对象 ;( ....__proto==constructor.prototype(那么杰哥原型链那些,就是链接到了属性共享的方面~) 
    3. 将步骤1新创建的对象作为this的上下文 ;(实际上就是call改变那句话,构造函数.call(实例)这样就相当于实例.构造函数,使得函数里的this指向实例====》实际上【就是对象作为了this上下文】
    4. 如果该函数没有返回对象,则返回this

    基本就是这四步,但有的地方会写错,比如。。一定要避雷这篇 https://juejin.cn/post/6844904003545858056 (而甚至,听得课里面的老师也看的这篇导致这里有一部分直接误人子弟,讲的错了!!!!这里面没提原型链,这是理解上的误区,因为call这个马上就执行了,没必要再拆成两个(所以说看网上不权威的东西危害是多么大!一定要多看几篇综述一下!)】

    为什么会有这种认知呢,,https://www.zhihu.com/question/36440948 这里29赞这个说了,js(三)里是这么写的,但实际上少了原型链这部分,所以不要生搬硬套!

    4、【继续深究(思考之后得到的)】

    1 call apply调用的是什么?是马上调用吗?
    可以明确从apply应用多参数的push那里感知到,call这么一行话写了就是调用的,相比于bind是要加个括号再调用的,也可以感受到这一点。
    也就是A.call(B)就相当于B.A() 一定是A()因为调用了,马上执行~
    或者是A.call(B,C,D)就相当于B.A(C,D) cd是伪装在那里的A调用的参数
    此时AB是正常的夫妻关系,函数A可以访问B里面的方法,因为函数A的this环境已经被改成对象B了
    2 call做完返回值是怎么样的呢?
    应该就是函数的返回值了,很多情况下没有返回值所以没有接着,但是比如slice() 这种返回的新数组就要设立返回值啦
    3 对象嵌套与函数嵌套与this怎么理解,为什么函数嵌套不继承this,为什么对象嵌套也不继承this?
     
    只要记住:谁最后调用,函数的this就归谁,
    没人调用this就归window了
     
    ① 对象嵌套,最后是b先调用的,那么this就归b啦
    var o = {
        a:10,
        b:{
            a:12,
            fn:function(){
                console.log(this.a); //12
            }
        }
    }
    o.b.fn();
    ② 函数嵌套。
    var obj = {
        a1:1,
        foo: function () {
        console.log(this.a1,"到此处还是正常访问的");
            var fn = function () {
                console.log(this);//这里就已经完全不能继承,并且整到全局去了
            }
            fn()
        }
    }
    obj.foo()  
    表面上,这能说明嵌套函数不继承this
    但实际上怎样导致的呢?
    因为obj调用了foo,所以foo可以继承obj里面的,但是又没有人调用fn()。
    没人调用fn,那就只能window了,window下面又没有a1,那么打印this也是打印的window下面的this头脑风暴:如果使得fn被调用呢,怎么修改代码?
    ①emmm。return fn()的话本质也是先调用fn() 再看fn的返回值是啥返回那个值,还是没有做到xxx.fn
    ② 如果是在函数内先扒拉扒拉。。。
    好吧,函数要写语句的,不能写成员变量,所以这个问题先无解,
    但确实是可以理解为嵌套函数不继承的。~~
     
    这里好像理解的不太对,首先作用域链和this是完全不同的两套
        var num=1;
        function qwq1(){
            var num=2;
            function qwq2(){
                function qwq3(){
                    console.log(num,'啊啊啊啊啊啊啊');
                }
                qwq3();
            }
            qwq2();
        }
        qwq1();
    看这段代码,如果console那里加了this,打印的是1因为没对象调用,如果不加this就打印2,这里是作用域链的“是在声明的时候决定的作用域链,和调用的时候无关(可以看我的面经no1)”
    4 Object.prototype.toString.call(arr )这里call是干嘛的呢
    比如 var arr =new Array()
    仔细一想,这不就是A.call(B)嘛 ,通俗一点就是B.A()  那也是就arr.toString? 为什么不直接这么用呢
     
    嗯~~~ 因为大多数对象,toString() 方法都是重写了的,没有重写的那些当然就返回一样的结果啦,为了统一就用食物链顶端的Object来做法了。
    因为,想想啊比如number.toString就是把number转换成字符串,var array=[1,2,3]这里就是转换成"1,2,3",所以说其实都荡~然~无~存~  所以还是乖乖的用object. xxxxx吧
    5  括号问题
    注意 以[].push.apply(list1,list2);为例 你想用的是push() 但实际上你在调用的时候是没有括号的  有括号就变成函数调用(立刻调用那种) 而需要传参数的一定在call的最后  那么前面就不要有括号了) 
    6 let max = Math.max.apply(null, array);
    ===》max= window.max(array) 
     

    5、原型链系列。。。 因为new的时候也有原型链就去复习了一下,不过明天再写吧

    怎么说呢,大概就是其实网上的东西鱼龙混杂,你找得到的不一定是你想看的
    官话:(?)
    __proto__通常称为隐式原型,prototype通常称为显式原型,那我们可以说一个对象的隐式原型指向了该对象的构造函数的显式原型。那么我们在显式原型上定义的属性方法,通过隐式原型传递给了构造函数的实例。这样一来实例就能很容易的访问到构造函数原型上的方法和属性了。
    自己的理解:
    原型链首先知道函数才有prototype,其次那个prototype也是一个实例对象,只不过①它是js底层给我们创建好的所以可以共享②新加的需要共享的也可以填上去③归根结底也只是一个可怜的实例罢了
    关键点:实际上xxx.prototype也是一个可怜的实例罢了,只是js帮我们创建好了,实例就是比如var a=new Array() a就是实例 那么a.__proto__就是object通过var array=new Object(xxxx) array这个类实际上也是object创建的实例 只不过是现成的……
    添加各种类型创建出来的(好像讲的有点乱,可以去后面看图)
     
    可以看这篇,https://segmentfault.com/a/1190000021232132 可以说是讲的非常清楚了,不要死记硬背三个箭头,那样会评价很差,你懂得~
    具体:
    (1)首先要知道概念:
    ① __proto__、 constructor属性是对象所独有的;
    ② prototype属性是函数独有的;
    ③  js中函数也是对象的一种,那么函数同样也有属性__proto__、 constructor
    其实也就是对象有__proto__和constructor,函数有__proto__和constructor和prototype,作为一个对象是没有prototype的(这个是构造函数才~ 有~ 的~ )如果一个新的实例没有constructor,那么就会去原型链__proto__去找,这也是新实例.constructor==array()的原因(但是去.hasOwnProerty是false~ 自己没有,只是去原型链找了而已~ )
     
    (2)函数、构造函数的区别:任何函数都可以作为构造函数,但是并不能将任意函数叫做构造函数,只有当一个函数通过new关键字调用的时候才可以成为构造函数。
    var Parent = function(){
    }
    //定义一个函数,那它只是一个普通的函数,下面我们让这个函数变得不普通
    var p1 = new Parent();
    //这时这个Parent就不是普通的函数了,它现在是一个构造函数。因为通过new关键字调用了它
    //创建了一个Parent构造函数的实例 p1
     
    下面分别介绍这三个
    (1)prototype 结合下文的prototype其实就=可共享的,那么函数指向的prototype就是孩子们可以共享的“爸爸” 的各种。。。
    为了方便举例,我们在这模拟一个场景,父类比作师父,子类比作徒弟。师父收徒弟,
    徒弟还可以收徒弟。徒弟可以得到师父传授的武功,然后徒弟再传给自己的徒弟。
    师父想要传授给徒弟们的武功就放到“prototype”这个琅琊福地中。徒弟徒孙们就去这里学习武功。
    prototype属性可以看成是一块特殊的存储空间,存储了供“徒弟”、“徒孙”们使用的方法和属性。
    (只有函数才有的prototype)

     (下面是null)

    prototype是函数独有的属性,从图中可以看到它从一个函数指向另一个对象,代表这个对象是这个函数的原型对象,这个对象也是当前函数所创建的实例的原型对象。
    prototype设计之初就是为了实现继承,让由特定函数创建的所有实例共享属性和方法,也可以说是让某一个构造函数实例化的所有对象可以找到公共的方法和属性。有了prototype我们不需要为每一个实例创建重复的属性方法,而是将属性方法创建在构造函数的原型对象上(prototype)。那些不需要共享的才创建在构造函数中。
    继续引用上面的代码,当我们想为通过Parent实例化的所有实例添加一个共享的属性时,

    Parent.prototype.name = "我是原型属性,所有实例都可以读取到我";

    这就是原型属性,当然你也可以添加原型方法。那问题来了,p1怎么知道他的原型对象上有这个方法呢,往下看↓↓↓

    (2)proto属性

    __proto__属性相当于通往prototype(“琅琊福地”)唯一的路(指针)
    让“徒弟”、“徒孙” 们找到自己“师父”、“师父的师父” 提供给自己的方法和属性
    (这里其实把prototype理解成上一个实例可以)

     prototype篇章我们说到,Parent.prototype上添加的属性和方法叫做原型属性和原型方法,该构造函数的实例都可以访问调用。那这个构造函数的原型对象上的属性和方法,怎么能和构造函数的实例联系在一起呢,就是通过__proto__属性。每个对象都有__proto__属性,该属性指向的就是该对象的原型对象。

    p1.__proto__ === Parent.prototype; // true

    __proto__通常称为隐式原型,prototype通常称为显式原型,那我们可以说一个对象的隐式原型指向了该对象的构造函数的显式原型。那么我们在显式原型上定义的属性方法,通过隐式原型传递给了构造函数的实例。这样一来实例就能很容易的访问到构造函数原型上的方法和属性了。
    我们之前也说过__proto__属性是对象(包括函数)独有的,那么Parent.prototype也是对象,那它有隐式原型么?又指向谁?

    Parent.prototype.__proto__ === Object.prototype; //true

    可以看到,构造函数的原型对象上的隐式原型对象指向了Object的原型对象。那么Parent的原型对象就继承了Object的原型对象。由此我们可以验证一个结论,万物继承自Object.prototype。这也就是为什么我们可以实例化一个对象,并且可以调用该对象上没有的属性和方法了。如:

    //我们并没有在Parent中定义任何方法属性,但是我们可以调用
    p1.toString();//hasOwnProperty 等等的一些方法

    我们可以调用很多我们没有定义的方法,这些方法是哪来的呢?现在引出原型链的概念,当我们调用p1.toString()的时候,先在p1对象本身寻找,没有找到则通过p1.__proto__找到了原型对象Parent.prototype,也没有找到,又通过Parent.prototype.__proto__找到了上一层原型对象Object.prototype。在这一层找到了toString方法。返回该方法供p1使用。
    当然如果找到Object.prototype上也没找到,就在Object.prototype.__proto__中寻找,但是Object.prototype.__proto__ === null所以就返回undefined。这就是为什么当访问对象中一个不存在的属性时,返回undefined了。

    (3)constructor属性

    constructor属性是让“徒弟”、“徒孙” 们知道是谁创造了自己,这里可不是“师父”啊
    而是自己的父母,父母创造了自己,父母又是由上一辈人创造的,……追溯到头就是Function() 【女娲】。
    

    constructor是对象才有的属性,从图中看到它是从一个对象指向一个函数的。指向的函数就是该对象的构造函数。每个对象都有构造函数,好比我们上面的代码p1就是一个对象,那p1的构造函数是谁呢?我们打印一下。

    console.log(p1.constructor); // ƒ Parent(){}

    通过输出结果看到,很显然是Parent函数。我们有说过函数也是对象,那Parent函数是不是也有构造函数呢?显然是有的。再次打印下。

    console.log(Parent.constructor); // ƒ Function() { [native code] }

    通过输出看到Parent函数的构造函数是Function(),这点也不奇怪,因为我们每次定义函数其实都是调用了new Function(),下面两种效果是一样的。

    var fn1 = new Function('msg','alert(msg)');
    function fn1(msg){
        alert(msg);
    }

    那么我们再回来看下,再次打印Function.constructor

    console.log(Function.constructor); // ƒ Function() { [native code] }

    可以看到Function函数的构造函数就是本身了,那我们也就可以说Function是所有函数的根构造函数。
    到这里我们已经对constructor属性有了一个初步的认识,它的作用是从一个对象指向一个函数,这个函数就是该对象的构造函数。通过栗子我们可以看到,p1constructor属性指向了Parent,那么Parent就是p1的构造函数。同样Parentconstructor属性指向了Function,那么Function就是Parent的构造函数,然后又验证了Function就是根构造函数。

     自己手画了张图:
     

     后续思考

    礼貌发言:
    实际上那个课除了内容不深入,就广度上来说还是可以的。谁能想到instanceof手写这种真的会考到呢,155551
    思考:
    看到手写instanceof的时候
    形式是 arr instanceof Array
    手写是左边.__proto__===右边.prototype 
    (1)为什么是array不是()或者[]
    打印Array,可以看到控制台返回的就是 ƒ Array() { [native code] },也就是这里右边其实是指代的函数那边的
    所以要左边的隐式原型是否等于右边的显式原型

    既然Array就指代了Array(),那arr.__proto__呢?其实只是Array.prototype,又回到了起点,函数其实是很高的,这个prototype才是弟弟

    var obj={}  obj.__proto__ 你感觉是应该到Object了吧,实际上打印的并不是object而是Object.prototype,也就是函数Object()的狗(Object创建出的函数 给下一代共享的方法,Object创建出的是obj不是这个Object.prototype) 
    ↓ Object.prototype:
    {constructor: ƒ, __defineGetter__: ƒ, __defineSetter__: ƒ, hasOwnProperty: ƒ, __lookupGetter__: ƒ, …}
     
    表面上,我去试试Object.__proto__是不是null?但实际上你要知道这个时候你找到的是Object函数的__proto__,这个时候Object函数是作为一个实例的,它的__proto__是Function.prototye 然后就还是那一堆代码
    实例的.__proto__也就是构造函数的prototype是一堆共享代码,这个是不能比较的!!!!!所以也只能去比较构造函数!!!!!!
    那么我们大胆一点,Object.prototype.__proto__==null虽然这个是终点了,但是Funtcion那里才是不停指向自己的死循环,那么不妨可以假设这个Function才是背后boss终极老鸨子……  实际上后面那些不都是它先搞了构造函数,构造函数整的实例和共享对象们(实例的隐式.__proto__ 函数的显示prototype)
    (2)为什么是===
    因为需要确定是相同而不是相等
    这么说如果用的是== 并且你的链子上有重名的,那就会被判断相等~ 但实际上并不是两个相同的东东啊
    自己尝试一下,那就先从写构造函数开始吧(构造函数的名字在这里担任了类名这一角色)
    function qwq(){
        this.qwqq=1;
    }
    var obj1=new qwq()  哇呀,卡住了…… 我只会从object生成构造函数,不会继承qwq函数呀…… 果然继承没有好好学.jpg
    这里理解是错的,==和===的区别只是是否会额外类型转换而已。
    具体为啥…… ==也是可以的,但一般都是用===
     

    补了继承再来新增

    之前不知道纯粹是因为没自己下手试试吧。。。就会发现实际上有这么多问题
    所以说不是我开始追根究底了
    只是之前的我太不会动手实践了  人家课什么的没啥问题
     
    最后,这里是偏向原理的部分,为什么这么设计(?)
    https://www.ruanyifeng.com/blog/2011/06/designing_ideas_of_inheritance_mechanism_in_javascript.html 
    (1)首先,js里一切都是对象,

    如果真的是一种简易的脚本语言(设计初衷),其实不需要有"继承"机制。但是,Javascript里面都是对象,必须有一种机制,将所有对象联系起来。所以,Brendan Eich最后还是设计了"继承"。

    但是,他不打算引入"类"(class)的概念,因为一旦有了"类",Javascript就是一种完整的面向对象编程语言了,这好像有点太正式了,而且增加了初学者的入门难度。

    (2)他把new命令引入了js,用来从原型对象生成一个实例对象。但是,Javascript没有"类",怎么来表示原型对象呢?

    这时,他想到C++和Java使用new命令时,都会调用"类"的构造函数(constructor)。他就做了一个简化的设计,在Javascript语言中,new命令后面跟的不是类,而是构造函数。

    『仔细想想,确实var c=new Array() 首先是array()有括号那么是函数 显然这不是一个对象来的。。』而Array []这才 是一个对象。

    举例来说,现在有一个叫做DOG的构造函数,表示狗对象的原型。

      function DOG(name){

        this.name = name;

      }

    对这个构造函数使用new,就会生成一个狗对象的实例。

      var dogA = new DOG('大毛');

      alert(dogA.name); // 大毛

    注意构造函数中的this关键字,它就代表了新创建的实例对象。

    (3)但是,单单这样做还是有个问题,那就是无法共享属性和方法

    比如,在DOG对象的构造函数中,设置一个实例对象的共有属性species。然后,生成两个实例对象,这两个对象的species属性是独立的,修改其中一个,不会影响到另一个。每一个实例对象,都有自己的属性和方法的副本。这不仅无法做到数据共享,也是极大的资源浪费。这样就引入了prototype

    考虑到这一点,Brendan Eich决定为构造函数设置一个prototype属性。

    这个属性包含一个对象(以下简称"prototype对象"),所有实例对象需要共享的属性和方法,都放在这个对象里面;那些不需要共享的属性和方法,就放在构造函数里面。

    实例对象一旦创建,将自动引用prototype对象的属性和方法。也就是说,实例对象的属性和方法,分成两种,一种是本地的,另一种是引用的。

    species属性放在prototype对象里,是两个实例对象共享的。只要修改了prototype对象,就会同时影响到两个实例对象。

    由于所有的实例对象共享同一个prototype对象,那么从外界看起来,prototype对象就好像是实例对象的原型,而实例对象则好像"继承"了prototype对象一样。

    这就是Javascript继承机制的设计思想。

    后面还有三篇~ 时间关系没有看qwq~


    有时间把后面三篇继承相关的补了

    这本书不错,能找到什么在线版本吗?https://www.bookstack.cn/read/javascript-tutorial/README.md
     
    最后附上阮一峰this这篇的的教程
     
    1、理解诸如var foo = obj.foo的形式原理
    从函数是存储的相关地址开始(函数名实际上只是保存函数地址的一个变量,也因为这样函数可以这样在不同上下文(环境)执行,加上JavaScript 允许在函数体内部,引用当前环境的其他变量。this就指代了当前的运行环境。。)
    (1)对于
    var obj = { foo:  5 };
    上面的代码将一个对象赋值给变量obj。
    JavaScript 引擎会先在内存里面,生成一个对象{ foo: 5 },
    然后把这个对象的内存地址赋值给变量obj。

    也就是说,变量obj是一个地址(reference)。后面如果要读取obj.foo,引擎先从obj拿到内存地址,然后再从该地址读出原始的对象,返回它的foo属性。

    原始的对象以字典结构保存,每一个属性名都对应一个属性描述对象。举例来说,上面例子的foo属性,实际上是以下面的形式保存的。

    ↑ obj=foo对象的地址 
    ↓ obj=foo对象的地址 foo对象=函数的地址
    (2)对于函数
    var obj = { foo: function () {} };
    

    这时,引擎会将函数单独保存在内存中,然后再将函数的地址赋值给foo属性的value属性。

    由于函数是一个单独的值,所以它可以在不同的环境(上下文)执行。

    一旦var foo = obj.foo,变量foo就直接指向函数本身,所以foo()就变成在全局环境执行。

    (因为啊,obj.foo相当于是拿到了obj对象里foo函数的地址,函数的地址就是存储的那一整个函数,然后定义var foo也指向这个这个地址,name

    var foo = obj.foo

    也就等于 var foo = function () {} // 此处是foo函数的具体内容)

    这里是foo是函数名,如果是var foo = obj.foo()那就是会返回函数的执行结果(也就是reurn值了)

    (3)有关环境变量

    JavaScript 允许在函数体内部,引用当前环境的其他变量。

    var f = function () {
      console.log(x);
    };
    

    上面代码中,函数体里面使用了变量x。该变量由运行环境提供。

    由于函数可以在不同的运行环境执行,所以需要有一种机制,能够在函数体内部获得当前的运行环境(context)。所以,this就出现了,它的设计目的就是在函数体内部,指代函数当前的运行环境。

    this=当前的运行环境
    面代码中,函数体里面的this.x就是指当前运行环境的x
    var f = function () {
      console.log(this.x);
    }
    回到最开始的问题
    var f = function () {
      console.log(this.x);
    }
    var x = 1;
    var obj = {
      f: f,
      x: 2,
    };
    // 单独执行 函数f在全局环境执行,this.x指向全局环境的x f() // 1 // obj 环境执行 在obj环境执行,this.x指向obj.x。 obj.f() // 2
    啊啊先总结特点:
    首先this就是指代的运行环境,其次容易搞混的xx的函数都转换成函数地址和代码块就好懂多了
    上面这些,只是懂了函数的指代,具体this在干什么还是不懂,
    (4)在函数里!全局调用函数里面的this还是指向全局,只有调用了对象里面的this才可以保存下来。

    ES6 中的箭头函数并不会创建其自身的执行上下文,所以箭头函数中的 this 取决于它的外部函数

    嵌套函数中的this不继承(负负得正)

     
    稍微补充一下:为什么是===
    手写继承来实现为什么是===不是==?
     
    (1) "==="叫做严格运算符,"=="叫做相等运算符。
    绝大多数场合应该使用 === ,只有检测 null/undefined 的时候可以使用 x == null(因为null本来和其他值都不是一个类型,一进===肯定是false,除非是null===null是true)定义了==的时候和其他的比较也是true,那可以不进===
    嗯哼,null===null,false也是,2 3 都ok
    null==undefined √ null===undefined × ,因为类型不同了。
    **==是相等,先转换再比较,返回true。
    ===是全等,不转换就比较,返回true。**
    下面是规范:

    严格运算符的运算规则如下,

    (1)不同类型值
    如果两个值的类型不同,直接返回false。
    (2)同一类的原始类型值
    同一类型的原始类型的值(数值、字符串、布尔值)比较时,值相同就返回true,值不同就返回false。
    (3)同一类的复合类型值
    两个复合类型(对象、数组、函数)的数据比较时,不是比较它们的值是否相等,而是比较它们是否指向同一个对象。
    (4)undefined和null
    undefined 和 null 与自身严格相等。
    null === null  //true
    undefined === undefined  //true
    相等运算符在比较相同类型的数据时,与严格相等运算符完全一样。
    在比较不同类型的数据时,相等运算符会先将数据进行类型转换,然后再用严格相等运算符比较。

    相等运算符 

    相等运算符隐藏的类型转换,会带来一些违反直觉的结果。
    '' == '0'           // false
    0 == ''             // true
    0 == '0'            // true
    false == 'false'    // false
    false == '0'        // true
    ' ' == 0     // true
    这就是为什么建议尽量不要使用相等运算符。
    至于使用相等运算符会不会对后续代码造成意外影响,答案是有可能会。
    !是(逻辑非) 如果操作数能够转换为false就返回true 
    var a = undefined;
    if(!a){       /// 里面的如果能被转换成false,就会继续操作 
        console.log("1"); //1
    }
    if(a == null){    // 走了undefined==null这个捷径
        console.log("1"); //1
    }
    var a = undefined;
    if(a === null){
        console.log("1"); //无输出
    }
    也就是说当a为undefined时,输出的值会有变化,而在编程中对象变成undefined实在是太常见了。

    知识漏洞又出现了,他们的区别就只是是否会提前类型转换,如果 是指向不同地址的两个对象,不管是==还是===都会false,相同地址是对象都是true

    var obj1={name:1}
    var obj2={name:1}
    obj1==obj2 三个等号亦然
    obj2=obj1 (地址相同了),这里之后比较都是true
    之前我一直以为==不判断地址,===判断地址?他们都是判断地址的啊啊啊。
     
    那么回到上面,在原型链instanceof这题里
    最好都用===来做,
    __proto__==prototype也是预防类型不同的时候直接返回false吧?好像没啥必要啊QAQ 
     
     
    不得不说,游戏确实挺能消磨人的耐性。。今天我和昨天玩的内容就差不多,甚至做得事情还多一些,然鹅一个9小时一个4小。。。
    本来上面这些,在公交车上回来路上想的很清楚了,结果回来清了个体力的功夫,当时的豪情壮志荡然无存了_(:з」∠)_
    脑子能够灵光一现的时候可太少了呀
    最后…… 不行了,完全木有耐心,列一下还没弄玩的:
    1.new时候发生了什么(详细):https://alexzhong22c.github.io/2017/08/12/js-new-happen/
    2.彻底搞懂js原型链继承 https://juejin.cn/post/6844903503354134541 (和浮动那个是一个来源)
    3.事件循环(就是很长的那篇甚至涉及到nexttick)https://juejin.cn/post/6844903968292749319#heading-2 这里还有涉及到https://blog.csdn.net/qdmoment/article/details/83657410
    4.宏任务微任务确实是这样 https://www.cnblogs.com/wonyun/p/11510848.html
    5.rrf写的事件循环 但不涉及详细的 https://www.ruanyifeng.com/blog/2014/10/event-loop.html
     
    题目部分
    1.面试题总结(手写部分,看着还行)https://zhuanlan.zhihu.com/p/371637636
    2. github上的面试题按热度排序https://github.com/lgwebdream/FE-Interview/issues?q=is%3Aissue+is%3Aopen+sort%3Acomments-desc
  • 相关阅读:
    关于CLR、CIL、CTS、CLS、CLI、BCL和FCL
    (DateTime)日期型数据转换成C#长整型数据
    List<T>.FindIndex 方法 (Predicate<T>)
    C#用int的0--31位表示32个bool值,int拆分成bool数组
    C# 协程 WaitForSeconds产生GC(Garbage Collection)问题
    Unity3D教程:尽量避免使用foreach
    NGUI中button无法用find函数找到
    Vue + axios + SpringBoot 2实现导出Excel
    Kafka 0.10.1版本源码 Idea编译
    Gradle Wrapper
  • 原文地址:https://www.cnblogs.com/lx2331/p/15195029.html
Copyright © 2020-2023  润新知