对象
什么是对象
什么是对象,其实就是一种类型,即引用类型。而对象的值就是引用类型的实例。
在ECMAScript中引用类型是一种数据结构。用于将数据和功能组织在一起,它也常被称做为类,
但ECMAScript中却没有这种东西。虽然ECMAScript是一门面向对象的语言。
却不具备传统面向对象语言所拥有的类和接口等基本结构。
万物皆对象,除了数字,字符,布尔这种绝对值以外的所有部分都是对象,
对象是类的实例化体现,类是对象的抽象体现。
对象是一个个体,他具备自身类的所有属性和方法。
Object类是基类(基础类别:对象类),
我们曾经遇到过的对象:
var arr=new Array()
var date=new Date();
var obj=new Object();
对象的新建,有以下几种方法:
1、var obj=new Object();
2、var obj={};
3、var obj=Object.create();
1、new Object()
var obj=new Object();
obj.属性=属性值
obj.方法=方法函数
obj[属性]=属性值
obj[方法]=方法函数
中括号中的属性和方法必须是字符串,如果是变量,该内容必须是字符型变量。
var arr=new Object([])
创建数组,在javascript中数组不是单独的类型,它是由对象扩展出来的,
因此,可以使用这种形式来建立数组。
2、var obj={}
var obj={
属性:属性值,
方法:方法函数
}
花括号在语言中是指代码块的意思,在obj也相当于一个代码块。obj自身在使用中可以完成和丰富各种代码块。
在函数中,有时候需要返回一个对象,这时候,我们通常使用花括号的形式来返回对象
function abc(){
return {
属性:属性值,
方法:方法函数
}
}
3、Object.create()
Object.create(proto, [ propertiesObject ])
proto对象原型
propertiesObject 一组属性和值,该参数对象不能是 undefined,
另外只有该对象中自身拥有的可枚举的属性才有效,也就是说该对象的原型链上属性是无效的。
该方法可以针对已知对象创建新对象也可以创建一个空对象。
var obj=new Object();
var obj1={
a:1,
b:2,
c:function () {
}
};
var obj2=Object.create(obj1);
对象有2种属性,原型属性,对象属性
每个对象的对象属性都是不同的,如果继承完成的对象,它的原型属性是相同的
针对对象当获取某个属性时,先查看该对象是否有这个对象的对象属性,如果没有
就获取该对象下最近的一个原型属性,如果没有就返回undefined
如果给对象的属性赋值时,首先考虑赋值对象的对象属性,不考虑赋值给原型属性
原型属性可以理解为该对象的默认初始属性及初始值,如果设置时一定就是覆盖了对象
对象属性和属性值,那么以后调用的时候也是调用的对象属性,而不再应用原型属性
直到将对象属性删除
对象的操作方法
delete
删除对象的属性
var obj={a:3,b:4}
delete obj.a;
也可以根据键值删除对象下的属性。
变量无法通过delete删除
var s=10;
delete window.s;
delete obj1.__proto__.a;//可以删除原型属性,不允许,容易出问题
属性的值为函数,也不能通过delete删除。
assign()(只能复制一层,不能深复制 )
var 目标对象=Object.create(源对象); 源对象将作为目标对象的原型属性和方法
var 目标对象=Object.assign(目标对象,源对象1,源对象2,源对象3...);
将源对象的属性整体复制给目标对象的
成为目标对象的对象属性和对象方法,只能复制一层,里面的属性如果是引用对象
复制后仍然是相同引用(只能复制最外层的属性,如果有属性是引用关系,则两者也是相通的)
复制对象时仅能复制可以遍历属性(枚举属性),不可复制原型属性
可以将多个源对象复制到同一个对象上,完成多个对象的属性合并
方法或者函数本身也是引用关系,因此在是assign时,注意函数
复制后任然是引用关系,因此处理时,函数如果有对象属性时也会发生改变。
Object.defineProperty(目标对象,属性/方法,属性描述对象)
属性描述对象 Descriptor
configurable(英:可配置的,结构的) 是否该属性可删除、描述是否可修改 默认为false,不可删除修改。
enumerable(英:可距离的) 是否该属性可遍历(是否可枚举),默认为false,不可删除
writable(英:可写的) 是否该属性可修改,默认为false,不可修改
value 设置该属性的值,默认为undefined。
访问器属性,如果使用访问器属性,不能设置writable和value值
设置setter函数,设置属性值的函数
set:function (value) {
this._a=value;
},
设置getter函数,获取属性值的函数
get:function () {
return this._a;
}
当对象的有些属性和方法不希望暴露公开,可以设置为不可枚举属性
当对象的某个属性不希望修改,让这个属性成为常量
当对象的某个属性不希望在遍历删除时清空它,就可以设置不可删除属性
封装属性描述对象,增加到Object的原型链上,并默认addKey方法设置成不可修改,不可遍历,不可删除
Object.defineProperty(Object.prototype, "addKey", {
value: function (key, value, enumerable, writable, configurable) {
Object.defineProperty(this, key, {
value: value,
enumerable: enumerable ? enumerable:false,
writable: writable ? writable:false,
configurable: configurable ? configurable:false
})
}
})
defineProperties
Object.defineProperties(obj, props)
给对象定义属性值
Object.defineProperties(对象,{
“属性名”:{
value:属性值,
writab
le:布尔值
}
})
属性名必须是字符串,value后面的内容是属性的值,writable是该属性是否可写。
freeze()
冻结对象,使用该方法以后,不能修改该对象的所有属性,不能删除所有属性。
Object.freeze(obj)
冻结的对象是可以复制的,而且复制后的对象是可以修改的。
一些事件不希望被修改或者删除,一直运行的事件,可以使用freeze冻结这个事件。
getOwnPropertyDescriptor
bootstrap常用单词.note
获取对象下属性的描述,也就是使用defineProperty定义的所有属性的描述内容
获取的对象实际是对象中对于该属性的描述对象的复制对象,而不是引用对象
也就是说如果修改这个获取到描述对象,不会影响到原始对象中对于该属性的描述
var desc=Object.getOwnPropertyDescriptor(obj,names[0]);
getOwnPropertyNames
获取对象下所有属性的名称,并返回一个数组,
该数组的内容就是这些属性名,该数组对元素是 obj 自身拥有的枚举或不可枚举属性名称字符串。
数组中枚举属性的顺序与通过 for...in 循环(或 Object.keys)迭代该对象属性时一致。
原型中的属性不可获取
var obj={a:1,b:2,c:3}
var arr=Object.getOwnPropertyNames(obj);
打印显示的是[a,b,c]
通过获取对象属性名称和对象属性的描述进行深拷贝
function cloneObj(targetObj,sourceObj) {
var names=Object.getOwnPropertyNames(sourceObj);
for(var i=0;i<names.length;i++){
var desc=Object.getOwnPropertyDescriptor(sourceObj,names[i]);
if(typeof desc.value==="object" && desc.value!==null){
var obj=new desc.value.constructor;
cloneObj(obj,desc.value);//把obj当成引用对象带入递归函数继续给obj赋值
Object.defineProperty(targetObj,names[i],{
enumerable:desc.enumerable,
writable:desc.writable,
configurable:desc.configurable,
value:obj
});
continue;
}
Object.defineProperty(targetObj,names[i],desc);
}
return targetObj;
}
判断方法集合
Object.is(value1, value2);判断两个对象或者两个内容是否相等,
这种相等性判断逻辑和传统的 == 运算符所用的不同,== 运算符会对它两边的操作数做隐式的类型转换
(如果它们是不同类型的值的话),然后才进行相等性比较,(所以才会有类似 "" == false 为 true 的现象),
但 Object.is 不会做这种类型转换。
Object.isExtensible(obj) 判断一个对象是否是可扩展的(是否可以在它上面添加新的属性)。
Object.isFrozen(obj)判断一个对象是否被冻结 frozen。
setter与getter
访问器属性
getter和setter
Getters和Setters使你可以快速获取或设置一个对象的数据。
一个对象属性拥有两个方法,分别用于获取和设置某个值,
你可以用它来隐藏那些不想让外界直接访问的属性。一个对象内,每个变量只能有一个getter或setter。
当给一个属性设置值时,可以写入多条语句,可以解决若干个问题设置值等同于执行一个函数,
同样获取值时也可以执行一个函数
解决多个问题
删除getter或setter的唯一方法是:delete object[name]。delete可以删除一些常见的属性,getters和setters。
1、对数据的访问限制:a.value是对value变量的getter方法调用,如果在getter方法实现中抛出异常,
可以阻止对value变量的访问
使用场景
1、前端和服务端通信后获得发来数据结果时,通过setter属性可以直接
设置返回过来的结果来改变显示内容,只能使用这个数据设置一个入口
来完成改变多个显示内容的变化
2、从外容器将数据传递进入子容器时,或者从外向内设置值。或者给组件设置初始值时
var obj={
_age:10,
set age(value){
this._age=value;
},
get age(){
return _age;
}
}
setter
每个setter设置一个属性的时,必须有一个参数value,并且,
我们需要用一个外部变量来接收这个参数,用于保存。因此setter写法基本固定于
set 属性名(value){
存储用的内部属性名=value;
。。。。当设置这个属性后随之需要的操作
}
getter
每个getter是获取一个属性,因此,必须有一个return返回内部存储的值
get 属性名(){
。。。当获取这个属性时需要操作的内容
return 内部存储的这个属性;
}
注意
注意setter和getter设置的属性一般是成对出现,对应的相应属性。
如果仅出现set,没有使用get,表示该属性只写,不能获取,如果仅出现get没有出现set,表示该属性只读,不可写值。
最后说明,setter和getter虽然很好用,但是目前ie不支持,使用的时候要注意。
数据结构
数组
所谓数组,是无序的元素序列。 若将有限个类型相同的变量的集合命名,
那么这个名称为数组名。组成数组的各个变量称为数组的分量,也称为数组的元素,
有时也称为下标变量。用于区分数组的各个元素的数字编号称为下标。数组是在程序设计中,
为了处理方便, 把具有相同类型的若干元素按无序的形式组织起来的一种形式。
这些无序排列的同类数据元素的集合称为数组。
集和多重集
某些指定的对象集在一起就是集合。一定范围的,确定的,可以区别的事物,
当作一个整体来看待,就叫做集合,简称集,其中各事物叫做集合的元素或简称元。
如
(1)阿Q正传中出现的不同汉字
(2)全体英文大写字母。任何集合是它自身的子集。一般的,把一些能够确定的不同的对象看成一个整体,
就说这个整体是由这些对象的全体构成的集合(或集)。
Object就是集,对象下的属性就是元,多重集就是复杂对象{1,2,3}是一个集合,
{{1,1,1},{2,2},3}而不是一个集合,而是一个多重集。
散列表
散列表(Hash table,也叫哈希表),是根据关键码值(Key value)而直接进行访问的数据结构。
也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。
这个映射函数叫做散列函数,存放记录的数组叫做散列表。
给定表M,存在函数f(key),对任意给定的关键字值key,
代入函数后若能得到包含该关键字的记录在表中的地址,则称表M为哈希(Hash)表,函数f(key)为哈希(Hash) 函数。
实际我们的obj也是一种散列表
树tree
树状图是一种数据结构,它是由n(n>=1)个有限节点组成一个具有层次关系的集合。
把它叫做“树”是因为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的。它具有以下的特点:
每个节点有零个或多个子节点;没有父节点的节点称为根节点;
每一个非根节点有且只有一个父节点;除了根节点外,每个子节点可以分为多个不相交的子树;[1]
链表
链表是一种物理存储单元上非连续、非顺序的存储结构,
数据元素的逻辑顺序是通过链表中的指针链接次序实现的。链表由一系列结点(链表中每一个元素称为结点)组成,
结点可以在运行时动态生成。每个结点包括两个部分:一个是存储数据元素的数据域,
另一个是存储下一个结点地址的指针域。 相比于线性表顺序结构,操作复杂。
由于不必须按顺序存储,链表在插入的时候可以达到O(1)的复杂度,比另一种线性表顺序表快得多,
但是查找一个节点或者访问特定编号的节点则需要O(n)的时间,
而线性表和顺序表相应的时间复杂度分别是O(logn)和O(1)。
堆栈
堆栈在多个领域当中都有,我们这里介绍一下,缓存方式和数据结构两种。
堆(数据结构):堆可以被看成是一棵树,如:堆排序。
栈(数据结构):一种先进后出的数据结构。
栈使用的是一级缓存, 他们通常都是被调用时处于存储空间中,调用完毕立即释放。
堆则是存放在二级缓存中,生命周期由虚拟机的垃圾回收算法来决定(并不是一旦成为孤儿对象就能被回收)。
所以调用这些对象的速度要相对来得低一些。
this
普通函数中的this
在普通函数中,this是表示window
console.log(this)
function abc(){
console.log(this);
function a(){
console.log(this);
}
a();
}
abc();
事件中的this
在事件侦听和触发过程中,执行事件触发的函数,我们称为事件处理函数,
在该函数中我们获取的this是触发事件的对象
bn.addEventListener(“click”,clickHandler);
function clickHandler(e){
console.log(this);
}
bn.onClick=function(){
console.log(this);
}
但是我们可以利用函数绑定,改变this,
例如bn.addEventListener(“click”,clickHandler.bind(this));
类中的this
当函数被实例化后,函数就是类的构造函数了,这个时候,
函数中的this就是被实例化的对象本身了。
function Ball(){
console.log(this);
}
var obj=new Ball();
函数call以后替代执行的this
使用函数的方法call,替代执行方法。关于call部分,
我们后面详细讲解该内容,但是在这里我们先做一下该部分this的说明
function fun2(){
console.log(this);
}
function fun1(callBack){
var obj={a:1};
callBack.call(obj);
}
fun1();
这个时候this是obj对象。