JavaScript笔记 Object对象

JavaScript 对象

对象只是一种特殊的数据。对象拥有属性和方法。
JavaScript 中的所有事物都是对象:字符串、数值、数组、函数…

此外,JavaScript 允许自定义对象。

所有事物都是对象

JavaScript 提供多个内建对象,比如 String、Date、Array 等等。 对象只是带有属性和方法的特殊数据类型。

  • 布尔型可以是一个对象。
  • 数字型可以是一个对象。
  • 字符串也可以是一个对象
  • 日期是一个对象
  • 数学和正则表达式也是对象
  • 数组是一个对象
  • 甚至函数也可以是对象

访问对象的属性

属性是与对象相关的值。

访问对象属性的语法是:

objectName.propertyName

这个例子使用了 String 对象的 length 属性来获得字符串的长度:

var message="Hello World!";
var x=message.length;

在以上代码执行后,x 的值将是:

12

访问对象的方法
方法是能够在对象上执行的动作。

您可以通过以下语法来调用方法:

objectName.methodName()

这个例子使用了 String 对象的 toUpperCase() 方法来将文本转换为大写:

var message="Hello world!";
var x=message.toUpperCase();

在以上代码执行后,x 的值将是:

HELLO WORLD!

创建 JavaScript 对象

通过 JavaScript,我们能够定义并创建自己的对象。

创建新对象有两种不同的方法:

  • 使用 Object 定义并创建对象的实例。
  • 使用函数来定义对象,然后创建新的对象实例。
    使用 Object
    在 JavaScript 中,几乎所有的对象都是 Object 类型的实例,它们都会从 Object.prototype 继承属性和方法。

Object 构造函数创建一个对象包装器。

Object 构造函数,会根据给定的参数创建对象,具体有以下情况:

  • 如果给定值是 null 或 undefined,将会创建并返回一个空对象。
  • 如果传进去的是一个基本类型的值,则会构造其包装类型的对象。
  • 如果传进去的是引用类型的值,仍然会返回这个值,经他们复制的变量保有和源对象相同的引用地址。
  • 当以非构造函数形式被调用时,Object 的行为等同于 new Object()。

语法格式:

// 以构造函数形式来调用
new Object([value])

vaule 可以是任何值。

以下实例使用 Object 生成布尔对象:

// 等价于 o = new Boolean(true);
var o = new Object(true);

JavaScript对象创建

字面量的创建方式

示例

	var obj = {
    
    
		name : "林江涛",
		age : 18,
		gender: "男"
	};
	
	console.log(obj);
	console.log(obj.name);
	console.log(typeof obj);

效果
在这里插入图片描述

{}就是对象的界定符,就是对象的字面量。对象有属性,所谓的属性就是这个对象的特点、特性,name、age、gender都是这个obj对象的属性(preperty)。
什么是对象?对象就是属性的无序集合。
我们可以用.点语法、方括号法来获得一个对象的属性。那么你会发现,和数组有点相似,只不过数组的下标只能是数字0、1、2……,而我们的对象,可以用任何的词儿来当做属性名。

公式:

{
    
    
		k : v,
		k : v,
		k : v,
		k : v
	}

JSON和对象字面量的区别:
之前学习过JSON,JSON要求所有的k必须加引号,而对象字面量不需要加引号,当然加引号也不错。
JSON = JavaScript Object Notation,JS对象表示法。JSON是一个用于交换的格式,所以JSON不仅仅JavaScript用,后台语言比如PHP、Java、ASP等等都要识别JSON,为了最大的兼容,k必须加引号。也就是说,JSON里面的k加引号,不是因为JS,而是因为后台的那些语言。
JSON要比对象字面量,要严格,严格在哪儿呢?就是所有的k,必须加引号。
JSON:

{
    
    
		"k" : v,
		"k" : v,
		"k" : v,
		"k" : v
	}

但是,下面的特殊情况,这个k必须加引号:

  • k是特殊字符
  • k是数字
  • k是有空格
  • k是关键字、保留字

先说一下,上面这些情况,也同时不能使用点语法来访问属性了,必须使用方括号:

	var obj = {
    
    
		name : "树懒"
	} 
	console.log(obj["name"]);

特殊形式的k,必须要加上引号,检索属性的时候,必须用方括号:

	var obj = {
    
    
		"24&*$&#@@)@!" : "哈哈",
		"all name" : "六六六",
		"++++%%%%" : "嘻嘻",
		"var" : "么么哒",
		"function" : "嘻嘻"
	} 
	
	console.log(obj["24&*$&#@@)@!"]);
	console.log(obj["all name"]);
	console.log(obj["++++%%%%"]);
	console.log(obj["var"]);
	console.log(obj["function"]);

你会发现,JS会一个对象的属性名,没有特殊的规定。这是因为属性名不是标识符,没有那些规定。

对象的属性的访问,点语法是有局限的,它不能访问上面的特殊的那些情况。也不能访问以变量保存的k:

	var obj = {
    
    
		name : "林江涛",
		age : 18,
		gender : "男",
		"study score" : 100
	}
	
	//console.log(obj."study score");//错误的
	console.log(obj["study score"]);	//正确的
	console.log(obj["a" + "ge"]);		//正确的
	var a = "gender";
	console.log(obj[a]);			//正确的

效果

在这里插入图片描述

new Object创建

var obj = new Object();	//这是一个空对象,里面没有任何属性
obj.name = "林江涛";
obj.age = 18;
obj.gender = "男";

console.log(obj);	
console.log(obj.age);	
console.log(typeof obj);	

new是一个运算符,你没有看错,和±*/一样是一个运算符。表示新创建一个对象。一会儿我们学习构造函数,实际上你将了解到new是一个函数调用的方式。Object()大写字母O,这是一个系统内置的构造函数,什么是构造函数,我稍后会在下面写到。
下面就可以用obj.k = v ;来追加属性了:

obj.name = "林江涛";

这是一条语句,如同:

oDiv.className = "current";

事实上,工程师更喜欢用字面量的方式来创建对象。因为更直观:
字面量方式:

	var obj = {
    
    
		name : "林江涛",
		age : 18,
		gender : "男"
	};

构造函数方式:

	var obj = new Object();
	obj.name = "林江涛";
	obj.age = 18;
	obj.gender = "男";

上面两种方式创建出来的对象,是相同的。字面量的方式直观、简单、并且有“封装”的感觉。所以我鼓励大家用字面量来创建对象。
但是,不要杂糅:

	var obj = {
    
    };   //的确能创建一个空对象
	obj.name = "林江涛";   //追加属性
	obj.age = 18;        //追加属性
	obj.gender = "男";      //追加属性

这样写虽然不会报错,但是,别这样写不易于别人理解
在这里插入图片描述

对象的属性值

对象属性值,可以是任何东西。比如数字、字符串、布尔值、正则表达式、对象、数组、函数……

	var kaola = {
    
    
		name : "林江涛",
		age : 18,
		peiou : {
    
    
			name : "JiuMei",
			age : 19
		}
	}
	
	console.log(kaola.peiou.age);
	
	var obj = {
    
    
		a : 1,
		b : "哈哈",
		c : true,
		d : /[A-Z]/g,
		e : function(){
    
    
			alert(1+2);
		},
		f : {
    
    
			p : 1
		}
	}

特别的,当对象的属性的值是一个函数的时候,我们称这个函数是对象的方法。

对象的方法

当一个对象的属性的值,是一个函数,那么这个函数我们就称为对象的“方法”(method)。
方法就是一个对象能够做的事情,一般来说,就是一个动词。比如小明打招呼、长大方法。

	var lin= {
    
    
		name : "林江涛",
		age : 18,
		gender : "男",
		sayHello : function(){
    
    
			alert("你好,我是" + this.name);
			alert("今年" + this.age + "岁了");
			alert("我是可爱的小" + this.gender + "生");
		}
	}
	
	lin.sayHello();

比如上面的案例,sayHello就是一个属性,只不过它的值是一个函数,所以我们就可以说lin这个对象,有sayHello方法。
一个对象,方法函数里面的this指的是这个对象。

那我们复习一下现在,我们调用函数的方式有哪些?这些调用函数的方式,里面的this又是谁?

  • 直接用()运算符来调用函数,那么函数里面的this指的是window对象
  • 函数如果绑定给了某个HTML元素的事件上,那么函数里面的this就是这个HTML对象
  • 用定时器调用函数,函数内部的this就是window对象
  • 用对象打点(方法)来调用函数,函数里面的this指的是这个对象
  • 用apply、call,可以人工设置this是谁了,百变。

说白了,我们学习“方法”,无非就是学习了一种函数的调用方式。这个函数里面的this指的是这个对象。
函数里面的this到底是谁,在函数定义的时候并不知道,要看函数如何被调用。

对象的方法的哲学,就是操作自己的属性。如果一个对象的方法,不操作自己的属性,那干嘛还要是方法呢?
zhangda方法,就是让自己的age++:

	var lin= {
    
    
		name : "林江涛",
		age : 18,
		gender : "男",
		sayHello : function(){
    
    
			alert("你好,我是" + this.name);
			alert("今年" + this.age + "岁了");
			alert("我是可爱的小" + this.gender + "生");
		},
		zhangda : function(){
    
    
			this.age++;
		}
	}

构造函数

JavaScript规定,一个函数可以用new关键字来调用。那么此时将按顺序发生四件事情:

  1. 隐秘的创建一个新的空对象
  2. 将这个函数里面的this绑定到刚才创建隐秘新对象上
  3. 执行函数体里面的语句
  4. 返回这个新的对象
	function People(){
    
    
		this.name = "林江涛";
		this.age = 18;
		this.gender = "男";
	}
	var lin= new People();
	
	console.log(lin);
	console.log(lin.age);
	console.log(typeof lin);

效果
在这里插入图片描述

上面的函数的机理解析:

	var lin= new People(); //此时遇见了new操作符,计算机将做四件事
	function People(){
    
     //1)隐式创建一个空对象
		this.name = "林江涛"; //2)函数里面的this指向这个创建的空对象
		this.age = 18; //3)顺序执行函数体里面的语句
		this.gender = "男";//4)执行完毕之后,返回这个对象
	}
	
	
	console.log(lin);
	console.log(lin.age);
	console.log(typeof lin);

函数使用new关键字来调用。
此时很有意思,函数不仅仅能够执行,还能返回出来一个对象。也就是说,对象是函数“生”出来的,对象是函数“new”出来的。
我们称呼这个函数,叫做构造函数,一般的,构造函数用大写字母开头。也叫作People“类”。
我们称呼lin这个对象是People类的实例。


真实社会,真实自然界,万物分为各种各样的“种类”,比如有“人类”、“猪类”、“鸟类”、“计算机类”。为什么能分出类别呢?哲学上讲,是因为他们有不同的属性群。换句话说,有相同属性群的东西,就可以称为一“类”。

所以我们的构造函数,也可以看成类的定义:

	//类,People类
	function People(name,age,gender){
    
    
		this.name = name;
		this.age = age;
		this.gender = gender;
	}
	
	//new关键字造出来的xiaoming、xiaohong,我们称为People类的实例。
	var lin= new People("林江涛",18,"男");
	var jiu= new People("JiuMei",17,"女");
	
	console.log(lin);
	console.log(jiu);

People这个函数一会儿将用new关键字来调用,所以称为构造函数。

构造函数里面的语句将执行,并且将返回一个对象。所以new多少次,里面的语句就会执行多少次。宏观的看,返回的对象,就都有name属性、age属性、gender属性了。我们说,这些返回的对象都有相同的属性群了,所以可以看做是一类东西。那么People这个构造函数,也可以看成类的定义。

但是JavaScript中,没有类的概念。是通过构造函数的4步走机制来创建类似的对象,可以看为类。JS这个语言是“基于对象”(base Object)的语言,不能叫做“面向对象”(orinted object)的语言。
注意,我们学习Java、C++、C#语言的惯例,构造函数以大写字母开头。

	function People(){
    
    
	}

这是一个People类,这个函数一会儿要用new来调用。能返回对象。
类就是蓝图,上帝要根据这个蓝图造小人儿。造出的小人,就是People类的实例。

构造函数中,肯定会出现this语句,如果没有this语句,那就相当于不能给创建出来的空对象绑定属性。
构造函数,在JS中,就是一个普通的函数,JS没有对里面要书写什么进行任何规定。只不过我们工程师习惯的,先用this.*** = ***来罗列所有属性,然后罗列所有的方法而已。你一定要深刻理解:
new一个函数的时候,函数里面的语句会执行
总结:

  1. 当一个函数用()调用的时候,this就是window
  2. 当一个函数用对象方法调用的时候,this就是这个对象
  3. 当一个函数绑定给一个HTML元素事件的时候,this就是这个HTML元素
  4. 当一个函数用定时器调用的时候,this就是window
  5. 当一个函数用apply、call调用的时候,this就是你指定这个东西
  6. 当一个函数用new调用的时候,this就是隐秘创建的空对象,函数里面的语句将被执行,并且返回新对象

宏观的看,new出来的东西都有相同的属性群、方法群。此时我们就发现了:哇塞这个构造函数像模板一样,可以非常快速的制作类似的实例。这个构造函数可以称为类,它new出来的东西叫做类的实例。

原型prototype

原型的定义

我们先来看一个事儿:

示例

	function fun(){
    
    
		alert("你好");
	}
	console.log(fun.prototype);
	console.log(typeof fun.prototype);

效果
在这里插入图片描述

在JavaScript中,任何一个函数,都有一个prototype属性,指向一个对象。我们输出了一个函数的prototype属性,你会发现是一个空对象。输出这个prototype的类型,发现是object类型。
prototype就是英语“原型”的意思。每个函数都有原型,原型是一个对象。
一个函数的原型,对于普通函数来说,没用。但是如果函数是一个构造函数,那么函数的原型,用处极大

	//构造函数,构造函数里面没有任何语句,也就是说,这个构造函数在执行的时候,不会给创建出来的对象添加任何属性。
	function People(){
    
    
	this.name="JiuMei"
	}
	//构造函数的原型,我们更改了构造函数的原型,为一个新的对象:
	People.prototype = {
    
    
		name : "林江涛",
		gender : "男",
		age : 18
	}
	
	//当一个对象被new出来的时候,不仅仅执行了构造函数里面的语句,也会把这个函数的__proto__指向构造函数的prototype。
	var lin= new People();
	
	console.log(lin.__proto__);
	console.log(lin.__proto__ == People.prototype);
	
	//当我们试图访问name、gender、age属性的时候,身上没有。那么就去查找原型,原型身上有,就当做了自己的属性返回了。如果身上有原型上也有,就只使用身上有的
	console.log(lin.name);
	console.log(lin.gender);
	console.log(lin.age);

效果

在这里插入图片描述

prototype一定是函数的属性!当这个函数是一个构造函数的时候,那么它new出来的对象,将以它的原型那个对象为new出来的实例的原型对象。

在这里插入图片描述

注意,任何一个对象,都有__proto__属性,这个属性是Chrome自己的属性,别的浏览器不兼容,但是别的浏览器也有原型对象,只不过不能通过__proto__进行访问而已。
这是属性指向自己的原型对象。
我们的JavaScript有一个非常牛逼的机制:原型链查找。
当我们试图访问一个对象身上的属性的时候,如果这个对象身上有这个属性,则返回它的值。如果它身上没有这个属性,那么将访问它的原型对象,检测它的原型对象身上是否有这个值,如果有返回它原型对象身上的这个值。

也就是说,我们刚才讲解了2个对象和一个函数的故事。任何一个函数都有原型,原型是一个对象,用prototype来访问。当这个函数是构造函数的时候,new出来的对象,它们的原型对象就是这个构造函数的原型。
prototype我们称为“原型”,只有函数有原型
__proto__我们称为“原型对象”,任何对象都有原型对象。

在这里插入图片描述

原型的用途

我们定义一个方法的时候,如果写在构造函数里面:

	function People(name,age){
    
    
		this.name = name;
		this.age = age;
		this.sayHello = function(){
    
    
			alert("你好,我是" + this.name + "我今年" + this.age + "岁了");
		}
	}
	
	var lin= new People("林江涛",12);
	var jiu= new People("JiuMei",11);
	
	lin.sayHello();
	jiu.sayHello();

实际上这个函数被复制了两份,一份给了lin,一份给了jiu。lin和jiu这两个实例身上有了相同功能的函数,但是这个函数不是同一个函数!
而函数的意义就是被复用,你没有复用函数:

	alert(lin.sayHello == jiu.sayHello); //false

lin身上的函数,和jiu身上的函数,不是同一个函数。

那应该怎么办呢?一句话:所有的属性要绑在对象身上,而所有的方法,定义在对象的原型对象中:

	function People(name,age){
    
    
		//构造函数里面,负责定义一些属性,随着构造函数的执行,这些属性将绑定到new出来的对象身上
		this.name = name;
		this.age = age;
	}
	//把所有的方法,定义在原型对象身上:
	People.prototype.sayHello = function(){
    
    
	alert("你好,我是" + this.name + "我今年" + this.age + "岁了");
	}

在这里插入图片描述

	alert(lin.sayHello == jiu.sayHello);

在这里插入图片描述
证明了lin的sayHello方法和jiu的,是同一个函数。内存消耗小很多。

JavaScript原型链机制

先学一个属性,constructor,函数的原型有constructor属性,指向构造函数。
在这里插入图片描述

People.prototype.constructor //指向构造函数

我们之前说过,一个对象的原型身上有什么,那么实例对象就也可以打点调用什么,所以:

xiaoming.constructor   //指向构造函数

只要是对象,一定有原型对象,就是说只要这个东西是个对象,那么一定有__proto__属性。
世界上只有一个对象没有原型对象,这个对象就是Object.prototype。

Object是一个函数,是系统内置的构造函数,用于创造对象的。Object.prototype是所有对象的原型链终点。
所以,当我们在一个对象上打点调用某个方法的时候,系统会沿着原型链去寻找它的定义,一直找到Object.prototype。

在这里插入图片描述

所有的引用类型值,都有内置构造函数。比如
new Object()
new Array()
new Function()
new RegExp()
new Date()

我们来看看数组的情况:
在这里插入图片描述

函数也是对象。JavaScript中函数是一等公民,函数是对象。函数也是对象,只不过自己能()执行。

在这里插入图片描述

基本类型值,也有包装类型。所谓包装类型,就是它的构造函数。
new Number()
new String()
new Boolean()

在这里插入图片描述
所以你就能明白,为毛毛”abc”能够调用indexOf()方法,是因为String.prototype身上有这个方法。

猜你喜欢

转载自blog.csdn.net/weixin_44368963/article/details/108959013