JavaScript面向对象之对象

对象

什么是对象
    什么是对象,其实就是一种类型,即引用类型。而对象的值就是引用类型的实例。
    在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对象。
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值