面试题

75 阅读4分钟
  // 这里定义一个构造函数 Foo
  function Foo() {
    // 这里没有let var  const  声明直接赋值,相当于全局变量(window)但是这个函数没有执行,里面赋值就不会进行
    // 注意这个方法,不会添加的 new出来的实例化对象上面
    getName = function () {
      console.log(1);
    };
    // 这里返回 this  是为了后面  Foo().getName();  进行调用  函数没有返回值就是 udf  udf点任何属性都会报错的
    // 这个也可以不返回  Foo()  getName()  这样也是可以的
    return this;
  }

  Foo.getName = function () {
    // 函数是一个特殊的对象 ,只不过函数多了一个 call 属性可以进行调用而已  call也可以用来修改this指向
    // 也就是说 Foo这个对象 上面添加一个方法 这个方法不在 构造函数里面 那么 new出来的对象也不会用这个方法
    // 这就是静态成员 ,es6的类可以用  static关键字 变成静态成员
    // 静态成员相对应的是 动态成员 也就是new可以继承的
    console.log(2);
  };

  Foo.prototype.getName = function () {
    // 这个是添加到原型连上面的 new Foo出来的对象 就可以调用这个方法 相当于  Foo.prototype.getName()  这样调用;
    // es6  就可以不用怎么麻烦在原型上添加方法
    // class Foo {
    //  这个方法相当于添加到原型上面了
    //   getName = function () {
    //     console.log(3);
    //   };
    // }
    console.log(3);
  };

  var getName = function () {
    // 这是声明全局的变量 ,通过var  声明的  var会变量提升,这里用let声明就会报错
    // 因为函数变量提升 声明过了 你let又声明一次就会报错
    console.log(4);
  };
  // 函数也会变量提升 不过函数是整体提升上去  var  这是声明而已
  // var getName
  // getName =getName() {  console.log(5); }  后面  var 还有个赋值操作 又覆盖了
  // getName =getName() {  console.log(4); }
  function getName() {
    console.log(5);
  }
  // Foo对象调用自己的getName方法  也就是静态方法
  Foo.getName(); //2
  // 这里调用 全局(window)的getName方法  函数声明的5 被  var 声明的 4覆盖了
  getName(); //4
  // new 作用  创建对象 函数里面的this指向这个对象 指向函数  返回这个对象
  // 这里没有new  也就是里面的this指向的是  (window)执行这个函数里面的代码,覆盖了上面的 全局的getName方法 4变成了1
  Foo().getName(); //1
  // 全局都被修改了 getName方法 就是1
  getName(); //1
  // 这里new 没有作用(构造函数没有被调用)  相当于调用静态方法
  new Foo.getName(); //2
  // 这里是 new 执行 返回这个对象 这个对象  没有这个方法 就会往原型上面找        Foo.prototype.getName  也就是这个方法 3
  new Foo().getName(); //3
  // 这里是  new Foo() => {} .getName() => new udf 虽然不会报错但是这个new没有什么作用的
  // 你 new new Foo()这样就会报错  说你这个不是一个构造函数说
  new new Foo().getName();
  // TypeError: (intermediate value) is not a constructor TypeError:(中间值)不是一个构造函数 也就是说你没有这个函数  这个函数是 new时候都会有的
  // new Foo() => new  {} ()  这个{} 也就是中间值不是一个构造函数了
  new new Foo()();    
      // let a = true; true 会转换成为1
      // console.log(a == 1 && a == 2 && a == 3);
      // console.log(a == 1); //true
      // console.log(a == 2); //false
      // console.log(a == 3); //false

      // 一个对象或者是数组相加,本身是加不了的。就需要进行隐s转换,这里就会调用toSting方法了
      // let a = {
      //   _a: 0,
      //   toString() {
      //     return ++this._a;
      //   },
      // };
      // if (a == 1 && a == 2 && a == 3) {
      //   console.log('成功了');
      // }

      // JS里面直接使用变量,没有声明这个变量就会存在全局里面也就是wd里面
      // let _a = 0;
      // Object.defineProperty(window, 'a', {
      //   get() {
      //     return ++_a;
      //   },
      // });

      // if (a === 1 && a === 2 && a === 3) {
      //   console.log('成功了');
      // }

      // 这里{}+{}本身就不能直接进行计算,就需要通过转换。进行隐私转换。({}).toString()  {}直接调用这个toString是会报错的
      // 就需要通过()进行调用,这个本身会  let data = {}并没有什么区别  '[object Object]' + '[object Object]'
      let a = ({} + {}).length; //30
      // 这里[] + []本身就不能直接进行计算,就需要通过转换。进行隐私转换。数组的toString指的是什么呢?是里面的元素也就是[1,2]这里就是2
      let b = ([] + []).length;
      let c = function (a, b, c, d) {
        console.log(arguments.length);
      };

      c(1, 2, 3);
      // Arguments(3) [1, 2, 3, callee: ƒ, Symbol(Symbol.iterator): ƒ]
      // 0
      // :
      // 1
      // 1
      // :
      // 2
      // 2
      // :
      // 3
      // callee
      // :
      // ƒ (a, b, c)
      // length
      // :
      // 3
      // Symbol(Symbol.iterator)
      // :
      // ƒ values()
      // [[Prototype]]
      // :
      // Object;
      // 普通函数是有 arguments这个属性指的是数组里面都是实参,那么数组的 toString是什么就是里面的元素个数了
      // Arguments.callee  就是形参了  实参和形参关系是映射关系,相当于  = 赋值的关系
      let d = function (a, b, d, e) {}.length;
      console.log(a, b, d);