JS 对象
土灵 人气:1JavaScript 中的对象
在 JavaScript 中万物皆对象,比如:字符串、数组、日期等等。但是 JavaScript 又不是一种真正的面向对象编程(OO)语言,因为 ECMAScript(ES6之前) 中没有类的概念,因此它的对象也与基于类的语言中的对象有所不同。
ECMA-262 把对象定义为:“无序属性的集合,其属性可以包含基本值、对象或者函数。”大白话来讲就是:“对象就是拥有属性和方法的数据”
一、理解对象
创建自定义对象的最简单方式就是创建一个 Object 的实例,然后再为它添加属性和方法,早期写法如下:
var person = new Object()
person.name = "Nicholas" // person 实例对对象的属性为 name ,值为 "Nicholas"
person.age = 29 // person 实例对对象的属性为 age ,值为 29
person.sayName = function() {
alert(this.name)
} // person 实例对象的方法名 sayName 方法为 打印当前的 name
现在对象字面量方法成为首选:
var person = {
name: "Nicholas",
age: 29,
123: '123',
sayName: function(){
alert(this.name)
}
}
通过点语法访问对象属性 如上述例子
console.log(person.name) // 打印 name 值为 "Nicholas"
console.log(person.age) // 打印 name 值为 29
通过方括号访问对象属性
console.log(person[name]) // 输出 "Nicholas"
console.log(person[123]) // 输出 "123"
访问对象方法
console.log(person.sayName()) // 输出 "Nicholas"
区别:中括号法可以用变量作为属性名,而点方法不可以。
中括号法可以用数字作为属性名,而点语法不可以。
二、工厂模式
字面量创建对象和传统创建对象方式并没有什么问题,但是如果要创建多个对象实例就会显得很麻烦。所以为了解决这个问题,我们可以写一个函数,解决代码重复问题。
function Person(name, age) {
var o = new Object();
o.name = name
o.age = age
return o
}
var person1 = Person("小明", 12)
var person2 = Person("小刚", 14)
上述的 person1 和 person2 生成实例对象。就等于是在调用函数。但是这个方法存在一个问题,person1 和 person2 之间没有联系,不能反映它们是一个原形对象的实例,所以又有一个新的模式出现。
三、构造函数模式
Javascript 提供了一个构造函数(Constructor)模式。所谓的构造函数就是一个普通函数,内部使用了 this,直接将属性和方法赋给了 this 对象,对构造函数使用 new 运算符,就能生成实例,并且 this 变量会绑定在实例对象上。首字母要大写为了区分普通函数和构造函数。所以 Person 的原型对象现在可以这样写:
function Person(name, age) {
this.name = name
this.age = age
}
var person1 = new Person("小明", 12)
var person2 = new Person("小刚", 14)
我们现在就可以生成实例对象了,如上述所示,person1 和 person2 分别保存着 Person 的一个不同的实例。而且 person1 和 person2 会自动含有一个 constructor(构造函数)属性,该属性指向 Person 它们的构造函数。如下所示:
alert(person1.constructor == Person); // true
alert(person2.constructor == Person); // true
为此 Javascript 提供了一个检测对象类型的操作符 instanceof。
alert(person1 instanceof Person); // true
alert(person2 instanceof Person); // true
四、构造函数的问题
构造函数模式虽然好用,但也并非没有缺点,就是每个方法都要在每个实例上重新创建一遍,这就造成了内存浪费的问题。请看下面这个例子,我们为 Person 对象添加一个方法 play(玩)。那么原型对象 Person 如下:
function Person(name, age) {
this.name = name
this.age = age
this.play = function() {
alert("打游戏")
}
}
var person1 = new Person("小明", 12)
var person2 = new Person("小刚", 14)
alert(person1.play()); // 打游戏
alert(person1.play == person2.play); //false
这样做的话,每生成一个实例对象,play() 方法都是一样的,每次都会多占内存,那么能不能让 play() 方法在内存中只生成一次,然后所有实例对象都指向那个内存呢,是可以的。
五、Prototype(原型)模式
我们创建的每个函数都有一个 prototype(原型)属性,这个属性是一个指针,指向一个对象,而这个对象的用途是包含可以由特定类型的所有实例共享的属性和方法。按照字面意思来理解,那么 prototype 就是通过调用构造函数而创建的那个对象实例的原型对象。这样的话我们就可以把同样的方法定义到 prototype 对象上。
function Person(name, age) {
this.name = name
this.age = age
}
Person.prototype.play = function() {
alert("打游戏")
}
// 然后在生成实例
var person1 = new Person("小明", 12)
var person2 = new Person("小刚", 14)
alert(person1.play == person2.play); //true
这时,它们的 play() 方法,都是同一个地址,指向 prototype 对象。如上
六、Prototype(原型)的一些方法
1、in 操作符
in 操作符只要通过对象能够访问到属性就返回 true,也可以遍历某个对象的所有属性。
alert("name" in person1) // true
alert("age" in person1) // true
for (var newDemo in person1){
alert(`person1的属性为:${newDemo},值为${person1[newDemo]}`)
}
2、isPrototypeOf()
用来检测某个对象和某个实例之间的关系,或者说一个对象是否是另一个对象的原型
alert(Person.prototype.isPrototypeOf(person1)) // true
alert(Person.prototype.isPrototypeOf(person2)) // true
2、hasOwnProperty()
当属性存在于实例中时才返回 true。
alert(person1.hasOwnProperty("name")) // true
加载全部内容