1 对象与构造函数
JavaScript对象是基于构造函数(constructor)和原型链(prototype)的,在JavaScript这门语言中并没有“类”(class)这个概念。
注:在ES6 引入了
class
语法。
那么什么是对象呢?简单地说,对象就是现实世界中的实物的抽象。
那对象又如何被创建呢?首先我们将现实世界中的实物抽象为模板——构造函数,具体来说,就是用属性来表示实物的某些特征,用方法来表示实物的某些行为,然后利用这个模板就可以创建实例对象了。
下面来举个实例,例如:我们将一种交通工具抽象为一个构造函数Vehicle
,内部使用的关键字this
代表所要生成的对象实例。
注:这里为了和普通函数有所区分,故将首字母大写,也推荐大家这样去书写。
var Vehicle = function () {
//属性
this.brand = "沃尔沃"
this.price = 500000;
//方法
this.run = function (){
console.log("我是在公路上跑的小轿车");
}
}
具体到如何创建对象,请继续往下看。
2 对象的创建方法
2.1 通过new命令创建对象
new
命令可以执行构造函数,返回一个实例对象。
-
构造函数可以不带参数,示例如下:
var Vehicle = function () { this.brand = "沃尔沃" this.price = 500000; this.run = function (){ console.log("我是在公路上跑的小轿车"); } } var v = new Vehicle(); v.brand // 沃尔沃 v.price // 500000 v.run() // 我是在公路上跑的小轿车
-
构造函数也可以带参数,示例如下:
var Vehicle = function (brand, price) { this.brand = brand; this.price = price; } var v = new Vehicle("奔驰", 1000000); v.brand //奔驰 v.price //1000000
-
当然我们也可以像调用普通函数一样创建对象:这里其实是改写了构造函数,在内部做判断,若像普通函数进行调用,则在构造函数内部创建一个对象(这不就是单例模式中的懒汉式创建方法嘛😂,有了学习Java的感觉了)。
function Vehicle(brand, price) { if(!(this instanceof Vehicle)) { return new Vehicle(brand, price); } this.brand = brand; this.price = price; } Vehicle("宝马",800000).price (new Vehicle("宝马",800000)).price
我们在浏览器控制台测试一下,结果如下:这样两种创建方式效果是一致的。
-
上述函数要是不在函数中加
if
代码块,直接调用会返回undefined
,并没有给出提示告知我们忘记使用new
命令来创建对象了,相反,忘记加new
命令反而会将其作为普通函数进行调用了,由于没有返回值,因此结果为undefined
,直至将其当成对象,访问其属性时才会报错。
为了避免在创建对象时忘记写new
关键字,我们可以使用严格模式:如下所示,在构造函数的开始加上'use strict';
var Vehicle = function (brand, price) { 'use strict'; this.brand = brand; this.price = price; }
如下图所示:实际测试在严格模式下,不带
new
关键字会在创建时就出错。
2.2 通过Object.create()方法创建对象
我们也可以使用一个现有的对象作为模板,生成一个新的实例对象,这就要借助Object.create()
方法了。
如下例子所示:我们将p1
对象作为一个模板创建了p2
对象,并且p2
继承了p1
的属性和方法。
var p1={
name:'张三',
age:22,
greeting: function(){
console.info("Hi, I\'m " + this.name + ".");
}
}
var p2=Object.create(p1);
p2.name //张三
p2.greeting() //Hi, I'm 张三.
3 new命令的内部原理
其实在使用new
命令创建对象之前就需要做一些前期准备,具体操作如下:
- 首先创建一个空对象;
- 将这个空对象的原型,指向构造函数的
prototype
属性; - 而后将这个空对象赋值给函数内部的
this
关键字(this
指向的是新生成的空对象); - 此时才开始执行构造函数内部的代码,最后对象就被创建出来了。
这么看来,构造函数果然人如其名,通过操作一个空对象(即this
),将其构造成需要的样子(在构造函数中对this
赋值)。
于是乎可以这么说new
命令总是会返回一个对象,我们拿一个普通函数使用new命令,此时会返回一个空对象,测试如下:
上面的例子中忽略了return
后面的字符串,便返回了一个对象,由于函数中并没有针对this
即空对象的赋值操作,因此为一个空对象。
4 new.target
函数内部可以使用new.target
属性,它有两种值:
- 若当前函数使用new命令调用,则
new.target
指向的为当前函数; - 若像普通函数进行调用,则
new.target
的值为undefined
。
测试代码如下:
function f(){
console.log(new.target === f);
}
f()
new f()
测试结果如下:
使用这个属性可以用来判断函数被调用时是否使用了new
命令。
function f(){
if(!new.target){
console.log('您直接调用了函数');
}else{
console.log('您使用了new命令调用了函数');
}
}
测试结果如下:new.target
为undefined
时对应的布尔值为false
,当为对象时对应的布尔值则为true
(关于类型转换请移步至JavaScript数据类型转换-学习笔记)。