JavaScript——new关键字详解

一、new原理

new的实现步骤(原理)如下:

  1. 第一步:创建一个空对象,作为将要返回的对象
  2. 第二步:将这个空对象的原型指向构造函数的prototype属性,也就是将对象的__proto__属性指向构造函数的prototype【让对象能沿着原型链去使用构造函数中prototype上的方法】
  3. 第三步:将这个空对象赋值给构造函数内部的this关键字,执行构造函数。【让构造器中设置的属性和方法设置在这个对象上】
  4. 第四步:返回这个对象。
function F() {}
let f = new F()

F构造函数为例,上面原理转换为伪代码大概是这样的:

  1. let obj = {}
  2. obj.__proto__ = F.prototype
  3. F.apply(obj, 参数)
  4. return obj

因此,我们可以手搓一个new方法试试:

let _new = function (F, ...args) {
  // let obj = {};
  // obj.__proto__ = F.prototype;
  let obj = Object.create(F.prototype);  // 简写
  F.apply(obj, args);
  return obj;
};

下面我们通过对比原生的new和我们手搓的_new的输出结果以验证手搓的_new效果如何:

let F = function (val, num) {  // 构造函数
  this.val = num;
  this.num = val;
  this.hello = function hello() {};
  function hi() {}
};
let _new = function (F, ...args) {  // 手搓new方法
  // let obj = {};
  // obj.__proto__ = F.prototype;
  let obj = Object.create(F.prototype);  // 简写
  F.apply(obj, args);
  return obj;
};
let f1 = new F(1, 2);
console.log(new F(1, 2));  // 原生的new的实例化输出结果
console.log(_new(F, 1, 2));  // 手搓的_new的实例化输出结果

上述代码运行结果如下:

可以看到手搓的_new方法实现效果是和原生new一样的。

二、new function和new class的区别

functionclass都可以作为构造函数,但它们之间也有不少区别:

  1. funtion定义构造函数存在提升,可以先使用后定义;class定义构造函数不存在提升,只能先定义后使用,否则会报错。

    // funtion定义构造函数存在提升,可以先使用后定义
    console.log(new F4());
    function F4() {
      this.name = 1;
    }
    // class定义构造函数不存在提升,只能先定义后使用
    class F5 {
      constructor() {
        this.name = 1;
      }
    }
    console.log(new F5());
    

    输出结果:在这里插入图片描述

    1. class不能调用call、apply、bind改变执行上下文。

      function F5() {
          console.log(this.name);
      }
      const obj1 = {
          name: 'Jack',
      };
      F5.call(obj1); // Jack
      
      class F6 {
          constructor() {
              console.log(this.name);
          }
      }
      const obj2 = {
          name: 'Jack',
      };
      F6.call(obj2); // Class constructor F6 cannot be invoked without 'new'
      

三、function作为构造函数的注意事项

  1. function尽量别有返回值,如果有返回值会根据返回值按如下处理:

    • 返回值不是对象:无视返回值,输出的实例对象结果是this对象。
    • 返回值是对象:将function当成方法处理,就不再是构造函数了。
    function F7() {
      this.name = "Jack";
      this.age = 18;
      return { name: "AAA" };
    }
    let f7 = new F7();
    console.log(f7); // {name: 'AAA'}
    
    function F8() {
      this.name = "Jack";
      this.age = 18;
      console.log(this); // F8 {name: 'Jack', age: 18}  这是this对象
      return 1;
    }
    let f8 = new F8();
    console.log(f8); // F8 {name: 'Jack', age: 18}   这是this对象
    
  2. 实例化对象需要加new,加new后构造函数里的this就指向该实例,不加的话指向的是window

    function F9(name, age) {
      this.name = name;
      this.age = age;
    }
    // 加new
    let f9_1 = new F9("Jack-1", 18);
    console.log(f9_1.name); // Jack-1
    // 不加new
    let f9_2 = F9("Jack-2", 18);
    // console.log(f9_2.name); // 报错
    console.log(window.name); // Jack-2 在window上 说明this指向window
    

为了避免第二个注意事项,我们可以在定义构造函数时添加一个判断来处理忘记加new的情况:

function F9(name, age) {
  // 处理漏加new的情况
  if (!(this instanceof F9)) {
    return new F9(name, age);
  }
  this.name = name;
  this.age = age;
}

测试结果:

// 加new
let f9_1 = new F9("Jack-1", 18);
console.log(f9_1.name); // Jack-1
// 不加new
let f9_2 = F9("Jack-2", 18);
console.log(f9_2.name); // Jack-2

可以看到这种方式是没有问题。

四、new一个箭头函数会怎么样

箭头函数是ES6中提出来的,它没有prototype,也没有自己的this指向,更可以使用arguments参数,所以不能new一个箭头函数。它会报如下错误:
在这里插入图片描述

  • 8
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
JavaScript中,let关键字是ES6新增的一个变量声明关键字,与var关键字相比具有一些特点和区别。 首先,let关键字声明的变量具有块级作用域。意味着在被声明的块级作用域内(如函数、循环、条件语句等),let关键字声明的变量仅在该块内部有效,超出该范围就无法访问。这与var声明的变量不同,var声明的变量具有函数作用域。 其次,let声明的变量不存在变量提升。在使用var声明变量时,可以在之后的代码中进行访问,即使在声明之前也不会报错。但是使用let声明的变量必须在声明之后才能访问,否则会抛出“暂时性死区(Temporal Dead Zone)”错误。这样就能杜绝在变量定义之前就使用变量的错误行为,提高代码的健壮性和可读性。 另外,使用let关键字可以避免变量的重复声明。在同一个作用域(包括嵌套作用域)中,使用let声明同名变量会报错,而使用var声明则会覆盖之前的同名变量。这样可以减少潜在的变量名冲突问题,提高代码的可维护性。 最后,let关键字声明的变量不会将变量名添加到全局对象中,而var声明的变量会成为全局对象的属性。这意味着使用let声明的变量在全局环境中不可访问,从而减少了全局命名空间的污染。 总之,let关键字JavaScript中具有块级作用域、不存在变量提升、不允许重复声明以及不污染全局环境等特点,使得变量的作用范围更加清晰、规范,提高了代码的可读性和健壮性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值