美文网首页你不知道的JavaScript
你真的了解JS里的new吗?

你真的了解JS里的new吗?

作者: 写代码的海怪 | 来源:发表于2018-12-16 02:51 被阅读4次

前言

我们常常喜欢用new关键字去创建一些对象如new Vue(),但是这个关键字的背后究竟做了什么其实没太多人去关注。

想象我们是苹果公司,要生产30部iPod,规定:

  • 每台iPod都会有自己的ID
  • 每台iPod都是一样的制造商:Apple
  • 每台iPod的功能都是一样的(函数一样)
let iPod= {
    // 制造商不会变
    manufacturer: 'Apple',
    // 播放音乐
    play: function () { },
    // 暂停
    pause: function () { },
    // 继续播放
    resume: function () { }
}

好了,现在我们开始生产吧。

简单生产

要生产那么多iPod,那就循环30次吧。每次循环都创建一个对象,将这个对象加入到数组里就行了。

let box = []
let iPod

for (let i = 0; i < 30; i++) {
    iPod= {
        // 每次都改变 ID
        id: i,
        // 制造商不会变
        manufacturer: 'Apple',
        // 播放音乐
        play: function () {},
        // 暂停
        pause: function () {},
        // 继续播放
        resume: function () {}
    }

    box.push(iPod)
}

Manufacturer.deliver(box)

但是,这里有一个问题:每次都会新创建play()pause()resume()这些函数,manufacturer的值也是一样,没必要重新建。

使用原型改进

使用原理链,我们可以将上面说到的共有函数,属性放在一个共有对象里,然后用iPod.__proto__指向这个iPodCommon不就好了吗?所以现在代码可以改写成这样:

let box = []
let iPod

let iPodCommon = {
    // 制造商不会变
    manufacturer: 'Apple',
    // 播放音乐
    play: function () {},
    // 暂停
    pause: function () {},
    // 继续播放
    resume: function () {}
}

for (let i = 0; i < 30; i++) {
    iPod= {
        // 每次都改变 ID
        id: i,
    }

    iPod.__proto__ = iPodCommon

    box.push(iPod)
}

Manufacturer.deliver(box)

这样就好多了,省了很多空间。但是这个iPod对象的代码有点太分散了,跟for循环耦合在一起了。学习重构时听得最多的一句就是重复代码最好用函数包起来,所以我们可以试着传入要改变的属性(ID)用函数来返回iPod对象。,

函数返回对象

我们可以用一个函数返回iPod对象,这样就不用每次都在for循环里去定义对象了。

function iPod(id) {
    let tempObj = { }
    // 自有属性
    tempObj.id = id
    // 共有属性,函数
    tempObj.__proto__ = iPod.common

    return tempObj
}

iPod.common = {
    // 制造商不会变
    manufacturer: 'Apple',
    // 播放音乐
    play: function () {},
    // 暂停
    pause: function () {},
    // 继续播放
    resume: function () {}
}
// 保存为 iPod.js 文件

然后在创建时候引入这个文件,再去生成iPod。

let box = []

for (let i = 0; i < 30; i++) {
    box.push(iPod(i))
}

Manufacturer.deliver(box)

有没有感觉这样清爽了很多?我们将所有有关iPod的逻辑都放在一个文件里,这样就和主文件完全解耦了。

new

上面是很清爽,但是每次都要写创建一个临时对象好麻烦。这时候JS的new就上场了,它的作用如下:

  1. 帮你创建临时对象tempObj,函数里的this绑定为这个tempObj
  2. 统一共有属性所在对象的名字叫prototype而不是comon
  3. 帮你完成原型的绑定
  4. 帮你返回临时对象tempObj
    现在iPod.js文件可以写成这样
function iPod(id) {
    this.id = id
}

// 共有属性
iPod.prototype = {
    // 制造商不会变
    manufacturer: 'Apple',
    // 播放音乐
    play: function () {},
    // 暂停
    pause: function () {},
    // 继续播放
    resume: function () {}
}
// 保存为 iPod.js 文件

使用new再次生产iPod

let box = []

for (let i = 0; i < 30; i++) {
    box.push(new iPod(i))
}

Manufacturer.deliver(box)

这就是new的由来,不过是一种语法糖,和Java里面的new是完全不一样的东西,希望大家不要混为一谈。当然了,最后的这个iPod函数也就成了我们所说的构造函数

相关文章

网友评论

    本文标题:你真的了解JS里的new吗?

    本文链接:https://www.haomeiwen.com/subject/apazhqtx.html