• 欢迎访问天天编码网站,Java技术、技术书单、开发工具,欢迎加入天天编码
  • 如果您觉得本站非常有看点,那么赶紧使用Ctrl+D 收藏天天编码吧
  • 我们的淘宝店铺已经开张了哦,传送门:https://shop145764801.taobao.com/

4.6 构造器与new操作符

JS 教程 tiantian 150次浏览 0个评论 扫描二维码

那个普通的{...}语法可以轻松地创建一个对象。但是,我们经常需要创建多个类似的对象,比如多个用户或者菜单项等等。

这种情况下,我们可以使用构造器函数和"new"操作符。

构造器函数

就语法而言,构造器函数也是普通的函数。但是,构造器函数存在两个约定:

  1. 构造器函数的名称应该首字符大写。
  2. 构造器函数应该只与"now"操作符一起使用。

举个例子:

function User(name) {
  this.name = name;
  this.isAdmin = false;
}

let user = new User("Jack");

alert(user.name); // Jack
alert(user.isAdmin); // false

当函数与new操作符一起执行时:new User(...),它会执行如下的步骤:

  1. 一个新的空对象被创建,并且该对象被赋值给this
  2. 该函数的函数体被执行。通常而言,它会修改this,往其中添加新属性。
  3. 返回this的值。

换句话说,new User(...) 完成的操作如下:

function User(name) {
  // this = {};  (implicitly)

  // add properties to this
  this.name = name;
  this.isAdmin = false;

  // return this;  (implicitly)
}

所以,new User("Jack")操作的结果相同与如下的对象:

let user = {
  name: "Jack",
  isAdmin: false
};

现在,如果我们期望去创建其他的用户,我们可以调用new User("Ann")new User("Alice") 等等。每次的代码都比使用对象字面量的简短,而且更容易阅读。

那就是构造器函数的真正目的——实现对象创建代码的可重用性。

让我们来再次聚焦构造器函数——就技术而言,任何的函数都可以作为构造器函数来使用。也即是:任何函数可以与new操作符一起使用,而且也会执行上述相同的算法。那个“首字符大写”只是一个通用的约定,使得该函数应该只与new操作符一起使用变得更加清晰。

new function() {…}

如果我们创建一个单一复杂对象的函数具有很多行代码,我们就可以将它们包装在一个构造器函数中,比如:

let user = new function() {
 this.name = "John";
 this.isAdmin = false;

 // ...other code for user creation
 // maybe complex logic and statements
 // local variables etc
};

那个构造器函数无法再次被调用,因为它并没有被保存在任何位置,只是创建它并调用它。所以,这样的一个编程技巧只是封装了那些用来创建单一对象的代码,并且无法被复用。

双语法构造器:new.target

在函数的内部,我们可以检查该函数是否正被new操作符调用,这只需要使用一个特殊的new.target属性。

该属性在普通调用时为空,在使用new操作符调用时等于该函数:

function User() {
  alert(new.target);
}

// without new:
User(); // undefined

// with new:
new User(); // function User { ... }

这样的一个规则可用来使得函数的new操作符调用和普通语法调用具有相同的功能:

function User(name) {
  if (!new.target) { // if you run me without new
    return new User(name); // ...I will add new for you
  }

  this.name = name;
}

let john = User("John"); // redirects call to new User
alert(john.name); // John

有时,这个技巧被用在很多的代码库中,使得函数调用语法更加自由。但是,在所有的地方都是用这样的哦一个技巧并不是一个好的编程实践,因为缺少new操作符使得该代码的可读性并不是那么友好。在代码中明确地使用new操作符,使得我们清晰地知道一个新的对象被创建,这对于代码可读性是一个帮助。

构造器的返回值

一般地,构造器函数没有明确的return语句。它们的任务是往this中填入所有必要的属性,然后this自然就成为了该函数的返回值。

但是,如果构造器函数中具有一个return语句,那么规则如下:

  • 如果return的操作数是一个对象,那么该对象就代替this返回。
  • 如果return的操作数是一个原始类型,那么该语句就会被忽略。

换句话说,return后面为对象时,就返回该对象,否则的话,就返回this

举个例子,此处的return通过返回一个对象,复写了this

function BigUser() {

  this.name = "John";

  return { name: "Godzilla" };  // <-- returns an object
}

alert( new BigUser().name );  // Godzilla, got that object ^^

此外,下列的示例中演示一个空的return(也可以替换为一个返回值为原始类型的return):

function SmallUser() {

  this.name = "John";

  return; // finishes the execution, returns this

  // ...

}

alert( new SmallUser().name );  // John

一般地,构造器函数没有return语句。此处,我们学习了构造器函数具有return语句的情况,包括return objectreturn primitive的情况,只是为了知识的完备性。

省略小括号

另外,如果函数没有参数的话,我们可以省略new操作符后面的小括号:

let user = new User; // <-- no parentheses
// same as
let user = new User();

注意,此处的省略小括号并不是一个好的编程实践,只是JavaScript语法上允许这样的写法。

构造器中的方法

利用构造器函数来创建对象使得代码具有非常大的灵活性。那个构造器函数可能具有参数,定义了如何构造那个对象,或者影响对象的的内容。

当然,我们不仅可以往this中添加属性,也可以添加方法。

举个例子,下列的 new User(name) 使用那个给定的name创建对象和其方法sayHi

function User(name) {
  this.name = name;

  this.sayHi = function() {
    alert( "My name is: " + this.name );
  };
}

let john = new User("John");

john.sayHi(); // My name is: John

/*
john = {
   name: "John",
   sayHi: function() { ... }
}
*/

总结

  • 构造器函数,或者简称为构造器,也是普通的函数。但是,构造器函数存在一个首字符大写的通用约定。
  • 构造器函数应该只使用new操作符调用。这样的调用会创建一个空的this对象,执行函数体,最后返回该this的值。

我们可以使用构造器函数来创建多个相似的对象。

JavaScript 为很多的语言内建的对象都提供了构造器函数:比如日期的 Date,集合的Set,还有其他我们将要学习的构造器函数。

对象,我们会再次深入

在本章中,我们仅仅学习了对象爱你个和构造器函数的基本知识。掌握它们对于在接下来的章节中继续学习更多数据类型和函数相关的知识是足够的。

在我们学习完那些知识之后,我们将在对象,类,继承章节继续深入学习对象的知识,包括比较高级的继承和类的知识点。

任务


两个函数——一个对象

是否可能创建两个函数AB,而且new A()==new B()?

function A() { ... }
function B() { ... }

let a = new A;
let b = new B;

alert( a == b ); // true

如果可以,请提供函数AB的一个实例代码。


创建新的计算器

创建一个构造器函数Calculator,可以创建一个具有三个方法的对象:

  • read() 使用prompt函数要求用户输入两个数值,并将它们存储为对象属性。
  • sum() 返回对象属性的累加值。
  • mul() 返回对象属性的相乘值。

举个例子:

let calculator = new Calculator();
calculator.read();

alert( "Sum=" + calculator.sum() );
alert( "Mul=" + calculator.mul() );

创建一个新的累加器

创建一个构造器函数Accumulator(startingValue)

它创建的对象应该:

  • 存储当前值到属性value中。这个原始值来自于构造器的参数startingValue
  • 那个read()方法应该使用prompt来读取新值并添加到value中。

换句话说,那个value属性应该是所有用户输入值在加上初始值startingValue的结果。

下面是一个示例代码:

let accumulator = new Accumulator(1); // initial value 1
accumulator.read(); // adds the user-entered value
accumulator.read(); // adds the user-entered value
alert(accumulator.value); // shows the sum of these values


天天编码 , 版权所有丨本文标题:4.6 构造器与new操作符
转载请保留页面地址:http://www.tiantianbianma.com/constructor-new.html/
喜欢 (0)
支付宝[多谢打赏]
分享 (0)
发表我的评论
取消评论

表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址