设计模式(三):字面量和构造函数

字面量和构造函数

前置可能需要了解何为值类型、引用类型、作用域等概念

基础类型

基础类型是一种既非对象也无方法的数据。

  • string
  • number
  • boolean
  • null
  • undefined
  • symbol(ECMAScript 2015新增)

除了 null 和 undefined之外,所有基本类型都有其对应的包装对象

多数情况下,基本类型直接代表了最底层的语言实现。所有基本类型的值都是不可改变的。

var int = 0
var obj = {}
function add(i, o) {
  i += 1
  o.a = 1
}
add(int, obj)
console.log(int) // 0
console.log(o) // {a: 1}

代码运行的过程:

  1. JavaScript会检查标识符int, obj的值。
  2. 通过add的调用,JavaScript将其作为参数传递给函数的形参
  3. 在执行函数体内语句之前,JavaScript会将传递进来的基本类型的参数复制一份,创建一个本地副本,而引用类型的obj传递的是引用地址。
  4. 执行函数体,对基础类型传参操作,操作的都是它的副本,外部值不受影响。而对引用类型操作,操作的都是它最终的真实数据,外部值也发生了改变。

引用类型的传参如果赋值了全新的值,外部不会受其影响。

字面量

字面量的写法简化编写的代码量,避免了一些隐藏的问题。

对象字面量

var o = new Object({a: 1}) // var o = {a: 1}

字面量没有作用域解析,而构造函数有。详细请看后半部分的自定义构造函数

数组字面量

var arr = new Array('a', 'b') // var arr = ['a', 'b']
var arr2 = new Array(2) // [empty × 2]

但给数组构造器传入数值时,它代表的是创建数组的长度。

避免使用 typeof [] 来判断是否为数组类型,改用ES5提供的Array.isArray()

typeof {} // object
typeof [] // object
Array.isArray({}) // false
Array.isArray([]) // true

如果你的环境还不支持ES5语法,可使用 Object.prototype.toString.call([]) === ‘[object Array]’

正则表达式字面量

var reg = new RegExp("name", "g") //  /name/g

自定义构造函数

看一段事例,了解实例化的过程:

var Person = function(name) {
  this.name = name
  this.sayName = function() {
    console.log(this.name)
  }
}
var me = new Person('test')
me.sayName() // test
  • new Person时,创建了一个空对象并将this指向了该对象
  • 属性和方法都被调价到了this引用的该对象
  • 最后被隐式的返回了this,显式的返回引用类型将会覆盖它。(基础类型会被忽略)

上面的代码段,sayName方法可以说是所有实例的公共方法,为了避免每次实例化新建对象造成不必要的开销,可以将它挂载在Person的原型链上。

Person.prototype.sayName = function() {
   console.log(this.name)
}

当忘了使用new关键字来实例化时,内部的this将会指向当前调用的上下文的对象,默认为全局对象。使用构造函数实例化对象时总是使用new,也可通过下面方式避免遗忘。

var Person = function(name) {
  if(!(this instanceof Person)) { // 非Person的实例,便重新实例化
    return new Person(name)
  }
  this.name = name
}
Person.prototype.sayName = function() {
  console.log(this.name)
}
Person('我').sayName() // 我

参考资料