JS面向对象

面向对象

对象:现实中一切事物皆为对象

面向对象的实体:包含属性和行为的集合

js没有类的概念,叫做对象,思想上是基于对象的,js下定义对象还是用函数体进行定义,

基于对象和面向对象的区别

面向对象:自己设置图纸,照着图纸盖房子

基于对象:别人有一个房子,我照着房子创建

面向对象的三大特征:封装、继承、多态

封装

每一个对象就是一个封装,把具有共同属性和行为的事物放在一起

定义对象

var a -->饿汉式

a=11

var a=11 -->懒汉式
  • 通过Object创建
var p=new Object()

        p.name="小明"//创建变量

        p.age=22

        p.say=function(){//创建方法

            console.log("我叫"+p.name,p.age)

        }

        p.say()//调用方法
  • 简写
var p={

            name:"小明",

            age:23,

            say:function(){

                console.log(this.name,this.age)

            }

        }

        p.say()

属性操作

configurable是否可以通过dalete删除

enumerable是否可以通过for-in进行遍历

writable是否可以修改属性

value给属性添加默认值

get获取属性的方法

set设置属性的方法

思想:限定陌生人不能操作,但是自己可以通过get和set访问

例如:

限定属性:

var obj={name:"小明",age:13}

Object.defineProperty(obj,"name",{

        configurable:false,

         writable:false,

             value:"小兰"

         })

   设置get,set:

var obj={_name:"小明",age:13}

       Object.defineProperty(obj,"name",{

           configurable:true,

           writable:false,

           enumerable:true,

           value:"小兰",

           get:function(){//获得变量

               return this._name+"111"

           },

            set:function(name){//修改变量

                 this._name=name

            }

         })

设置多个属性:

 var obj={_name:"小明",age:13}

        Object.defineProperties(obj,{

            name:{writable:false,},

            age:{enumerable:false}

        })

注意: writable 不能和set一起用,  enumerable不能和get一起用

自己创建get和set方法

 var obj={

            name:"小敏",

            age:22,

            getName:function(){

                return this.name

            },

            getAge:function(){

                return this.age

                

            },

            setName:function (name) {//外界

                this.name=name//内部

            },

            setAge:function(age){

                this.age=age

                

            }

        }

        console.log(obj.getName(),obj.getAge())

        obj.setName("小红")

        obj.setAge(34)

        console.log(obj.getName(),obj.getAge())

构造器

用来给对象赋初始值,构造器是一种特殊的函数,如果不写,js会自动分配一个默认无参的构造器

例如:

new关键字具体做了什么

  1. 创建了一个新对象
  2. 将构造器的作用域赋给新对象
  3. 用this关键字指向这个对象
  4. 通过proto寻找父类对象
    function Emp(name,age) {//构造器
    
                this.name=name
    
                this.age=age
    
                this.say=function(){
    
                    console.log(this.name,this.age)
    
                }
    
            }
    
     var e=new Emp("小丽",21)//调用构造器
    
    e.say()
    
            console.log(e)
    
            var obj={}
    
            console.log(obj)
    
            e.name="小米"
    
            e.say()

  5. 返回新对象给调用者

私有变量

在对象下变量通过this关键字进行执行,表示通过地址找到对象下的属性和方法,如果要定义私有变量的属性和方法,可以不通过this关键字定义

例如:

function Emp(age){

            var name="小明"//私有变量

            this.age=age

        }

        var e=new Emp(22)

        console.log(e.age)

        console.log(e.name)

this指向

this关键字用于对象体内,用来指向对象下的属性和方法,方便调用

Global:在node环境下this的全局作用域指向Global

Window:在浏览器环境下this的全局作用域指向window

例如:

var a=11

console.log(a)

console.log(window.a)

console.log(this.a)

this的指向和在哪定义,在哪执行都没有关系

函数执行时,看函数前面是否有”.”,有的话,”.”前面是谁就指向谁,如果没有,就指向window

例如:

var name="我是window"

            var obj={

                name:"我是obj",

                info:function(){

                    console.log(this.name)

                }

            }

            console.log(obj.name)//obj

            console.log(window.name)//window

            console.log(name)//window

特殊情况

  1. 当this出现在匿名函数里,永远指向的是window

  例如:

 var name="我是window"

             var obj={

                name:"我是obj",

                info:function(){//匿名函数

                   return function(){return this.name

                   }

                }

            }

            var v= obj.info()()

            console.log(v)//window

2.当给一个dom元素绑定一个事件的时候,事件执行的方法,this指向的是当前元素

 btn.onclick=function(){

             this.name=222

            console.log(this)//指向btn按钮

            console.log(this.name)

        }

改变this指向 

var name="我是window"

            var obj={

                name:"我是obj",

                info:function(){//匿名函数

                var th=this//在obj环境下存一个对象

                return function(){

                       return th.name//window

                   }

                }

            }

           var v= obj.info()()

           console.log(v)//obj

继承

当子类继承父类对象时,可以直接拿到父类下的属性和方法,无需自己重新定义,减少代码写作,js下是单继承,用原型链实现

原型链

每个构造器都有一个原型对象,原型对象包含一个指向构造器的指针,name我们让原型对象指向另一个对象示例,就会实现机制

例如:

function Father(){

            this.name="张三"

            this.say=function(){

                console.log(this.name)

            }

        }

        function Son(){

            this.age=23

        }

        Son.prototype=new Father()//继承

        var s=new Son()

        console.log(s)

        console.log(s.age)

        console.log(s.name)//可以调用父类对象的属性和方法

        s.say()

多态-重写

子类和父类下有相同的方法。执行不同的操作,默认执行过程是,先找自己下的属性或方法执行,没有则去父类下找属性和方法,如果出现重名情况,则子类会覆盖父类的方法

function Father(){

            this.name="张三"

            this.say=function(){

                console.log("唱京剧")

            }

        }

        function Son(){

            this.age=23

            this.say=function(){

                console.log("唱流行歌曲")

            }

        }

        Son.prototype=new Father()//继承

        var s=new Son()

        console.log(s)

        s.say()//调用自己的方法,覆盖了父类的

改变this指向的方法->call,apply,bind

三个函数本身是用来改变this指向的可以在任何对象下使用,在继承关系里,我们来调用父类构造器,只是定义上有区别

调用对象.call(改变的对象,值1,值2....)call定义多个参数

调用对象.apply(改变的对象,[值1,值2....])apply只定义对象和数组

调用对象.bind(改变的对象,值1,值2....)bind返回一个函数自己手动执行

例如:

function Father(name,sex){

            this.name=name

            this.sex=sex

        }

        function Son(name,sex,age){

            this.age=age

            // Father.call(this,name,sex)

            // Father.apply(this,[name,sex])

              Father.bind(this,name,sex)()

         

        }

        Son.prototype=new Father()//继承

        var s=new Son("小明","男",23)

        console.log(s.age)

        console.log(s.name)//可以输出构造器里的赋值

        console.log(s.sex)

        console.log(s)

原型链的关键字

prototype:用来指向对象原型

_proto_:用来指向当前实例所属对象

constructor:用来指向构造器

实例有_proto_关键字,对象有prototype和constructor,构造器会有prototype

 

对象下的属性和方法

In判断属性是否属某个对象

Object.defineProperty()限定对象的属性操作

Object.defineProperties()限定对象的多个属性操作

Instanceof判断是否属于某个对象

Object.getPrototypeOf()获得对象原型

Object.isPrototypeOf()判断对象是否存在另一个原型上

Object.getOwnPropertyNames()返回对象下所有属性

Object.hasOwnProperty()判断对象自身是否有指定属性

Object.keys()返回对象可枚举的属性

Object.prototype.propertyIsEnumerable()判断是否是可枚举属性,返回布尔值

//console.log(s.prototype.propertyIsEnumerable("sex"))

Object.freeze()冻结一个对象,(只能查询)

//Object.freeze(obj)

Object.isFrozen()判断是否制冻结对象

Object.seal()密封一个对象,(只能查询和修改)

//Object.seal(obj)

Object.isSeal()判断是否是密封对象

Object.preventExtensions()让对象不可扩展(不能添加)

//Object.preventExtensions(obj)

Object.isExtensible()判断是否是不可扩展的对象

判断数组的方法有哪些

  1. Instanceof判断,但是会判断出父类对象

console.log(x instanceof Date)

  1. IsArray()Es5后新增的方法

console.log(Array.isArray(x))

  1. 通过构造器判断,每个对向都有自己的构造器

console.log(x.constructor==Array)(构造器)

  1. 通过prototype判断,如果是实例可以改变this指向

console.log(Object.prototype.toString.call(x)=="[object Array]")

  1. getPrototypeOf()返回原型进行判断

console.log(Object.getPrototypeOf(x)==Array.prototype)

判断对象的方法有哪些

同上,没有isArray()方法

typeof emp==”Object”//缺点null也会验证为对象

判断对象下的属性有哪些

  1. in 验证包括自身和原型的属性
function f(){

            this.name="zhang"



        }

        function s(){

            this.age=12

        }

        s.prototype=new f()

        var v=new s()

console.log("name" in v)//true
  1. hasOwnProperty验证自身对象的属性

console.log(v.hasOwnProperty("name"))//false

  1. 判断是否是undefined,验证包括自身和原型的属性

console.log(typeof v.age=="undefined")//false

console.log(v.name==undefined)//false

遍历对象的方法有哪些

  1. for in遍历 包括自身可枚举的和原型的属性

for(var k in v){

            console.log(k,v[k])

          }

    2.Object.keys()遍历自身属性

console.log(Object.keys(v))

    3.Object.getOwnPropertyNames()遍历自身可枚举和不可枚举属性

          console.log(Object.getOwnPropertyNames(v))

对象的复制

深拷贝和浅拷贝

浅拷贝:在引用变量赋值给另一个变量时,引用的是一个堆内存地址,当一个变量改变时,另一个变量跟着改变

深拷贝:在引用变量赋值给另一个变量时,开辟了一个新的堆内存地址,当一个变量改变时,另一个变量不改变

  1. 自己遍历,实现深拷贝
var obj={age:12,name:"zhang"}

            var o={}

            for(var v in obj){

                o[v]=obj[v]

            }

            obj.name="ss"

            console.log(obj)

            console.log(o)
  1. 借助数组的函数,凡是可以返回新数组的函数,都可以执行赋值
 var x=[1,2,3]

            var y=x.concat()

            x[0]=66

          console.log(x)//[66, 2, 3]

            console.log(y)// [1, 2, 3]
  1. 借助Object对象下的方法

var o=Object.assign(obj)//复制对象,实现浅拷贝

var o=Object.create(obj)//创建对象,实现深拷贝

  1. ES6下扩展运算符(...)

var x=[1,2,3]

var y=[...x]

        x[0]=22

        console.log(...x)//22 2 3

        console.log(y)//[1,2,3]

  1. Json数据格式

JSON.parse()转化成对象

JSON.stringify()对象转化成json

//var obj={name:"li",agr:12,color:["red","blue"],y:{a:1,b:2,c:3}}

 console.log(obj) console.log(JSON.stringify(obj))//{"name":"li","agr":12,"color":["red","blue"],"y":{"a":1,"b":2,"c":3}}

缺点:对象的属性如果是symbol类型是无法复制的

var obj={name:"li",agr:12,color:["red","blue"],y:{a:1,b:2,c:3}}

var json=JSON.stringify(obj)

var o=JSON.parse(json)

定义对象有哪些方式

  1. 工厂模式

  function Person(name){

            var o=new Object()

            o.name=name

            o.say=function(){

                console.log(o.name)

            }

            return o

         }

优点:能够解决创建多个对象的问题,兼容各个浏览器

缺点:没有解决对象识别的问题,不知道一个对象的具体类型

    2.构造函数模式

  function Person1(name){

            this.name=name

            this.say=function(){

                console.log(o.name)

            }

        }

优点:可以创建多个对象解决对象识别问题

缺点:每个对象都会创建不同function实例,如果完成同样的任务就没有必要。

    3.原型模式

  function Person(){}

       Person.prototype.name="xiaoming"

       Person.prototype.say=function(){

           console.log(o.name)}

优点:不用构造器传参,可以同时创建多个对象

缺点:原型的数据被共享,当属性被改变时,所有实例都改变

   4.组合使用构造器和原型模式

 function Person(name){

            this.name=name

        }

       Person.prototype={

           constuctor:Person,

           say:function(){

               console.log(this.name)

           }  

       }

优点:每个实例都有自己的属性副本,同时又共享了方法,既可以节省内存,又可以赋值

 5.动态原型模式

 function Person(name){

            this.name=name

            if(typeof this.say!="function"){

                    Person.prototype.say=function(){

                        console.log(this.name)

                    }

            }

        }

优点:满足组合模式的所有优点,并且代码比较规整,统一初始化

  6.寄生构造函数模式

  function toStrarr(){

        var arr=new Array()

        arr.push.apply(arr,arguments)

        arr.topstr=function(){

            return this.join("|")

        }

        return arr

}

优点:类似于工厂模式,用来给原型对象定义新的属性和方法,而无需自己创建新对象,节省内存。

  7.稳妥构造函数模式(最好的)

function Person(name){

        var o=new Object

        o.name=name

        _age=23

        if(typeof o.say!="function"){

            o.say=function(){

                console.log(this.name)

        }

    }

        return o

}

优点:可以定义私有变量,可以共享函数,可以节省内存,可以构造器赋值,代码更安全。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

兔子^-^

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值