当前位置: 首页/ 学苑/学习Note/

构造函数

2018-05-10| 阅读:684 |类别:学习Note

1.什么是构造函数

在 JavaScript 中,用 new 关键字来调用的函数,称为构造函数。

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

var p1 = new Person('zs', '男', 'basketball');
var p2 = new Person('ls', '女', 'dancing');
var p3 = new Person('ww', '女', 'singing');
var p4 = new Person('zl', '男', 'football');

console.log(p1);
console.log(p2);
console.log(p3);
console.log(p4);

Person {name: "zs", gender: "男", hobby: "basketball", age: 6}
Person {name: "ls", gender: "女", hobby: "dancing", age: 6}
Person {name: "ww", gender: "女", hobby: "singing", age: 6}
Person {name: "zl", gender: "男", hobby: "football", age: 6}

在使用对象字面量创建一系列同一类型的对象时,这些对象可能具有一些相似的特征(属性)和行为(方法),此时会产生很多重复的代码,而使用构造函数就可以实现代码的复用。

每一次通过构造函数的形式来调用时,都会开辟一块新的内存空间,所以实例 p1 和 p2 所指向的内存地址是不同的。修改其中一个值,另外一个不会变化

p1.name = 'new p1';
console.log(p1);
console.log(p2);


Person {name: "new p1", gender: "男", hobby: "basketball", age: 6}
Person {name: "ls", gender: "女", hobby: "dancing", age: 6}

2.构造函数的返回值

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

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

var p1 = new Person1();

p1: {
  name: 'zhangsan'
}

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

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

var p2 = new Person2();
console.log(p2.age);   // 28

p2: {
  age: 28
}

(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);  // '中性'

参考: https://juejin.im/post/5aa0f0ef6fb9a028e52d69ea

3.什么是原型对象(解决公用函数指向不同,造成的空间浪费)

当一个函数 (注意:不仅仅只有构造函数) 创建好之后,都会有一个 prototype 属性,这个属性的值是一个对象,我们把这个对象,称为原型对象

同时,只要在这个原型对象上添加属性和方法,这些属性和方法都可以被该函数的实例所访问。

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

Person.prototype.say = function () {
        console.log('Hello');
};

var p1 = new Person('Tom', 18);
var p2 = new Person('Jack', 34);

console.log(p1.say === p2.say); // true

console.log(Person.prototype)
console.log(p1.__proto__)
console.log(p2.__proto__)
console.log(Person.prototype === p1.__proto__)   // true
console.log(Person.prototype === p2.__proto__)   // true
console.log(p1.__proto__ === p2.__proto___)     // false

A. Person 函数创建之后,会产生一块内存空间,并且有一个 prototype 属性
B. prototype 属性的值是一个对象,我们称之为原型对象
C. 原型对象中的属性和方法

(1)原型对象上,有一个 constructor 属性指向 Person; (2)原型对象上,有一个 say方法,会开辟一块新的内存空间; (3)原型对象上,有一个 __proto__ 属性

D. 实例中的属性和方法

当 p1 这个实例创建好之后,又会开辟一块新的内存空间。

(1)p1 实例中有一个 name 属性; (2)p1 实例中有一个 __proto__ 属性,指向构造函数 Person 的原型对象。

总结:

  1. 一个函数创建好之后,就会有一个 prototype 属性,这个属性的值是一个对象,我们把这个 prototype 属性所指向的内存空间称为这个函数的原型对象。

  2. 某个函数的原型对象会有一个 constructor 属性,这个属性指向该函数本身。

function Person() {
    // ...
}
console.log(Person.prototype.constructor === Person); // true

     3、当某个函数当成构造函数来调用时,就会产生一个构造函数的实例。这个实例上会拥有一个 __proto__ 属性,这个属性指向该实例的构造函数的原型对象(也可以称为该实例的原型对象)。

function Person() {
    // ...
}
var p1 = new Person();
console.log(p1.__proto__ === Person.prototype); // true

备注:

1、通过构造函数 Person.prototype.fn=function(){}  继承的方法是公用的,如果该方法发生了改变,则所有通过New Person生存的新函数的这个方法调用都会发生改变

参考:https://juejin.im/post/5aadd8da6fb9a028cf324006

觉得有用,烦请给个小赏¥以资鼓励!~~