new
首先,new
是一个操做符,它能够用来建立两种对象的实例,一种是用户定义的对象类型,另外一种则是拥有构造函数的内建对象类型。javascript
建立用户定义的对象须要两个步骤:java
new
来建立对象实例。示例一:函数
var Person = function(personName) { this.name = personName; };
这是一个典型的经过编写函数来定义对象类型的范例,咱们能够这样来表述其行为:this
Person
函数定义了一种对象类型,其 类型名称 就叫 Person。
在使用Person
函数建立对象实例的时候能够传入变量personName
,该变量会成为对象实例的一个属性,这个属性的名字叫name
。
为对象实例定义name
属性的过程发生在Person
函数的函数体内;this
即指代将被建立的对象实例。prototype
值得初学者注意的是,在现实中你更多地会看到这样的代码:翻译
var Person = function(name) { this.name = name; };
有些人会搞不清楚究竟哪个 name
才是对象的属性,在这里详细解释以下:code
function(name)
里的 name
是待传入参数的名字,一般被称做:形式参数(Formal Parameter),或简称 形参 ——由于它只是表明参数的形式而并不是真正传入的参数(后者则被称做:实际参数(Actual Parameter),或简称 实参)。this.name
的 name
是对象的属性名字。= name
的 name
仍是形参,和 1. 里的 name
等价;这就是所谓的 参数传递,或传参。示例二:orm
var albert = new Person('Albert'); albert.name; // "Albert" albert['name']; // "Albert"
这是承接示例一,使用定义好的 Person
对象类型来实例化对象的范例,这个范例的表述相对容易一些:对象
定义一个变量
albert
,而后实例化一个新的Person
类型的对象,并将变量albert
指向这个新的对象。继承
若是你对 形参 和 实参 还不够清楚的话,看到这里就应该彻底明了了。保险起见再加以解释以下:
new Person('Albert')
中的 'Albert'
即对应着示例一中 function(name)
中的 name
,同时也是接下来一行中等号右边的 name
。'Albert'
就是 实际参数,name
就是 形式参数。示例二中还演示了两种对象属性的获取方法,分别为 object.property
和 object['property']
。前一种比较经常使用,不事后一种因为能够用字符串来访问对象属性,所以在某些场合下很是有用(好比说用字符串传递了对象的属性)。
回到 new
的话题。
当 new Person('Albert')
执行的时候,会有以下事情发生:
Person
并继承 Person.prototype
的全部属性。这就是 原型继承;Person
被调用并传入指定的参数(示例二中的 'Albert'
),而后 this
被绑定给新建立的对象。另外,若构造函数不须要参数,则 new Person
等价于 new Person()
;new
表达式的结果;反之,若构造函数内显式定义了返回值,则该返回值为整个 new
表达式的结果。关于第三点,举例示之:
示例三:
var Person = function(name) { return { name: 'Mr. ' + name } }; var albert = new Person('Albert'); albert.name; // "Mr. Albert"
var Person = function(name) { return { rawName: name, getName: function(gender) { if (gender === 'male') { return 'Mr. ' + name; } else { return 'Mrs. ' + name; } } } }; var albert = new Person('Albert'); albert.getName('male'); // "Mr. Albert" albert.getName('female'); // "Mrs. Albert"
var Person = function(name, gender) { return { rawName: name, name: (function() { if (gender === 'male') { return 'Mr. ' + name; } else { return 'Mrs. ' + name; } }()) } }; var albert = new Person('Albert', 'male'); albert.rawName; // "Albert" albert.name; // "Mr. Albert" var annie = new Person('Annie', 'female'); annie.rawName; // "Annie" annie.name; // "Mrs. Annie"
示例三演示了三种看起来类似但实际上具备显著差别的对象类型定义和对象实例化的例子:
第一种:在 new Person('Albert')
时返回自定义的对象,而不是默认由 new
建立的新对象。在这个自定义对象里,没有简单地把参数 name
赋给属性 this.name
,而是作了进一步的修改。这种修改很显然是很是简单但却不够灵活,为了改进它,看下面两个例子:
第二种:一样返回自定义对象,这一次定义了两个属性,一个是 rawName
,保存实例化时传递的参数;另外一个是 getName
,它是一个函数声明,所以不能直接用 albert.getName
或 albert['getName']
来访问(只会返回函数声明自己,但不会有返回值)。不过你能够用albert.getNam('male')
或 albert['getName']('male')
的方式来执行这个函数并求得结果,这就是所谓的 方法。
若是不想用方法调用,但仍然但愿像方法声明体内那样作一些逻辑判断是否能够呢?能够,继续看第三种:
第三种:这一次 name
属性又能够像之前那样直接访问了,缘由是 name
指向的函数声明使用了 IIFE(Immediately Invoked Function Expression) 技巧,该技巧使得函数声明直接转变成了函数表达式(并即刻执行)。咱们知道,函数表达式是可以直接返回值的,而函数声明则须要执行(调用)才能返回值,因而 name
属性得到了返回值,就能够像原来那样直接访问了。
这种属性定义方式有时被称之为 计算后属性(Computed Property),顾名思义:不是直接返回实例化时传递的值,而是对值进行了必定的处理(计算)以后才返回。
属性与方法:不少人都觉得对象有 属性 和 方法,其中属性是能够直接访问到值的,而方法是须要执行才能得到值的。但有的时候也会听到“方法也是属性”这样的说法,这是为何呢?
其实缘由在于对术语的翻译不够准确。英文里的property
和attribute
都被咱们翻译为属性,然而在谈及对象时这二者是不一样的。在一个对象里,attribute
和method
被统称为property
,直接保存值的property
称之为attribute
,保存函数声明能够用来执行的property
才是method
。在用中文描述时很容易把两种“属性”搞混,须要注意分辨清楚。
补充说明:本文发表出去以后,有人感谢我帮他分清了 属性 和 方法 在一些书中的歧义性,也有人拿着别的书来向我表示疑惑。以再版的 Object Oriented in JavaScript 为例,该书中在讲解面向对象基础的时候,明确地指出:保存数据的属性叫作 Property,保存行为的属性叫作 Method,根本就不使用 Attribute。这却是也简单明了,这样一来就不存在 Method 也是 Property 一说了。
老实说,对此我也不知该如何回应。不一样的书用不一样的术语,不一样的做者也有不一样的理解,我没有“统一业界术语”的能量,因此也只能把它们一一列举出来。对于初学者若形成理解上的误差我表示道歉,总而言之你要记住:一个对象有两类东西:一类记录数据,另外一类记录方法(方法老是作一件什么事,其中也包括返回新的数据),至于这两类在不一样的情境中叫法不一,也就要靠你本身去分辨了。