JavaScript里的面向对象心得

1、面向对象的概念

面向对象是一种编程思想编程

对象:能够添加属性(变量)和方法(函数);
面向对象写法特色:数组

一、把功能写成一个函数;
    二、函数必须写在对象身上,调用的时候直接拿对象.方法名();
    三、对象身上的功能能够继承;
    四、this指向,在事件或者定时器里面是访问不到真正的this的,须要在外面存一下;
写法示例:
        function 构造函数 (){
            this.属性=??;
        }
        构造函数.prototype.方法=??;
        
        var 实例=new 构造函数();
        实例.方法();

2、new的做用

一元运算符,后面只能接函数,用来调用函数;数据结构

用new调用函数的过程:模块化

一、构建一个空对象;
    二、把函数内部的this指向建立的对象;
    三、在函数执行完之后自动返回刚才建立的那个对象,即便函数里面没有return;假如函数后面有return的话会有两种状况:
        A 、return后面是对象的话,则返回这个对象;
        B 、return后面是非对象的话,则返回一开始new建立的对象;

注意:函数

一、用new调用的函数永远返回一个对象,无论有没有返回值;
    二、用new调用函数,这个函数必定是用来建立对象的,叫作构造函数;

3、构造函数

建立并初始化对象的函数,而且必须用new调用,否则和普通函数没有区别;性能

functon Person(name,age){
            this.name=name;
            this.age=age;
            this.say=function{
            console.log("my name is"+this.name);
            };
        };

new出来的都是构造函数的实例,构造函数就是实例化的过程;
构造函数的问题:性能问题会形成资源浪费;this

4、原型 prototype

概念:函数身上的属性,每一个函数都有,它的值是一个对象;prototype

用途:由于它是一个对象,因此身上能够放属性和方法,若是与构造函数相结合,经过构造函数建立的对象就会具备原型身上的属性和方法;code

建议把一些共用的属性和方法放在构造函数的原型身上;对象

5、__proto__

对象身上的属性,每一个对象都有这个属性;它的值也是一个对象,它的值就是它对应的构造函数的prototype的值;

实例.__proto__===构造函数.prototype;这句话解释了为何实例可以继承构造函数身上的属性和方法;

functon Person(name,age){
        this.name=name;
        this.age=age;
    };
    this.prototype.say=function{
    console.log("my name is"+this.name);
    }; 
                
    var p1=new Person("peter",18);
在这个例子中:p1.__proto__=Person.prototype;因此p1才能继承Person构造函数身上的属性和方法;

6、原型链

对象与原型之间的关系(连接)

原型链查找规则:

7、包装对象

  • 在js中,当咱们去调用字符串,布尔值,数字的属性和方法的时候,js会在内部把这些基本数据类型转变成一个对应的对象类型(包装对象),而后再调用这个包装对象的属性和方法;
  • 包装对象有:

    • String
    • Number
    • Boolear
  • 注意:

    • null和undefined没有包装对象;
    • 基本数据类型只能使用对应的包装对象身上的属性和方法;

8、hasOwnProperty

做用:判断一个属性是否是本身对象身上的;

语法:对象.hasOwnProperty(属性);

参数:要检测的属性;

返回值:

**true**         *自身属性*
**false**        *非自身属性*

注意:

一、这个方法是Object身上的方法    
二、不会顺着原型链往外面去查找属性,只查找自身

9、constructor

概念: 每一个对象身上都会有这个属性,默认指向该对象对应的构造函数;
这个属性不是放在对象身上,放在对应的原型对象身上;

做用:查看对象的构造函数;

语法:对象.constructor;

返回值:对象的构造函数;他能够用来作数据类型的判断;

constructor的问题    :constructor的值是能够修改的;
 
    function Person(name){
        this.name=name;
    }
    var p1=new Person('kaivon');
    console.log(p1);
    console.log(p1.constructor==Person);    //true
            
    p1.constructor=Array;
    console.log(p1.constructor==Array);        //true

10、 toString

做用:把对象类型转成字符串;

注意:系统对象身上的这个方法都是在对应的原型身上;而本身写的构造函数这个方法在达的Object原型身上

它能够用来作类型判断:

Object.prototype.toString.call( );

//用toString作类型判断
        var num=0;                  //[object Number]
        var str='kaivon';           //[object String]
        var b=true;                 //[object Boolean]
        var n=null;                 //[object Null]
        var u=undefined;            //[object Undefined]
        var arr1=[];                //[object Array]
        var obj1={};                //[object Object]
        var fn=function(){};        //[object Function]
        var d=new Date();           //[object Date]
        var re=new RegExp();        //[object RegExp]
        
        console.log(Object.prototype.toString.call(num));

11、浅拷贝与深拷贝

基本数据类型复制:

var num1=123;
var num2=num1;//那么num2和num1就是同样的,**复制了值**

复杂数据类型复制的问题:

var arr1=[1,2,3];
var arr2=arr1;

arr2.push(4);
//注意这个时候arr1和arr2的值;
console.log(arr2);              //[1,2,3,4]
console.log(arr1);              //[1,2,3,4]

arr1和arr2同样的缘由:复杂数据类型复制的时候不只仅是复制了值,还复制了引用地址,因此修改arr2时,那么arr1的地址和arr2其实仍是同样的,因此arr1的值也相应改变了;

思考:那么咱们应该如何复制复杂数据类型?

浅拷贝

var obj1={a:10,b:20};               //如何复制呢?

function copy(obj){
    var newObj={};
    for(var attr in obj){
        newObj[attr]=obj[attr];
    }
    return newObj;
}
var obj2=copy(obj1);
//这时候的obj2和obj1看起来是同样的,可是实际上是不一样的,有不一样的引用地址;

深拷贝

深拷贝和浅拷贝的区别:
一、当要复制的那个对象里面全部的值都是非对象的时候,用浅拷贝;
二、当要复制的那个对象里面有对象的时候,用深拷贝;

var obj1={
    a:10,
    b:{
        c:20    //这时候对象里面还有对象;这时候怎么办呢?
    }
}

//若是这时候还用上面的浅拷贝的话,那么修改复制后的值,原来对象里面的值也仍是会改变,因此要用下面的办法;

function deepCopy(obj){
    if(typeof obj!=="object"){
        return obj;
    }
    //上面的代码是给了一个跳出条件,当传入的条件不是对象的时候就不须要递归了;
    if(obj instanceof Array){
        var newObj=[];
    }else{
        var newObj={};
    }
    for(var attr in obj){
        newObj[attr]=deepCopy(obj[attr]);
        //递归;当对象里面的值仍是对象的时候须要用到;
    }
    return newObj;
}

12、继承

概念:

让一个对象拥有另外一个对象的属性和方法,而且本身添加的属性和方法不会影响原来的对象;

属性继承:

经过call的方法调用构造函数来继承属性;

function Person(name,age){
                this.name=name;
                this.age=age;
            }
Person.prototype.say=function(){
                console.log('我叫'+this.name);
            }
//Person至关于一个大类,Coder至关于一个小类,他们是有共同的地方的;
function Coder(name,age,job){
                this.name=name;
                this.age=age;
                this.job=job;
            }
Coder.prototype.say=function(){
                console.log('我叫'+this.name);
            }
//经过属性继承,咱们能够将小类和大类共同的部分简化以下:
function Coder(name,age,job){
                Person.call(this,name,age);
                
    //若是不用call的话,那么this的指向就是window了,因此要用call将指向指到当前的this上面;
                this.job=job;
            }

方法继承:

经过for in 想要继承的构造函数的原型的方法去去继承;

参考属性继承?的代码:

for (var attr in Person.prototype){
    if(Person.prototype.hasOwnProperty(attr)){
        Coder.prototype[attr]=Person.prototype[attr];
    }
}

十3、组件

概念

把一个效果或者方法用面向对象的方法封装起来,只提供给用户一些相关的方法和数据接口;(模块化

特色

易扩展易维护相互之间没有影响

组件的组成:

1、配置参数

放在初始化函数里;

  • 初始化函数放在构造函数的原型身上,通常用init表示
  • 须要写一个默认参数放在构造函数里面;
function Drag(obj){
    this.disX=0;
    this.disY=0;
    //下面的就是默认参数,下面的函数都要用下面的参数;
    this.settings={
        id:"",          //这是必传的;
        downFn:function{},
        moveFn:function{},
        upFn:function{}
    }
}
//下面这个叫作初始化函数;
Drag.prototype.init=function (opt) {
    //在初始化函数里面,拿用户输入来的参数覆盖默认参数;
    for(var attr in this.settings){
        if(this.settings.hasOwnProperty(attr)){
        //若是默认参数里面有这个属性的话,才会去覆盖;
            this.settings[attr]=opt[attr];
        }
    }
    this.obj=document.getElementById(this.settings.id);
}
//用户传进来的就叫作配置参数;是一个对象;

2、方法

放在原型里的函数;

3、自定义事件

  • 概念:

    • 除了系统自带之外的事件叫作自定义事件;
    • 有利于多人协做开发,可扩展js事件;
    • 须要用到事件绑定,事件触发器;
    • 自定义事件其实就是调用函数,在指定的环境下让事件触发;
  • 自定义事件三要素:

    • 对象;
    • 事件名;
    • 事件处理函数;
  • 能够利用对象数据结构里面的key:value键值对的方式去把事件名和事件处理函数联系起来; 把多个函数放到一个数组里面,循环数组里面的每一个函数;
//定义事件
object.events={
    "事件名1":[fn1,fn2],
    "事件名2":[fn3,fn4,fn5]
}

//调用事件(循环去调用)
  • 代码实现示例
//事件绑定器,添加自定义事件;
function customEvent(obj,eventName,fn){
    /*  obj         对象名;
     *  eventName   对象的一个事件名,它的值是一个数组;
     *  fn          事件调用函数,它在数组里面;
     */
    //这里的"||"逻辑符号的意思是左边为真走左边,左边为假走右边;
    obj.events=obj.events||{};
    obj.events[eventName]=obj.events[eventName]||[];
    obj.events[eventName].push(fn);//push方法把函数添加到数组;
}
//事件触发器;
function(obj,eventName){
    //触发的时候要看看对象身上有没有这个事件;
    if(obj.events[eventName]){
        for(var i=0;i<obj.events[eventName].length;i++){
            obj.events[eventName][i].call(obj);
            //注意this的指向,要指向这个obj;
        }
    }
}
相关文章
相关标签/搜索