《JavaScript启示录》笔记——JavaScript对象的神奇

说明:

笔者并不是对这本著作流水线的进行笔记的摘抄,而是通读完一部分,并且对所有的例子进行测试后自己重新写的,下面所有的例子也都是笔者自己自己写出并且进行过测试的。书中一些内容与实际测试并不一致,笔者以实际测试结果为准,并进行了更正(所有测试结果均以截图的方式呈现)。

这一部分非常的有趣,可能会革新我们对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的本质与奇妙。

猜你喜欢

转载自blog.csdn.net/qq_32925031/article/details/88740964