JavaScript对象

JS对象简介

JS对象是什么
  • JS对象是一种复合值:将很多值复合在一起(包括原始类型值、对象、函数(方法))
  • JS对象是若干无序属性的集合,可以直接通过属性名来访问对象的属性(键值对)
  • 函数作为某一个对象的属性时,称其为该对象的方法

补充:注意键值对中,键key的数据类型是string类型,但是值value的数据类型就不一定了。

var obj = {
  	name:3,
  	age:function(){
  		return typeof(name);
	}
}
obj.age();// 'string'
typeof(obj.name);// 'number'

创建对象:

var man = {
  	name:'frewen',
  	age:20,
  	hobby:['playing ping pong','dancing'],
  	describe:function(){
  		console.log(this.name + '\'s age is ' + this.age + '.And his hobbies are ' + this.hobby[0] + ' and ' + this.hobby[1] + '.');
	}
}
// 定义完成 调用函数
man.descirbe();
// frewen's age is 20.And his hobbies are playing ping pong and dancing.
JS对象分类
  • 内置对象(native object)由ECMAScript规范定义的对象或构造器对象(数组、函数等)

  • 宿主对象(host object)由JS解析器所嵌入的宿主环境定义的(如:window、document)

    ​注意:当前学习的宿主环境是浏览器,而不仅仅有浏览器这一个宿主环境,比如node.js环境

  • 自定义对象(user-defined object)运行中的用户自定义JS代码创建的对象//man对象

标准内置对象分为两类:

  1. 构造器函数对象(类对象)–类似于String、Number、Boolean等构造函数
  2. 非构造器对象—类似于Math、Json等非构造函数、

在这里插入图片描述

/* 使用构造器的方式相应的创建相应的对象 */
var i = new String('str');// string object
var h = new Number(1);// number object
var g = new Boolean(true);// boolean object
var j = new Object({name:"Tom"});// object object
var k = new Array([1,2,3,4]);
var l = new Date();
var m = new Error();
var n = new Function();
var o = new RegExp(/\d/);

难点:

console.log(Function instanceof Function); // true
console.log((new Function()) instanceof Function); //true 类似于Person()这就是一个new Function
console.log((new(new Function)) instanceof Function);
//false 类似于var p = new Person();p是一个对象

JS对象的属性

JS对象属性的分类
  • 数据属性(property,属性),字符串的键到值的映射(包括基本类型数据、对象、函数)

  • 访问器属性(accessor,或称为访问器),访问属性的方法,注意:访问和设置时不加括号

  • 内置属性(internal property)存在与ECMAScript规范中,不能直接访问

var o = {
  	_x:1.0,// 不成文的规定 一般约定_x表示这个属性是私有属性
  	get x(){
  		return this._x;// 如果写成 get x(){return this.x;} 此时会不断的进行循环递归的调用
	},
  	set x(val){
  		this._x = val;
	}
}

console.log(o.x);// 调用get方法 1
o.x = 2;
console.log(o.x,o._x);// 调用set方法 访问_x属性值 2 2

上述代码注意几点:

  • 对于JS对象中,一般将带有_的属性称为私有属性,并通过getset方法进行设置

  • 上述代码中如果将get x()改为

在这里插入图片描述

则会出现错误,由于get x()方法的优先级要高于x属性,因此会一直调用get x()方法,出现递归执行的错误。

  • 代码解读
console.log(o.x); //调用get x()方法,返回_x的值
o.x = 2; // 为对象添加一个x属性,同时调用set x()方法,设置_x的值为2
console.log(o.x, o._x); //由于get x()方法的优先级要高于x所以两个返回的都是this._x的值
  • 代码变形
var o = {
  	x:1.0,// 不成文的规定 一般约定_x表示这个属性是私有属性
  	get x(){
  		return this._x;// 如果写成 get x(){return this.x;} 此时会不断的进行循环递归的调用
	},
  	set x(val){
  		this._x = val;
	}
}

console.log(o.x);// 调用get方法 没有_x属性 因此返回undefined
o.x = 2;// 给对象x属性重新赋值,同时调用set方法 会给_x赋值为2
console.log(o.x,o._x)// 2 2
  • 只读模式
var o = {
  	_x:1.0,// 不成文的规定 一般约定_x表示这个属性是私有属性
  	get x(){
  		return this._x;// 如果写成 get x(){return this.x;} 此时会不断的进行循环递归的调用
	},
}

console.log(o.x);// 1
o.x = 2;// 添加属性x
console.log(o.x,o._x);//1 1
JS对象访问器属性实例
var p1 = {
  	_name:"Jack",
  	_age:23,
  	set age(val){
  		if(val > 0&&val<150){
  			this._age = val;
		} else {
  			console.log('请设置正常的年龄');
		}
	},
  	get age(){
  		return this._age;
	}
};
p1.age = 178;// 请设置正常的年龄

JS对象相关操作

创建JS对象的方式
  • 通过对象字面量的方式直接创建对象
var obj = {
  	num:10,
  	str:'Hi',
  	show:function(){
  		return this.str;
	}
};

console.log(obj.__proto__ === Object.prototype);// true
console.log(obj.__proto__.__proto__);// null
/*
1. obj对象的proto属性应该是其原型Object的prototype属性
2. obj对象的proto的proto为null
*/
  • 通过Object的create静态方法创建对象
var newObj = Object.create(obj);// newObj的原型的obj
newObj.age = 23;
// 其中静态方法相当于又在原来的基础上重新创建了一个对象newObj 这个对象是一个空对象

注意这个原型链:

newObj的原型为obj,其中obj的原型为Object的prototype属性,obj的原型的原型为null

console.log(newObj.__proto__ === obj);// true
console.log(newObj.__proto__.__proto__ === Object.prototype);// true
console.log(newObj.__proto__.__proto__.__proto__ === null);//true
  • 通过构造函数的方式创建对象
function Person(name,age){
  	this.name = name;
  	this.age = age;
}
Person.prototype.sayName = function(){
  	console.log("hello,I'm",this.name,this.age,"years old.");
}
var person1 = new Person('Mike',21);
person1.sayName();// hello.I'm Mike 21 years old.

注意这个原型链:

person1的原型为Person的prototype属性,其中Person的原型为Function的prototype属性,Function的原型为Object,最终回归到null

console.log(person1.__proto__ === Person.prototype);//true
console.log(Person.__proto__ === Functon.prototype);//true
console.log(person1.__proto__.__proto__ === Object.prototype);// true
console.log(person1.__proto__.__proto__.__proto__ === null);//true
对象属性的增删改查
  • 添加和删除自有属性

  • 访问和修改自有属性

  • 通过点与中括号访问属性的区别(写个访问属性的for循环练习)

var obj = {};
obj.x = 2; //直接添加属性
console.log(obj.x); //通过.访问属性
obj.x = 5; //设置属性
console.log(obj["x"]); //通过[]访问属性
delete obj.x; //删除属性
console.log(obj.x);

# 输出结果
2
5
undefined
  • 添加属性:直接通过点的方式或者是中括号的方式直接进行添加

练习:

var obj2 = {
    id_1: 2,
    id_2: 4,
    id_3: 6,
    id_4: 8,
    id_5: 10
};
for (var i = 1; i <= 5; i++) {
    console.log(obj2['id_' + i]);// 此时要用到中括号的方式
}

//思考obj3 和 obj4 内容是什么?为什么?
var obj3 = {};
for (var i = 0; i < 10; i++) {
    obj3.i = i;
}
// obj3的输出结果为对象里面有一个属性i,i的值为9。在循环里面第一次循环相当于给对象添加了一个i属性,
//属性值为0,后面的循环都是在改变i的值,因此最终循环结束,对象只有一个属性,属性值的结果为在循环里i的最后一个结果为9
var obj4 = {};
for (var i = 0; i < 10; i++) {
    obj4[i] = i;
}
/*在obj4的输出结果里面有10个属性,每一个的属性值分别是循环时的i值。在循环的每一个循环里,都为obj4添加了
一个新的属性,采用中括号的方式,所添加的属性值不是一样的。因此最终循环结束,对象有10个属性,每个属性对应
一个属性值*/

对象属性特性简介

问题:为什么原型链上有些属性遍历不到

在这里插入图片描述

上述的代码中,在obj2上添加了y和z两个属性,同时obj1也有x这个属性,在obj2的原型链上有toString这个属性,但是通过for in的方式只能访问到x,y,z这三个属性,为什么访问不到原型链上的有些属性呢?

对象属性(数据属性)的特性

JS对象属性(数据属性)的特性
  • 属性的值([[value]]),对应属性的值

  • 可写特性([[writable]]),确定属性是否可写性

  • 可配置特性([[configurable]]),确定属性是否能删除和其他特性是否可配置

  • 可枚举特性([[enumerable]]),属性是否可枚举(是否可以遍历出来)

设置属性的特性(defineProperty方法设置enumerable)

{enumerable:false})//表示不可枚举,如果是true表示可以枚举
var obj = {
    x: 1,
    y: 2
};
Object.defineProperty(obj, 'x', { enumerable: false }); //表示不可枚举,如果是true表示可以枚举
for (var k in obj) {
    console.log(k, obj[k]);
}
# y 2

设置属性特性实例(writable与configurable)

{enumerable:true,writable:false,configurable:false}
// 上述说明可以枚举,不可写,不可删除
//设置属性特性实例(writable与configurable)
var person = { name: "Jack" };
Object.defineProperty(person, 'name', { enumerable: true, writable: false, configurable: false });
console.log(person.name); //jack
person.name = "Lucy"; // 不可写
console.log(person.name); //jack
delete person.name; // 不可删除
console.log(person.name); //jack
给对象添加属性
  • 直接给对象添加属性(属性特性默认都为true)
var obj = {
    x: 1,
    y: 2
};
//直接添加的属性,其所有特性默认都是true
obj.z = 3;
for (var k in obj) {
    console.log(k, obj[k]);
}
/*
x 1
y 2
z 3
*/
  • 通过defineProperty方法添加(属性特性默认为false)
Object.defineProperty(obj, "w", { value: 456, configurable: true }); 
//writable,enumerable没有指定,所以默认为false

在上述过程中,给对象通过defineProperty的方式添加属性,这样所有的特性都默认为false,除非手动指定为true

//通过defineProperty方法添加(属性特性默认为false)
var obj = {
    x: 1,
    y: 2
};
//直接添加的属性,其所有特性默认都是true
obj.z = 3;
//通过Object.defineProperty方法添加的属性,除了手动修改,其所有特性默认都是false
Object.defineProperty(obj, "w", { value: 456, configurable: true }); //writable,enumerable没有指定,所以默认为false
for (var k in obj) {
    console.log(k, obj[k]);
} // 没有办法输出w
/*
输出结果:
x 1
y 2
z 3
*/

没有输出w属性,因为w属性的enumerable的值为false,不可枚举

对象访问器(访问器属性)的特性

JS对象访问器(访问器属性)的特性
  • 可配置特性([[configurable]]),确定属性是否能删除和其他特性是否可配置

  • 可枚举特性([[enumerable]]),属性是否可枚举

  • 读取属性特性([[get]]),在读取属性时调用的函数,默认是undefined

  • 写入属性特性([[set]]),在写入属性时调用的函数,默认是undefined

//添加访问器
var obj1 = {
    _name: "Lucy"
};
Object.defineProperty(obj1, "name", {
    get: function() { //只定义了get 特性,因此只能读不能写
        return this._name;
    }
});
console.log(obj1.name); //"Lucy"
obj1.name = "jack"; //只定义了getter访问器,因此写入失效
console.log(obj1.name); //"Lucy"

因为在用defineProperty添加属性的时候,默认为false,只添加了get方法,因此没有写入的set方法,因此没有办法写入。

综合实例
var obj2 = {
    _name: "Lucy",
    set name(val) { this._name = val; },
    get name() { return this._name; }
};
Object.defineProperty(obj2, "name", {
    get: function() {
        return this._name + "_hihi";
    },
    set: function(val) {
        this._name = val + "_haha";
    }
});
console.log(obj2.name);// Lucy_hihi
obj2.name = "jack";// 通过set方法 设置值
console.log(obj2.name); // jack_haha_hihi

在上述代码中,第一个输出调用了get方法,因此输出lucy加上hihi。第二个调用了set方法,因此写入了this._namejack_haha,因此再调用get方法的时候输出了jack_haha_hihi

属性特性描述符及属性特性补充部分

什么是属性特性描述符
  • 属性特性描述符是一个用来查看对象属性的特性的对象

  • 该对象包含4个属性,对应4个特性,通过getOwnPropertyDescriptor方法获得

var obj = { x: 5 };
Object.defineProperty(obj, "y", {
    configurable: false,
    writable: false,
    enumerable: true,
    value: 6
});
Object.defineProperty(obj, "z", {
    configurable: false,
    value: 7
});
Object.getOwnPropertyDescriptor(obj, "x");
// {value: 5, writable: true, enumerable: true, configurable: true}
Object.getOwnPropertyDescriptor(obj,"y");
// {value: 6, writable: false, enumerable: true, configurable: false}
Object.getOwnPropertyDescriptor(obj,"z");
// {value: 7, writable: false, enumerable: false, configurable: false}
对象属性特性
  • 给多个属性设置特性的方法(Object.defineProperties

  • 在给多个属性添加特性的时候,相当于给不同的属性添加特性。

  • Object.create的第二个参数类似于Object.defineProperties的第二个参数,可以添加多个属性。

  • 使用Object的create方法,第二个参数的用法和defineProperties一样。

// 给多个属性设置特性的方法(Object.defineProperties)
//Object.create的第二个参数类似于Object.defineProperties的第二个参数,可以添加多个属性。
var obj1 = { x: 3 };
var obj2 = Object.create(obj1, { y: { value: 3, enumerable: true } });
for (var i in obj2) {
    console.log(i, obj2[i]);
}
/*
输出结果:
x 3
y 3
*/

var obj = { _x: 1 };
Object.defineProperties(obj, {
    y: { value: 2, writable: true, configurable: true, enumerable: true },
    z: { value: 2, writable: true, configurable: true, enumerable: true },
    x: {
        get: function() { return this._x; },
        set: function(val) {
            this._x = val;
        }
    }
});
// {_x: 1, y: 2, z: 2}
Object与属性和属性特性相关的方法
  • Object.keys(...)Object.getOwnPropertyNames(...) 区别:是否包含可遍历的属性
    • Object.keys() 返回所有自有(非继承)可枚举属性的键
    • Object.getOwnPropertyNames()返回所有自有(非继承)键,包括不可枚举

在这里插入图片描述

  • Object.prototype.hasOwnProperty(...) 可结合Object.keys一起使用

  • Object.prototype.propertyIsEnumerable(...)(hasOwnProperty的升级版)

    • Object.prototype.hasOwnProperty() 判断自身(不包括继承的)是否有该属性,不包括检测可枚举的属性
    • Object.prototype.propertyIsEnumerable() 判断自身(不包括继承的)是否有该属性并检测该属性是否可枚举
obj2.hasOwnProperty("k"); //true
obj2.hasOwnProperty("x");// false
obj2.propertyIsEnumerable("k");//false
obj2.propertyIsEnumerable("x");// false
  • in for...in (两者关于enumerable的区别)
    • in 检测一个对象是否有某个属性,包括继承的属性,包括不可枚举的属性
    • for...in 遍历一个对象的属性,包括继承的属性,但不包括不可枚举的属性

在这里插入图片描述

JS 对象之扩展、密封及冻结(级别逐渐升高)
  • Extensible(Object.isExtensible()、Object.preventExtensions( ))限制添加新属性
var empty1 = {
    a: 1
};
console.log(Object.isExtensible(empty1)); //true
empty2 = Object.create({}, {
    "a": {
        value: 1,
        configurable: false, //不可配置
        enumerable: true, //可枚举
        writable: true //可写
    }
});
console.log(Object.isExtensible(empty2));// true

一般来说,对象都是可以进行扩展的

注意:

(1)设置对象是不可扩展的,一个对象是可以扩展的,但是二者仍然相等

var obj = {};
var obj2 = Object.preventExtensions(obj);
console.log(obj === obj2); //true

(2)新创建的对象默认是可以进行扩展的,如果让其变为不可扩展的对象,则不可扩展

var empty = {};
console.log(Object.isExtensible(empty)); //true
empty.a = 1; //添加成功
Object.preventExtensions(empty);
console.log(Object.isExtensible(empty)); //false

(3)使用传统的方式给不可扩展对象添加属性,会静默失败,不抛出异常;在严格模式中,为不可扩展对象添加属性将抛出错误;使用 Object.defineProperty方法为不可扩展对象添加新属性会抛出异常

在这里插入图片描述

  • seal(Object.isSealed()、Object.seal( ))在extend的限制基础上,增加限制可配置属性特性

注意:

(1)设置一个对象是密封的,一个对象是不密封的,但是二者仍然相等

var obj = { //声明一个对象
    prop: function() {},
    foo: "bar"
};
var o = Object.seal(obj); //将 obj 密封,且返回原对象
console.log(o === obj); //true
console.log(Object.isSealed(obj)); //true

其中isSealed()判断是否是密封的

(2)密封的对象仍然可以修改原先的属性值,但不能把密封对象的属性进行重新配置,譬如将数据属性重定义成访问器属性.

在这里插入图片描述

(3)使用传统的方式给密封对象添加属性或删除属性,会静默失败,不抛出异常;在严格模式中,为密封对象添加属性或删除属性将抛出错误;使用 Object.defineProperty方法为密封对象添加新属性会抛出异常

在这里插入图片描述

  • freeze(Object.isFrozen()、Object.freeze( ))在seal的限制基础上,增加限制可写属性特性
var obj = {
    prop: function() {},
    foo: "bar"
};
//可以添加新的属性,已有的属性可以被修改或删除
obj.foo = "baz";
obj.lumpy = "woof";
delete obj.prop;
Object.freeze(obj); //冻结
console.log(Object.isFrozen(obj)); //true

注意:

  • 对冻结的任何对象做任何操作都会失败,不可写入,不可删除,不可添加新的属性。

  • 使用传统的方式给冻结对象添加属性或删除属性或修改属性,会静默失败,不抛出异常;

  • 在严格模式中,为密封对象添加属性或删除属性或修改属性将抛出错误;

  • 使用 Object.defineProperty方法为密封对象添加新属性会抛出异常

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值