说明:
笔者并不是对这本著作流水线的进行笔记的摘抄,而是通读完一部分,并且对所有的例子进行测试后自己重新写的,下面所有的例子也都是笔者自己自己写出并且进行过测试的。书中一些内容与实际测试并不一致,笔者以实际测试结果为准,并进行了更正(所有测试结果均以截图的方式呈现)。
这一部分非常的有趣,可能会革新我们对JavaScript的理解,我们一起来学习一下(下面的标题也都是笔者自拟的)。
一、JavaScript对象概述
JavaScript是一门非常独特的语言,它先预包装了若干原生对象,然后哦使用这些原生对象构造函数,以此使得对象的创建变得简单。例如我们构建一个数组对象,可以这样;
arr = new Array(1,2,3,4,5);
这里的Array就是JS的原生对象,当然我们也可以用一种简化的方法来创建数组:
arr = [1,2,3,4,5]
大多数情况下,省略new
操作符与使用new
的效果是相同的,但是对于Number(),String(),Boolean()是不同的,我们将在下面进行介绍。
上面创建arr数组对象的过程叫做实例化。
当然我们也可以自定义构造函数,并且可以创建实例化对象,同时也为实例创建了原型继承。
//自定义构造函数
var Person = function(name,age,interest){
this.name = name;
this.age = age;
this.instrest = function(){
return this.interest;
}
}
//实例化构造函数
var person = new Person('fltenwall',22,'coding');
在JS中对象只是属性的容器,对象在JS中是作为表达式的构建块而存在的。JS中的方法其实是包含Function()对象的属性,这样做的目的为了对函数内部对象进行操作(就像上面构造函数的例子,JS中是使用对象来表示值的)。
JS中构造函数的作用是创建多个共享特定特性(属性)和行为(方法)的对象,这些对象(构造函数的实例)具有默认的属性与方法。
var arr1 = new String('coding');
var arr2 = new String('javascript');
console.log(arr1.length);
console.log(arr2.length);
我们可以在控制台得出输出:6,10。length是构造函数(原生对象)Array默认的属性,创建实例时构造函数内部的this值设置为了正在构建的新对象,因此上面创建的两个实例分别继承了Array构造函数默认的对象和方法。
二、原生对象构造函数非原生对象构造函数
1、原生对象构造函数
原生对象构造函数也叫内置对象构造函数,是JS语言预先定义好的。
JS中共有9个原生对象构造函数,分别是:
Number(),
String(),
Boolean(),
Object(),
Array()
Function()
Date()
RegExp()
Error()
需要注意的是:Number(),String(),Boolean()这三个原生对象构造函数既可以直接调用返回复杂对象,也可以简单的表示原始值,此时将返回一个原生值,而非复杂对象。比如下面的例子(与上面的例子相同):
var num = 10;//此时是返回一个原始值
var num2 = new Number('10');//此时是返回一个复杂对象
console.log(num === num2)//返回false
console.log(num,num2)//前一个返回数值10,后面一个返回Number()对象
我们来看一下控制台的输出:
再来观察一下此时num和num2的类型:
console.log(typeof num);
console.log(typeof num2);
看一下此时控制台的输出:
可以看到此时 num2是对象类型。
需要注意的是,我们经常使用的一个对象Math是一个静态对象,它只是用来储存数学函数的容器,因此使用的时候不需要使用关键字new
进行实例化(实际上这样做会报出一个错误)。
a = Math.random();
console.log(a);
b = new Math();
console.log(b);
我们看一下控制台的输出:
报错提示Math并不是一个构造函数。
2、非原生对象构造函数
非原生对象构造函数的创建我们已经在上面演示过,这里不再重复。需要注意的是:
(1)与原生对象构造函数一样,使用new
关键字进行实例化创建对象的时候,构造函数内部的this
指向创建的新对象。而不使用new
时,this
将引用包含该函数的“父”对象。
(2)当我们创建于new一起使用的自定义构造函数时,建议构造函数的第一个字母大写。
(3)可以放弃使用new关键字和构造函数的概念,方法是使函数显式返回Object()对象的函数
`var func= function(){return {prop:val}}`
这样做是因为在JS中所有对象都继承自Object构造函数,就连原生构造函数也是如此,我们可以用instanceof
属性进行验证:
console.log(String instanceof Object);
输出结果为:true
,说明原生构造函数也是继承自Object构造函数的,而Object()构造函数是一个生成空的通用对象的容器,该容器叫Object对象。
三、真实值赋值与引用赋值
对于原始值(String,Number,Boolean)来说,复制是真实值的复制,而复杂对象的复制是引用(地址)复制,复制的是对象的地址或引用。
var num4 = 10;
var num5 = num4;
num5 = 20;
console.log(num4,num5);//10,20
可以看到,当num5的值发生改变时,num4的值并未改变,这是因为num5“复制” 了num4中储存的值,它们分别指向两个内存地址。
var objc = new function(){
this.name = 'fltenwall';
}
objc2 = objc;
objc2.name = 'cinderella';
console.log(objc.name);
看下此时控制台的输出:
发现objc2
发生改变的同时,objc
的值也发生了改变。这是因为对象是按照引用赋值的,它们指向同一个内存地址,当其中一个发生改变时,另外一个也随之改变。那么如何真正复制一个对象呢?这需要从原来的对象中提取值,然后将提取的值注入新对象,这样就是创建了两个属性完全相同,但各自拥有内存地址的独立对象。
var objc = new function(){
this.name = 'fltenwall';
}
var objc3 = new function(){
this.name = '';
};
objc3.name = objc.name;
console.log(objc3.name);
console.log(objc === objc3);
此时两个对象所具有的属性是相同的,此时输出为:
需要注意的是:即使String(),Number(),Boolean()使用new
创建时,它们仍然是按值进行存储和复制。
var number3 = new Number('10');
var number4 = number3;
number4 = 20;
console.log(number3,number4);
发现当number4
改变时,number3
并未改变。
四、typeof
使用typeof
可以测试对象的类型
var str2 = new String();
console.log(typeof str2);
var number5 = new Number();
console.log(typeof number5);
var bool = new Boolean();
console.log(typeof bool);
var function2 = new Function();
console.log(typeof function2);
var regexp = new RegExp();
console.log(typeof regexp);
var err = new Error();
console.log(typeof err);
发现Function
构造函数创建的实例对象类型为function
,其余均为Object
*(而在中译版书中,RegExp构造函数创造的实例函数也为function
类型,可能是印刷错误)。
而undefined,‘string’,10,true,false等原始值都不是对象:null是对象(中译版书中null不是对象,但测试结果是对象)。
var test3 = null;
var test4 = undefined;
var test5 = Number('10');
var test6 = 10;
var test7 = String('10');
var test8 = '10'
var test9 = true;
var test10 = Boolean('false');
console.log(typeof test3);
console.log(typeof test4);
console.log(typeof test5);
console.log(typeof test6);
console.log(typeof test7);
console.log(typeof test8);
console.log(typeof test9);
console.log(typeof test10);
控制台的输出为:
五、constructor属性
构造函数实例都拥有指向其构造函数的constructor
属性
下面用一个实例,综合前面关于原始值赋值的问题:
var num8 = Number('10');
var num9 = num8;
num9 = 20;
console.log(num8 === num9);//false
console.log(num8,num9);//10,20
console.log(num8.constructor);//Number()
console.log(num8.constructor === Number);//true
可以看到通过constructor
属性,找到了num8的构造函数。
var test5 = Number('10');
var test6 = 10;
var test7 = String('10');
var test8 = '10'
var test9 = true;
var test10 = Boolean('false');
console.log(test5.constructor);
console.log(test6.constructor);
console.log(test7.constructor);
console.log(test8.constructor);
console.log(test9.constructor);
console.log(test10.constructor);
而null,undefined
没有构造函数
var test3 = null;
var test4 = undefined;
console.log(test3.constructor);
console.log(test4.constructor);
六、instanceof操作符
instanceof
操作符用于验证对象是否是特定函数的实例:
var myFunction = function myFun(){return 'yes'};
var instanceofmyFunction = new myFunction();
console.log(instanceofmyFunction.constructor);//myFun(){return 'yes'}
console.log(instanceofmyFunction.constructor === myFunction);//true
console.log(instanceofmyFunction instanceof myFunction)
console.log(instanceofmyFunction instanceof Object);//true
var number = 123;
console.log(number instanceof Object);//false
var number2 = new Number('123');
console.log(number2 instanceof Object);//true
console.log(myFunction instanceof Object);//true
console.log(Number instanceof Object);//true
var myString = new String();
myString.test = 'test';
console.log(myString.test);//test
myString.func = function(){return 'coding'};
console.log(myString.func());//coding
而任何时候判断一个对象是不是Object
实例时,都将返回true
:
var number5 = new Number();
var string3 = new String();
var bool = new Boolean();
var function2 = new Function();
var array = new Array();
var object = new Object();
var date = new Date();
var regexp2 = new RegExp();
var err = new Error();
console.log(number5 instanceof Object);
console.log(string3 instanceof Object);
console.log(number5 instanceof Object);
console.log(function2 instanceof Object);
console.log(array instanceof Object);
console.log(object instanceof Object);
console.log(date instanceof Object);
console.log(regexp2 instanceof Object);
console.log(err instanceof Object);
输出结果为:
而对null,undefined,‘string’,10,true,false等原始值进行测试时结果都为false
var test3 = null;
var test4 = undefined;
var test5 = Number('10');
var test6 = 10;
var test7 = String('10');
var test8 = '10'
var test9 = true;
var test10 = Boolean('false');
console.log(test3 instanceof Object);
console.log(test4 instanceof Object);
console.log(test5 instanceof Object);
console.log(test6 instanceof Object);
console.log(test7 instanceof Object);
console.log(test8 instanceof Object);
console.log(test9 instanceof Object);
console.log(test10 instanceof Object);
输出结果为:
七、神奇的NULL
null
是一个很特殊的值,我们对null
进行单独测试:
var null2 = null;
var test11 = null2;
var test11 = true;
console.log(null2);//输出null,说明null是原始值
console.log(typeof null2);//输出为Object,说明null是对象
console.log(null2 instanceof Object);//输出为false,说明null不是继承自Object
console.log(null2.constructor)//显示null没有构造函数
我们可以看到null
在JavaScript当中是一个非常神奇的存在。
后面将持续更新,一起探索JavaScript的本质与奇妙。