comprensión del constructor js

Como base del prototipo y la cadena de prototipos, comprender primero al constructor y su proceso de ejecución puede ayudarnos a aprender mejor el conocimiento del prototipo y la cadena de prototipos.

1. ¿Qué es un constructor?

En JavaScript, una función llamada con la nueva palabra clave se llama constructor. La primera letra del constructor suele estar en mayúscula.

2. ¿Por qué usar un constructor?

Aprende cada concepto, no solo qué es, sino por qué y qué tipo de problema resuelve.

Por ejemplo, queremos ingresar la información personal de cada compañero de primer grado, luego podemos crear algunos objetos, como:

var p1 = { name: 'zs', age: 6, gender: '男', hobby: 'basketball' };
var p2 = { name: 'ls', age: 6, gender: '女', hobby: 'dancing' };
var p3 = { name: 'ww', age: 6, gender: '女', hobby: 'singing' };
var p4 = { name: 'zl', age: 6, gender: '男', hobby: 'football' }; 
// ...
复制代码

Al igual que lo anterior, podemos tratar la información de cada compañero como un objeto. Sin embargo, encontraremos que repetidamente escribimos mucho código sin sentido. Como nombre, edad, género, pasatiempo. Si hay 60 alumnos en esta clase, tenemos que repetirlo 60 veces.

En este momento, se reflejan las ventajas de los constructores. Descubrimos que aunque cada compañero de clase tiene atributos como nombre, género y pasatiempo, todos son diferentes, por lo que pasamos estos atributos como parámetros del constructor. Dado que todos son estudiantes de primer año, la edad es básicamente de 6 años, por lo que podemos escribir a la muerte y podemos tratarla por separado en caso de circunstancias especiales. En este punto, podemos crear la siguiente función:

function Person(name, gender, hobby) {
    this.name = name;
    this.gender = gender;
    this.hobby = hobby;
    this.age = 6;
} 
复制代码

Cuando se crea la función anterior, podemos llamarla a través de la nueva palabra clave, es decir, crear un objeto a través del constructor.

var p1 = new Person('zs', '男', 'basketball');
var p2 = new Person('ls', '女', 'dancing');
var p3 = new Person('ww', '女', 'singing');
var p4 = new Person('zl', '男', 'football');
// ... 
复制代码

En este punto encontrará que la creación de objetos se vuelve muy conveniente. Por lo tanto, aunque el proceso de encapsular el constructor será más complicado, una vez que la encapsulación sea exitosa, será muy fácil para nosotros crear el objeto, por lo que usamos el constructor.

Cuando se usan literales de objeto para crear una serie de objetos del mismo tipo, estos objetos pueden tener algunas características (propiedades) y comportamientos (métodos) similares, lo que resultará en una gran cantidad de código repetitivo, que se puede lograr mediante el uso de constructores 代码复用.

3. El proceso de ejecución del constructor

Hablemos primero de algunos conceptos básicos.

function Animal(color) {
 this.color = color;
} 
复制代码

Cuando se crea una función, no sabemos si es un constructor o no, incluso si el nombre de la función está en mayúsculas como en el ejemplo anterior, no podemos estar seguros. Podemos decir que una función es un constructor solo cuando se llama con la palabra clave new. Me gusta lo siguiente:

var dog = new Animal("black"); 
复制代码

A continuación solo discutimos el proceso de ejecución del constructor, es decir, el caso de llamar con la nueva palabra clave.

我们还是以上面的 Person 为例。

function Person(name, gender, hobby) {
 this.name = name;
 this.gender = gender;
 this.hobby = hobby;
 this.age = 6;
}

var p1 = new Person('zs', '男', 'basketball'); 
复制代码

此时,构造函数会有以下几个执行过程:

(1) 当以 new 关键字调用时,会创建一个新的内存空间,标记为 Animal 的实例。

(2)函数体内部的 this 指向该内存

通过以上两步,我们就可以得出这样的结论。

var p2 = new Person('ls', '女', 'dancing');  // 创建一个新的内存 #f2
var p3 = new Person('ww', '女', 'singing');  // 创建一个新的内存 #f3 
复制代码

每当创建一个实例的时候,就会创建一个新的内存空间(#f2, #f3),创建 #f2 的时候,函数体内部的 this 指向 #f2, 创建 #f3 的时候,函数体内部的 this 指向 #f3。

(3) 执行函数体内的代码
通过上面的讲解,你就可以知道,给 this 添加属性,就相当于给实例添加属性。

  1. 默认返回 this

由于函数体内部的this指向新创建的内存空间,默认返回 this ,就相当于默认返回了该内存空间,也就是上图中的 #f1。此时,#f1的内存空间被变量p1所接受。也就是说 p1 这个变量,保存的内存地址就是 #f1,同时被标记为 Person 的实例。

以上就是构造函数的整个执行过程。

4、构造函数的返回值

构造函数执行过程的最后一步是默认返回 this 。言外之意,构造函数的返回值还有其它情况。下面我们就来聊聊关于构造函数返回值的问题。

(1) 没有手动添加返回值,默认返回 this

function Person1() {
 this.name = 'zhangsan';
}

var p1 = new Person1(); 
复制代码

按照上面讲的,我们复习一遍。首先,当用 new 关键字调用时,产生一个新的内存空间 #f11,并标记为 Person1 的实例;接着,函数体内部的 this 指向该内存空间 #f11;执行函数体内部的代码;由于函数体内部的this 指向该内存空间,而该内存空间又被变量 p1 所接收,所以 p1 中就会有一个 name 属性,属性值为 ‘zhangsan’。 

p1: {
 name: 'zhangsan'
} 
复制代码

(2) 手动添加一个基本数据类型的返回值,最终还是返回 this

function Person2() {
 this.age = 28;
 return 50;
}

var p2 = new Person2();
console.log(p2.age);   // 28
p2: {
 age: 28
} 
复制代码

如果上面是一个普通函数的调用,那么返回值就是 50。

(3) 手动添加一个复杂数据类型(对象)的返回值,最终返回该对象

直接上例子

function Person3() {
 this.height = '180';
 return ['a', 'b', 'c'];
}

var p3 = new Person3();
console.log(p3.height);  // undefined
console.log(p3.length);  // 3
console.log(p3[0]);      // 'a' 
复制代码

再来一个例子

function Person4() {
  this.gender = '男';
  return { gender: '中性' };
}

var p4 = new Person4();
console.log(p4.gender);  // '中性' 
复制代码

5、构造函数首字母必须大写吗?

大小写都可以

6、不用new关键字,直接运行构造函数,是否会出错?如果不会出错,那么,用new和不用new调用构造函数,有什么区别?

  1. 使用new操作符调用函数

例子:

function Person(name){
  this.name = name;
  this.say = function(){
    return "I am " + this.name;
  }
}

var person1 = new Person('nicole');
person1.say(); // "I am nicole" 
复制代码

用new调用构造函数,函数内部会发生如下变化:

创建一个this变量,该变量指向一个空对象。并且该对象继承函数的原型;
属性和方法被加入到this引用的对象中;
隐式返回this对象(如果没有显性返回其他对象)
用伪程序来展示上述变化:

function Person(name){
  // 创建this变量,指向空对象
  var this = {}; 
  // 属性和方法被加入到this引用的对象中
  this.name = name;
  this.say = function(){
    return "I am " + this.name;
  }
  // 返回this对象
  return this;
} 
复制代码

可以看出,用new调用构造函数,最大特点为,this对象指向构造函数生成的对象,所以,person1.say()会返回字符串: “I am nicole”。

小贴士

如果指定了返回对象,那么,this对象可能被丢失。

function Person(name){
  this.name = name;
  this.say = function(){
    return "I am " + this.name;
  }
  var that = {};
  that.name = "It is that!";
  return that;
}

var person1 = new Person('nicole');
person1.name; // "It is that!" 
复制代码

  2. 直接调用函数

如果直接调用函数,那么,this对象指向window,并且,不会默认返回任何对象(除非显性声明返回值)。

还是拿Person函数为例,直接调用Person函数:

var person1 = Person('nicole');
person1; // undefined
window.name; // nicole 
复制代码

可见,直接调用构造函数的结果,并不是我们想要的。

3.小结

为了防止因为忘记使用new关键字而调用构造函数,可以加一些判断条件强行调用new关键字,代码如下

function Person(name){
  if (!(this instanceof Person)) {
    return new Person(name);
  }
  this.name = name;
  this.say = function(){
    return "I am " + this.name;
  }
}

var person1 = Person('nicole');
console.log(person1.say()); // I am nicole
var person2 = new Person('lisa');
console.log(person2.say()); // I am lisa
复制代码

Supongo que te gusta

Origin juejin.im/post/6955051085409026078
Recomendado
Clasificación