给程序员看的Javascript攻略 - 对象(字典)

575 阅读4分钟

原文发表在: holmeshe.me , 本文是汉化重制版。

本系列在 Medium掘金上同步连载。

还记得早先用ajax胡乱做项目的时候踩过好多坑,然后对JS留下了“非常诡异”的印象。最近换了一个工作,工作语言就是JS。然后发现这个语言真不得了,前面后面都能干,基本成了全栈的同义词。所以刚好就趁这个机会系统学习一下这个语言。因为是给程序员看的,这个系列不会讲基本的“if-else”,循环,或者面向对象。相反,我会关注差异,希望能给您在Pull Request里走查代码式的学习体验!

JavaScript里,对象(object)和字典(dictionary, 或者有些语言叫map)的边界非常模糊。

打上码:

var hero = {
  name: 'iron man',
  birth: 1971,
};
alert(hero["name"]);// use map key to fetch property
alert(hero.name);
var herodict = {
  "name": 'iron man',
  "birth": 1971,
};
alert(herodict["name"]);
alert(herodict.name);// use property name to fetch a value

运行结果:

iron man
iron man
iron man
iron man

通过以上例子,我们可以知道对象(通过属性名来访问值)和字典(通过键来访问值)的行为是其实是完全一样的。因为这个东东官方就叫对象,接下来我只会用 . 来访问属性值。

上面的例子中,我们构建了一个“一次性”的对象。如果想定义一个可以复用的类型,我们需要借助构造函数class关键字(es6)。

Constructor

构造函数是一种函数的特殊用法。说到底,构造函数有两个作用:1)定义一个类型;2)构建一个对象:

打上码:

function StarkIndustries(name, birth) {
  this.name = name;
  this.birth = birth;
}

var iron1 = new StarkIndustries('iron01', 2017);
var iron2 = new StarkIndustries('iron02', 2017);

alert(iron1.name);
alert(iron2.name);

运行结果:

iron01
iron02

如码所述,函数的这个"构造技能"是被new关键字来激活的。然后我们就可以愉快的在JS里面用它来创建和初始化对象了。

再谈this

如果忘记加new了会再次掉进this的坑。

var name = "stark";
var birth = 1971;

function StarkIndustries(name, birth) {
  this.name = name;
  this.birth = birth;
}

var iron1 = StarkIndustries('iron01', 2017);
alert(iron1);
alert(name);
alert(birth);

运行结果:

undefined
iron01
2017

会造成两个问题:

1)this在函数StarkIndustries()会指向window,然后外面的全局变量(name ,birth)被这个错乱的构造函数篡改了。

2)StarkIndustries()会返回一个undefine。

所以这是一个非常危险的操作。

解决办法 1

一种解决办法是在构造函数里加上前置判断:

if (!(this instanceof StarkIndustries)) {
  warn("StarkIndustries is a constructor and should be called with `new`");
}

解决办法 2

或者用大名鼎鼎的strict关键字把指向window的this关键字设成undefined:

"use strict";

其实如果你想两个都用上也可以。或者呢,也可以用一个更为直观的办法,用更加正规的类(class)和构造器(constructor)。

Class

打上码:

class Hero {
  constructor(name, birth) {
    this.name = name;
    this.birth = birth;
  }
}

var iron1 = new Hero('iron01', 2017);
var iron2 = new Hero('iron02', 2017);

alert(iron1.name);
alert(iron2.name);

运行结果:

iron01
iron02

一切正常,这个时候如果拿掉new:

class Hero {
  constructor(name, birth) {
    this.name = name;// note, here we can still declare properties within constructor
    this.birth = birth;
  }
}

var iron1 = Hero('iron01', 2017);// error: Uncaught TypeError: Class constructor Hero cannot be invoked without 'new'
var iron2 = Hero('iron02', 2017);

alert(iron1.name);
alert(iron2.name);

这段代码在我们创建iron1的时候就直接报错了。所以总体来说class会比构造函数更加安全。

字典

在文章的开头我们列举了如何像访问字典键值对一样的查改对象属性。最后我们来看看对象的属性是如何做增删操作的。

打上码:

function StarkIndustries(name, birth) {
  this.name = name;
  this.birth = birth;
}

var iron1 = new StarkIndustries('iron01', 2017);

alert(iron1);
alert(iron1.name);
alert(iron1.birth);

iron1.age = 0;
alert(iron1.age);

delete iron1.age;
alert(iron1.age);

运行结果:

iron01
2017
0
undefined

除了以上讲到的方法,JavaScript还提供了一种更灵活的方式来定义和修改类,prototype。我会在下面一篇开始讨论。

好了,今天先写到这。如果您觉得这篇不错,请点赞或关注本专栏。也可以去Medium上随意啪啪啪我的其他文章。感谢阅读!👋