【慕课网】JavaScript对象

1.对象概述

把一组数据结构和处理它们的方法组成对象(object),把相同行为的对象归纳为类(class),通过类的封装(encapsulation)隐藏内部细节,通过继承(inheritance)实现类的特化(specialization)/泛化(generalization),通过多态(polymorphism)实现基于对象类型的动态分派(dynamic dispatch)。

对象包含一系列无序的属性,每个属性(可动态添加或删除)都有一个字符串key和对应的value,每个对象都还有个原型。

javascript中对象的每一个属性都有很多属性标签:writable、enumerable、configurable、value、set/get。

每一个对象还有一个原型[[proto]]。

[[proto]] [[class]]这些标签是描述属性特征的 在js中是无法直接访问的 因为这些特性都是内部值 ECMAScript的规范是把他们放在两个方括号中的

var obj={};
obj.x=1;
obj.y=2;

function foo(){}
foo.prototype.z=3;
obj.__proto__=new foo();  //这个地方是把obj对象的原型指向foo.prototype ;
obj.x ===1;   //true;
obj.y===2;  //true;
obj.y===3 ; //false ;

var obj=new foo();
obj.x ===1;    //false
obj.y===2;   //false

proto:指向foo()的prototype(函数的对象属性)。

访问obj.z 查找对象属性,没有z,再在对象的原型链上继续查找一直到末端。

对象的[class]标签表示它属于那个种类。

对象的[extensible]标签表示它是否允许增加新的属性。

2.创建对象、原型链

对象的创建:

1.字面量:var obj1 = {x:1,y:2};可嵌套

2.new构造器的方式: prototype是原型是对象属性

function foo(){}
foo.prototype.z = 3;
 
var obj = new foo();// obj的prototype指向foo.prototype
obj.y = 2;
obj.x = =1;
obj.z = 3;// obj中没有z这个值,会向上找原型,原型中有就返回
// 最上层的原型是Object.prototype --->null 找到null还没有就会返回undefined
typeof obj.toString; // 'function'
'z' in obj; //true
obj.hasOwnProperty('z'); // false 说明z不再obj上,而在原型上
// 会继承原型链上的属性,但是不会去修改他们

3.Object.create创建对象,create时系统内置函数

var obj = Object.create({x:1});// 会让对象的原型指向创建的x
obj.x//1
typeof obj.toString;// 'function'
obj.hasOwnProperty('x');// false
 
var obj = Object.create(null);
obj.toString //undeined

3.属性操作

读写对象属性、属性异常、删除属性、检测属性、枚举属性。

枚举简单的说也是一种数据类型,只不过是这种数据类型只包含自定义的特定数据,它是一组有共同特性的数据的集合

数据属性:
1.configurable:设置属性是否能被删除,属性的特性是否能被设置,能否修改属性的值等;
2.enumerable:设置属性是否可枚举
3.writable:设置属性的值能否被修改
4.value:设置属性的值

如果想通过自定义这些特性来设置对象属性,可以通过Object.defineProperty,如下:
var person = {name:"张三"};
Object.defineProperty(person,name,{configurable:true,enumerable:true,writable:true,value:"李四”});

在上面所设置的特性当中,configurable如果为false表示属性特性设置在之后不能被改动(除了writable,writable在configurable为false时仍然可以设置成false),而且configurable一旦为false后就不能再设置成true了,
而enumberable如果为false则表示该属性不可枚举,用for in循环输出对象属性时该属性不会被输出;
writable很明显,为false时则表示不可修改该属性的值(不过当configurable为true时可以通过修改value的值直接改写或者将writable修改为true)

Object.defineProperty(person,name,{configurable:false});   
delete person.name;    //delete操作不成功
Object.defineProperty(person,name,{enumerable:false});  //操作不成功
访问器属性
configurable:设置属性是否能被删除,属性的特性是否能被设置,能否修改属性的值等;
enumerable:设置属性是否可枚举
get / set :在读写属性时会自动调用的函数
比如:
var book = {
   _year:2004,
   edition:1
};
Object.defineProperty(book,"year",{
   get:function(){
        return this._year;
   },
   set:function(newValue){
       this._year = newValue;
       this.edition += newValue - 2004;
   }
});
 
book.year = 2005; //当要设置year属性时,会自动调用set方法
alert(book.edition);
 
如果要的不止是配置单单一个属性,而是要同时配置多个,可以通过Object.defineProperties,如下:
var person = {name:"张三"};
Object.defineProperty(person,{
      name:{value:"李四”,configurable:false},
      sex:{value:"man",writable:false}
});
在配置完属性后或者通过Object.defineProperty更改过属性后想读者该属性,可以通过Object.getOwnPropertyDescriptor读取
Object.getOwnPropertyDescriptor(book,"edition");        //读取book对象中的edition属性

属性读写:

var obj = {x:1,y:2};
obj.x;   //1
obj["y"];   //2

属性读写异常:

var obj = {x:1};
obj.y; //undefined

属性删除:

var person = {age:28,title:'fe'};
delete person.age; //true
delete person['title']; //true
person.age; //undefined
delete person.age; //true

delete Object.prototype; //false

//getOwnPropertyDescriptor 获取对象属性所有标签。
var descriptor = Object.getOwnPropertyDescriptor(Object,'prototype');
//configurabe: 方法,检查获取到的object下的对象是否可配置。
descriptor.configurable; //false

//var定义的全局变量或者局部变量不会被删除
var globalVal = 1;
delete globalVal; //false

(function(){
	var localVal = 1;
	return delete localVal;
}()) //false

//全局函数或者局部函数也不可以被删除
function fd(){};
delete fd; //false

(function(){
	function fd(){};
	return delete fd;
}()); //flase

//隐式全局变量
onNo = 1;
window.ohNo; //1
delete ohNo; //true

属性检测:

var cat = new Object;
cat.legs = 4;
cat.name = "Kitty";

'legs' in cat; //true
'abc' in cat; //false
'toString' in cat; //true,inherited property!!!

//Object.hasOwnProperty('property')只检测本对象上是否有该属性,有则返回true
cat.hasOwnProperty('legs'); //true
cat.hasOwnProperty('toString'); //false
//对象是否是可枚举的
cat.propertyIsEnumerable('legs'); //true
cat.propertyIsEnumerable('toString'); //false

//定义枚举为false
Object.defineProperty(cat,'price',{enumerable:false,value:1000});
cat.propertyEnumerable('price'); //false
cat.hasOwnProperty('price'); //true

//属性枚举(Object的属性是不可枚举,默认为false,其他对象默认是true)
var o = {x:1,y:2,z:3};
'toString' in o; //true
o.propertyIsEnumberable('toString'); //false
var key;
for(key in o){
	console.log(key); //x,y,z
}

var obj = Object.create(o);
obj.a = 4;
var key;
for(key in obj){
	console.log(key); //a,x,y,z
}

//Object.hasOwnProperty('property')只检测本对象上是否有该属性,有则返回true[只处理对象上的属性,不去向原型链请求属性]
var obj = Object.create(o);
obj.a = 4;
var key;
for(key in obj){
	if(obj.hasOwnProperty(key)){
		console.log(key); //a
	}
}

4.get/set方法

JavaScript中对象的property有三个属性:
1.writable。该property是否可写。
2.enumerable。当使用for/in语句时,该property是否会被枚举。
3.configurable。该property的属性是否可以修改,property是否可以删除。

var man = {
	name:"Bosn",
	weibo:"@Bosn",
	get age(){
		return new Date().getFullYear()-1988;
	},
	set age(val){
		console.log('Age can\'t be set to ' + val);
	}
}

console.log(man.age); //27
man.age = 100; //Age can\'t be set to 100
console.log(man.age); //still 27

// get/set与原型链

function foo(){}
Object.defineProperty(foo.prototype,'z',{
    get: function(){return:1;}
});
var obj = new foo();
 
obj.z;// 1
obj.z = 10;
obj.z;// still 1
 // 当obj中没有z属性,并向原型链上查找的时候有对应的get/set方法时,再赋值的时候会走原型上的相应的get/set方法,而不会直接赋值给obj
 
 // 想要赋值给obj.z
Object.defineProperty(obj,'z',{
    value: 100,
    configurable: true;
});
obj.z;// 100
delete obj.z;
obj.z;// back to 1

var o = {};
Object.defineProperty(o,'x',{value:1}); //writable=false,configurable=false
var obj = Object.create(o);
obj.x; //1
obj.x = 200;
obj.x; //1

Object.defineProperty(obj,'x',{writable:true,configurable:true,value:100});
obj.x; //100
obj.x = 500;
obj.x; //500

附注:

val = +val;

实际上就是利用一元+操作符的特性(会尝试转换为数字),来隐式将一个变量转换为数字类型(number)。

例如:如果val是"123",+“123”; // 输出123,类型是number,而不再是string

5.属性标签

writable、enumerable和configurable默认值:
1)在使用Object.defineProperty、Object.defineProperties 或 Object.create 函数的情况下添加数据属性,writable、enumerable和configurable默认值为false。
2)使用对象直接量创建的属性,writable、enumerable和configurable特性默认为true。

defineProperties应用场景:
1.Node.js编程,需要对属性的访问做控制,需要更健壮的get/set方法提供属性存取的控制。
2.前端安全,通过Object.defineProperties禁止部分敏感属性的访问。来防止前端页面环境被插件、ISP等因素篡改。
3.一些较为复杂的业务逻辑或较为底层的库,get/set/权限控制在一些情况下会让代码更加健壮。

configurable 是否能delete删除属性修改属性标签; writable 是否能修改属性值;enumerable 是否可以枚举,使用for in。

// 查看属性标签
Object.getOwnPropertyDescriptor({pro:true},'pro');
// Object{value:true,writable:true,enumerable:true,configurable:true}
Object.getOwnPropertyDescriptor({pro:true},'a'};
//undefined

var person = {};
Object.defineProperty(person,'name',{
	configurable:false,
	writable:false,
	enumerable:true,
	value:'Bosn Ma'
});
person.name; //Bson Ma
person.name = 1;
person.name; //Bson Ma
delete person.name; //false

Object.defineProperties(person,{
	title:{value:"fe",enumerable:true},
	corp:{value:'BABA',enumerable:true},
	salary:{value:50000,enumerable:true,writable:true}
});

Object.getOwnPropertyDescriptor(person,'salary');
//Object{value:50000,writable:true,enumerable:true,configurable:false}
Object.getOwnPropertyDescriptor(person,'corp');
//Object{value:'BABA',writable:false,enumerable:true,configurable:false}

在这里插入图片描述

6.对象标签、对象序列化

对象标签:[[proto]]、[[class]]、[[extensible]]

原型标签:[[proto]]

class标签:[[class]]

首先我们先了解Object.prototype.toString的用法:

toString 是 Object 原型对象上的方法,

使用 call 来调用该方法会返回调用者的类型字符串,格式为 [object,xxx],xxx 是调用者的数据类型,包括:String、Number、Boolean、Undefined、Null、Function、Date、Array、RegExp、Error、HTMLDocument 等,基本上,所有的数据类型都可以通过这个方法获取到。

Object.prototype.toString()返回[object class], 我们可以通过它获取对象的类型信息。

要获取一个对象的真实的内置类型,我们需要通过获取[[Class]]的属性值,在es5之前,该属性值只能通由Object.prototype.toString来访问,因此,通过Object.prototype.toString.call(arr)改变tostring方法的this指向,从而获得对象的内置类型。

console.log(Object.prototype.toString.call("jerry"));//[object String]
console.log(Object.prototype.toString.call(12));//[object Number]
console.log(Object.prototype.toString.call(true));//[object Boolean]
console.log(Object.prototype.toString.call(undefined));//[object Undefined]
console.log(Object.prototype.toString.call(null));//[object Null]
console.log(Object.prototype.toString.call({name: "jerry"}));//[object Object]
console.log(Object.prototype.toString.call(function(){}));//[object Function]
console.log(Object.prototype.toString.call([]));//[object Array]
console.log(Object.prototype.toString.call(new Date));//[object Date]
console.log(Object.prototype.toString.call(/\d/));//[object RegExp]
function Person(){};
console.log(Object.prototype.toString.call(new Person));//[object Object]

那为什么不直接用obj.toString()呢?

console.log("jerry".toString());//jerry
console.log((1).toString());//1
console.log([1,2].toString());//1,2
console.log(new Date().toString());//Wed Dec 21 2016 20:35:48 GMT+0800 (中国标准时间)
console.log(function(){}.toString());//function (){}
console.log(null.toString());//error
console.log(undefined.toString());//error

同样是检测对象obj调用toString方法,obj.toString()的结果和Object.prototype.toString.call(obj)的结果不一样,这是为什么?

这是因为toString为Object的原型方法,而Array ,function等类型作为Object的实例,都重写了toString方法。不同的对象类型调用toString方法时,根据原型链的知识,调用的是对应的重写之后的toString方法(function类型返回内容为函数体的字符串,Array类型返回元素组成的字符串…),而不会去调用Object上原型toString方法(返回对象的具体类型),所以采用obj.toString()不能得到其对象类型,只能将obj转换为字符串类型;因此,在想要得到对象的具体类型时,应该调用Object上原型toString方法。

//表示对象是哪一个类型
var toString = Object.prototype.toString;
function getType(o){return toString.call(o).slice(8,-1);};

toString.call(null); //"[object null]"
getType(null); //"Null"
getType(undefined); //"Undefined"
getType(1); //"Number"
getType(new Number(1)); // "Number"
typeof new Number(1); // "Object"
getType(true); //"Boolean"
getType(new Boolean(true)); //"Boolean"

extensible标签:[[extensible]]

var obj = {x:1,y:2};
Object.isExtensible(对象); //可判断对象是否可以添加;
Object.preventExtensible(对象); //可将对象改为不能添加,不改变原有属性标签
Object.defineProperty(obj,"x",{value:2});   //虽然禁止了对象扩展,但是删除或者修改属性的值以及标签

Object.seal(obj); //设置对象属性标签不可被配置,设置confinurable为false
Object.ifSealed(obj); //判断属性是否可以被修改

Object.freeze(obj); //冻结,设置属性不可写,也就是将对象writable、enumrable、configurable设置为false,阻止对象的所有修改 
Object.isFrozen(obj);   //判断对象是否被freeze
var obj = {x:1,y:2};
Object.isExtensible(obj); // true
Object.preventExtensions(obj);
Object.isExtensible(obj); //false
obj.z = 1;
obj.z; //undefined
Object.getOwnPropertyDescriptor(obj,'x');
// Object{value:1,writable:true,enumerable:true,configurable:true}

Object.seal(obj);
Object.getOwnPropertyDescriptor(obj,'x');
// Object{value:1,writable:true,enumerable:true,configurable:false}
Object.isSealed(obj); //true

Object.freeze(obj);
Object.getOwnPropertyDescriptor(obj,'x');
// Object{value:1,writable:false,enumerable:true,configurable:false}
Object.isFrozen(obj); //false

序列化:

在向后台发送请求数据时,用JSON.stringify将对象转化为字符串,用JSON.parse将字符串解析为对象,但是,在用JSON.stringify将对象转化为字符串时如果对象属性的值为undefined,那么它将不会出现在转化后的字符串里。

var obj = {x:1,y:true,z:[1,2,3],nullVal:null};
JSON.stringify(obj); //"{"x":1,"y":true,"z":[1,2,3],"nullVal":null}"

obj = {val:undefined,a:NaN,b:Infinity,c:new Date()};
JSON.stringify(obj); //"{"a":null,"b":null,"c":"2015-01-20T14:15:43.910Z"}"

obj = JSON.parse('{"x":1}');
obj.x; //1 

如果我们想自定义序列化,可以在对象里自定义toJSON方法,同理,我们在将对象toString或者valueOf时也可以自定义toString方法和valueOf方法。

其他对象方法:toString()、valueOf()

var obj = {x:1, y:2};
obj.toString = function(){return this.x + this.y;};
obj.valueOf = function(){return this.x + this.y + 100}
"result" + obj; // 这里是result103,而不是result3

JavaScript中的二元+操作符,若操作数为对象,则尝试转换为基本类型。优先级是先找valueOf,再找toString。

注意到,若valueOf/toString返回的不是基本类型,而是对象,则会被忽略。

var obj = {x:1, y:2};
obj.toString = function(){return this.x + this.y;};
obj.valueOf = function(){return {x : 1}}; // 不可用的valueOf
"result" + obj; // "result3", 因为valueOf无效,使用toString作为结果返回

若valueOf/toString均不可用,则报TypeError异常。

var obj = {x:1, y:2};
obj.toString = function(){return {};}; // 不可用的toString
obj.valueOf = function(){return {x : 1}}; // 不可用的valueOf
"result" + obj; // Uncaught TypeError: Cannot convert object to primitive value

对象转化为基本类型的过程:

在后台首先会自动调用valueOf方法尝试将对象转化为基本类型,如果valueOf不存在或者无法转化为基本类型则会调用toString方法继续尝试,如果两种都无法将对象转化为基本类型则会报错。

本节课程总结:

对象的结构
创建对象
属性操作
getter/setter
属性标签
对象标签
序列化
对象方法

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值