• 匿名函数自执行原理和instanceof运算符执行原理


    今天收到RSS订阅中有一篇《Javascript – Arraylike的7种实现》,看第一种实现方式是,瞬间被!function(){}()这种匿名函数自执行方式给亮瞎了眼睛。这种写法绝对是装逼神器,代码如下:

     1 !function () {
     2     //通过闭包实现
     3     var List = function () {
     4         var list = [],
     5             self = {
     6                 constructor: List,
     7                 //如果希望更像原生一点,将length定义为属性,那么length则需要自己维护
     8                 length: function () { return list.length; },
     9                 add: function (item) {
    10                     list.push(item);
    11                 },
    12                 eq: function (index) {
    13                     return list[index];
    14                 }
    15             };
    16         return self;
    17     };
    18     //测试
    19     console.group('第一种 - 通过闭包实现');
    20     var demo = new List();
    21     demo.add('List - add()');
    22     console.log('demo instanceof List : %c' + (demo instanceof List), 'color:red;');
    23     console.log('demo.constructor === List :%c' + (demo.constructor === List), 'color:blue');
    24     //无法通过索引demo[0]这种方式访问
    25     console.log('成员:[ ' + demo.eq(0) + ' , ' + demo.eq(1) + ' ]');
    26     console.log('length:' + demo.length());
    27     //注意看demo对象
    28     console.log(demo);
    29     console.groupEnd();
    30 }();

    其实-function(){}();+function(){}();~function(){}()这些也可以实现匿名函数的自执行,其原理就是当function(){}()前面有一个运算符时,js解释器在“看到”运算符后,会在后面继续寻找用于计算的值function(){},然后执行这个函数得到用于运算的值。在进行取反或加之类的运算时,由于js会将除null,undefined,0等个别的数转换为boolan值中的false,其它的字符串,对象函数都会转换为true,所以对函数进行一次取反运算不会抛出异常,也不会改变这个函数。同理,进行加运算也是一样,js会把对象和函数尝试转换为数字,得到NaN而不会抛出异常。这个可以使用如下代码进行验证:

    console.log(!function () {
            console.log(1); 
        }) ;  //只会打印出false,不会打印出1
    console.dir(-function () {
            console.log(1);
        });  //只会打印出NaN
    

      很明显,使用?function(){}()会比使用(function(){})()多一次运算过程。当js解释器知道function(){}是个函数后,在其后面加一个括号,则其调用这个函数,其是这和将function(){}赋值给一个变量a,然后使用a()调用一样。那么为什么不能直接使用function(){}()调用呢?其实我们可以看这样调用在chrome中报的错:  Uncaught SyntaxError: Unexpected token ( ,这和写function()报出的错误一样。可以发现,js解释器将function(){}()解析成了function();{}();为什么会解析成这样呢?还有就是为什么写成(function(){}())也可以正确执行呢?我们可以去看看函数的定义,在《javascript权威指南第6版》中对于函数的定义这样写道:函数使用function关键字来定义,它可以用在函数定义表达式或者函数声明语句里。函数定义表达式的语法为var functionName = function(){};函数声明语句语法为function funcname(){};所以,如果不写括号,javascript解释器会试图将关键字function解析为函数声明语句(同理用于运算的值只能是表达式和不能是声明语句)。在function前面使用了圆括号,则javascript解释器才会正确地将其解析为函数定义表达式(匿名)。这样就可以指定,Unexpected token ( 错误是因为expect 函数名。

    instanceof

    我们再来看看最上面代码的22行,

    demo instanceof List   =====> false

    其实很简单,因为List有返回值,所有var demo = new List();其实等价于var demo = List(); 所有demo并不是List的实例。在来看看instanceof的定义:

    instanceof运算符希望左操作数是一个对象,有操作数标识对象的类。如果左侧的对象是右侧类的实例,则表达式返回true;否则返回false。JavaScript中对象的类是通过初始化它们的构造函数来定义的。这样的话,instanceof的右操作数应当是一个函数,如果右操作数不是函数,则抛出一个类型错误异常。注意,所有的对象都是Object的实例。
    为了计算表达式 o instanceof f,javascript首先计算f.prototype,然后在原型链中查找o,如果找到,那么o是f(或者f的父类)的一个实例,则表达式instanceof返回ture。
    其原理是对象o中存在一个隐藏成员__proto__,该成员指向其父类的原型,如果父类的原型是另一个类的实例的话,这个原型对象中也存在__proto__指向另外一个类的原型,这就是原型链。

      function Person(){
        this.name = 'xt';
        this.get = function(){
          return "xt1";
        }
      }
      var p = new Person();

      var List = function(){
       var list = [],
         self = {
          constructor: List,
         //如果希望更像原生一点,将length定义为属性,那么length则需要自己维护
          length: function () { return list.length; },
          add: function (item) {
          list.push(item);
        },
        eq: function (index) {
          return list[index];
          }
        };
       return self;
      };
      var li = new List();

    console.log(p.__proto__ === Person.prototype); //true
    console.log(li.__proto__ === List.prototype); //false
    
    function inherit(p){
        function f(){}
        f.prototype = p;
        return new f();
    }
    var student = inherit(p); //student对象继承p对象。
    
    console.log(student.__proto__ === Person.prototype); //false
    console.log(student.__proto__.__proto__ === Person.prototype); //true
    

      

  • 相关阅读:
    Codeforces 1166 D. Cute Sequences 构造
    ZOJ 4103 浙江省第16届大学生程序设计竞赛 D题 Traveler 构造
    ZOJ 4100 浙江省第16届大学生程序设计竞赛 A题 Vertices in the Pocket 线段树+并查集
    若干结论和定理(持续更新)
    三类经典贪心问题
    2018 ICPC Asia Xuzhou Regional M. Rikka with Illuminations
    Educational Codeforces Round 99
    2018 CCPC-Final K
    2020浙江省赛 Huge Clouds
    BZOJ1030 文本生成器(AC自动机+DP)
  • 原文地址:https://www.cnblogs.com/towersxu/p/4378070.html
Copyright © 2020-2023  润新知