js构造函数

构造函数

通过 new 函数名 来实例化对象的函数叫构造函数。
任何的函数都可以作为构造函数存在。之所以有构造函数与普通函数之分,主要从功能上进行区别的,构造函数的主要 功能为 初始化对象,特点是和new 一起使用。new就是在创建对象,从无到有,构造函数就是在为初始化的对象添加属性和方法。构造函数定义时首字母大写(规范)。

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

let p1 = new Person('张三'); // 实例化

console.log(p1); // Person {name: "张三"}

此时,p1就是一个新对象。

1. new一个新对象的过程,发生了什么?

  1. 创建一个空对象obj {}
  2. 空对象的_proto_指向了构造函数的prototype成员对象
  3. 使用apply调用构造器函数,属性和方法被添加到 this 引用的对象中
  4. 如果构造函数中没有返回其它对象,那么返回 this,即创建的这个的新对象,否则,返回构造函数中返回的对象

对new理解:new 申请内存, 创建对象,当调用new时,后台会隐式执行new Object()创建对象。所以,通过new创建的字符串、数字是引用类型,而是非值类型。

2. 手写new函数

function _new(func, ...args) {
    // 1. 创建空对象
    let obj = {};
    // 2. 空对象的_proto_指向了构造函数的prototype成员对象
    obj.__proto__ = func.prototype; // 一二步合并就相当于 let obj = Object.create(func.prototype)
    // 3. 使用apply调用构造器函数,属性和方法被添加到 this 引用的对象中
    let result = func.apply(obj, args);
	// 4. 确保 new 出来的是个对象
    return typeof result === 'object' ? result : obj;
}

测试用例:

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

let obj = _new(Person, 'xia', 20);

console.log(obj); // Person {name: "xia", age: 20}

3. 构造函数上的方法

  1. 在构造函数上直接定义方法(不共享)
function Person() {
    this.say = function () { // 直接定义方法
        console.log('hello');
    }
}

let p1 = new Person();
let p2 = new Person();
p1.say(); // hello
p2.say(); // hello

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

很明显,p1 和 p2 指向的不是一个地方。 所以 在构造函数上通过 this 来添加方法的方式来生成实例,每次生成实例,都是新开辟一个内存空间存方法。这样会导致内存的极大浪费,从而影响性能

  1. 通过原型添加方法(共享)

构造函数通过原型分配的函数,是所有对象共享的。

function Person(name) {
    this.name = name;
}
Person.prototype.say = function () { // 通过原型添加方法
    console.log('hello ' + this.name);
}

let p1 = new Person('张三');
let p2 = new Person('李四');
p1.say(); // hello 张三
p2.say(); // hello 李四

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

所以我们经常 将公共属性定义到构造函数里,将公共方法放到原型对象上

点击查看“构造函数的五种继承方式”

你可能感兴趣的:(JavaScript,javascript,开发语言)