认识对象

241 阅读5分钟

对象

无序的数据集合,由若干个“键值对”(key-value)构成。

键值对由键名和键值组成,每个键值对之间用逗号分隔。

  • 键名是字符串,不是标识符。
  • 若引号省略,则键名按标识符格式命名,但它仍然是字符串。

创建对象的方式

  1. new Object()
  2. 对象字面量
//第一种
var person = new Object()
person.name = 'jane'
person.age = 18

//第二种
var person = {
    name: 'jane'
    age: 18
}

属性的方法(增删改查)

读取属性的方法 (读)

(重点)

点表示法

用来访问对象的属性和方法。

只能接受字面量的成员名字,不接受变量作为名字

数值键名不能用点表示法,如obj.0xFF会被当成小数点。

var  person = {
name : {
first : 'Bob',
last : 'Smith'
},
age : 18,
5 : 'number'
}
console.log(person.age); // 18  age是字符串
console.log(person.name.first); // Bob
console.log(person.5); // 会报错
Object.keys(person);//["5", "name", "age"]

括号表示法

另一种访问属性的方式。

将要访问的属性以字符串的形式放入方括号中。

键名必须加引号否则会被当成变量,数字键可以不加

console.log(person['age']) //18
console.log(person['name']['first'])  // Bob
console.log(person[5]) //number

优点括号表示法可以通过变量来访问属性

var a = 'xxx';
var obj = {
    xxx: 1234        //[a]作为变量使用
}
console.log(obj);//{xxx: 1234}

var a = 'xxx';
var obj = {};
obj.xxx = 'jane';
obj.a//undefined,访问不到对应的属性,点表示法不接受变量作为名字
obj[a]//"jane" 通过变量访问属性
//obj[a] 等同于 obj.xxx 等同于 obj['xxx']

给属性赋值的方法 (增/改)

  1. 点表示法
  2. 括号表示法
var o = new Object();
o.name = 'jane';
o['age'] = 18;
console.log(o); //{name: "jane", age: 18}
  1. 批量赋值

Object.assign(obj,{})

var o = new Object();
Object.assign(o,{a:1, b:2});
console.log(o);//{a: 1, b: 2}
  1. 无法通过自身修改或增加 继承属性
var obj1 = {};
obj1.toString = 'xxx';

若非要改变继承属性,可通过原型链改变

obj1.__proto__.toString = 'hello';

Object.create()

创建一个新对象,使用现有的对象来提供新创建的对象的__proto__。(新对象继承现有对象的原型和属性)

var common = {name: 'jane', age: 18};
var person = Object.create(common);
person;

删除属性 (删)

delete obj.name

无法认定某个属性是否存在的,只能保证读取这个属性肯定得到undefined。(即删除不存在的属性它也不报错)


var obj = {
name : 'jane',
age : 18
}
//判断是否含有属性名
'name' in obj === false;//true 则不含name属性名
'name' in obj === undefined;// 不能判断属性名,只能判断属性值

//删除属性名和属性值
delete obj.name;
console.log(obj); //{age: 18}

//仅删除属性值
obj.name = undefined;

查看所有属性(查)

Object.keys(obj)

var obj = {
name : 'jane',
age : 18
}
Object.keys(obj); //["name", "age"]

查看属性值

Object.values(obj)

var obj = {
name : 'jane',
age : 18
}
Object.values(obj);//["jane", 18]

查看自身属性和继承属性

console.dir(obj)

var obj = {
name : 'jane',
age : 18
}
console.dir(obj);

判断自身属性还是继承属性

obj.hasOwnProperty('属性名')

var obj = {
name : 'jane',
age : 18
}
obj.hasOwnProperty('name');//true
obj.hasOwnProperty('toString');//false

检查变量是否被声明

var a = 1
if(a){
    console.log('ok')
} // ok
if(window.a){
    console.log('ok')
} // ok

if(b){
    console.log('ok')
} // 报错
if(window.b){
    console.log('ok')
} // undefined 即找不到这个属性

模式

工厂模式

function createPerson(name,age,sex){
  var o = new Object();
  o.name = name;
  o.age = age;
  o.sex = sex;
  return o;
}
var person1 = createPerson('Bob',18,'female');
console.log(person1)

优点:

  • 解决了创建多个相识对象的问题

缺点:

  • 没有解决对象识别的问题(识别对象的类型)

构造函数

function Person(name,age,sex){
  this.name = name
  this.age = age
  this.sex = sex
  this.sayName = function(){
    console.log(this.name)
  }
 //相当于 this.sayName = new Function("console.log(this.name)")
//两个方法不是同一个Function的实例
}
var person1 = new Person('Bob',18,'male')
console.log(person1)
person1.sayName()//"Bob"

var person2 = new Person('Jane',20,'female')
console.log(person2)
person2.sayName()//"Jane"

console.log(person1.sayName == person2.sayName)//false

不同实例上的同名函数不相等

function Person(name,age,sex){
  this.name = name
  this.age = age
  this.sex = sex
  this.sayName = sayName
}
//设置成全局函数
function sayName(){
    console.log(this.name)
}
var person1 = new Person('Bob',18,'male')
console.log(person1)
person1.sayName()
var person2 = new Person('Jane',20,'female')
console.log(person2)
person2.sayName()

console.log(person1.sayName == person2.sayName)//true

缺点:

  • 需要定义很多方法,就需要定义多个全局函数

与工厂模式区别:

  • 没有显示创建对象
  • 直接将属性和方法赋值给了this对象
  • 没有return语句

new运算符

var person1 = new Person('Bob',18,'female');
console.log(person1)
  • 创建空的对象{} var person = new Object();
  • 设置 该对象的构造函数到另一个对象(原型链) person._proto_ = Person.prototype;
  • 将创建的对象person作为this的上下文
  • 判断返回值,若没有返回对象,则返回this

原型模式

function Person(){
}
Person.prototype.name = 'Bob'
Person.prototype.age = 18
Person.prototype.sayName = function(){
  console.log(this.name)
}
var person1 = new Person()
console.log(person1)
person1.sayName()//"Bob"

var person2 = new Person()
person2.sayName()//"Bob"

console.log(person1.sayName === person2.sayName)//true

优点:

  • 让所有实例共享它的属性和方法

JSON

JavaScript Object Notation 是一种用于数据交换的文本格式

格式

  • 复合类型的值只能是数组或对象,不能是函数、正则表达式对象、日期对象。
  • 简单类型的值只有四种:字符串、数值(必须以十进制表示)、布尔值和null(不能使用NaN, Infinity, -Infinity和undefined)。
  • 字符串必须使用双引号表示,不能使用单引号。
  • 对象的键名必须放在双引号里面。
  • 数组或对象最后一个成员的后面,不能加逗号。

注意

空数组和空对象都是合格的 JSON 值,null本身也是一个合格的 JSON 值。

方法

JSON.stringify()

用于将一个值转为字符串,并且可以被JSON.parse方法还原。

JSON.stringify('abc')//""abc"" 
//双引号可以让 JavaScript 引擎知道,foo是一个字符串,而不是一个变量名
JSON.stringify(1)//"1"
JSON.stringify([])//"[]"
JSON.stringify({})//"{}"
JSON.stringify([1,2,'hello'])//"[1,2,"hello"]"
JSON.stringify(name : 'zhang')//"{"name":"zhang"}"

比较: 对于原始类型的字符串,转换结果会带双引号

JSON.stringify('abc') === "abc"//false
JSON.stringify('abc') === "\"abc\""//true
  • 对象中,有成员的值是undefined、函数等,这个成员会被JSON.stringify()过滤。
  • 数组中,成员是undefined、函数等,则这些值被转成null。正则对象会被转成空对象。
var obj = {
    a : undefined,
    b : function(){}
}
JSON.stringify(obj) // "{}"

var arr = [undefined,function(){}]
JSON.stringify(arr) // "[null,null]"

JSON.stringify(/foo/) // "{}"

JSON.parse()

用于将JSON字符串转化成对象。

JSON.parse('"abc"');//"abc"
JSON.parse('true');//true
JSON.parse('{}');//{}
JSON.parse('[1,2,"hello"]');//[1, 2, "hello"]

JSON.parse("'String'") // (对象的键名没有放在双引号内)Unexpected token ' in JSON at position 0

JSON.parse(JSON.stringify([1,2,"hello"])) == [1,2,"hello"];//false
//通过JSON转化成字符串再还原的字符串[1,2,"hello"]已经不是原来的字符串了。

深拷贝的另一种写法

var obj = {
    name: 'Jane',
    age: 3,
    friends: ['aa', 'bb', 'cc']
}
var obj2 = JSON.parse(JSON.stringify(obj))
obj.age = 4
console.log(obj2.age) // 3