频道栏目
首页 > 资讯 > JavaScript > 正文

js面向对象编程读书笔记

17-08-21        来源:[db:作者]  
收藏   我要投稿

面向对象编程OOP object oriented object

对象:
实质上的事物、可以是任何的东西 包含属性和方法

把部分对象的的共同特征的抽象
封装
封装的内容一般有:1、相关的数据 2、基于这些数据的方法
封装的结果就是暴露给其他对象一个操作这些数据的方法
聚合
将一个复杂的对象分解为多个简单的对象
继承
优雅的实现代码的重用,但是js中没有具体的类,所以有继承关系的只能是对象之间
多态
worker继承了person的全部的方法,这就意味这在这个类中实现了不同的talk()方法,当各自类生成的对象调用这个talk方法的时候,会实现各自的功能,这个现象就是多态。

js的基本5大数据类型

数字、字符串、布尔值、undefined、null
undefined和null的区别
js试图访问某个不存在的或者是没有经过赋值的变量,就会得到一个undefined
1+undefined undefined
1+null 1

函数

什么是函数:代码的一种分组形式。
参数:传递给函数多余的参数,函数会自动省略掉没有用的参数,可以利用函数的滋生的属性arguments这个数组来访问参数
预定义函数
js中已经预定了一些函数,parseInt()、parseFloat()、idNaN()。。。。。
isNaN() 判断一个值是否是可以参与运算的数字
encodeURI
eval()
变量作用域
js中不能为变量定义特定的块级作用域,但是可以为其定制特定的函数域
如果变量是定义在某个函数中,在函数之外这个变量是不可见的
如水果是定义在if或者for语句中,这个变量在外界是可见的
匿名函数
匿名函数的作用:
1、可以将匿名函数作为参数传递给其他的函数,接收方就能利用我们所传递的函数来完成某些事情
2、定义某个匿名函数来完成某些一次性的事情
回调函数
将函数作为参数传递给另一个函数,可以理解为一个函数调用操作交给了另一个函数
自调函数
在一个函数后边加一个()就会自己调用一边
内部函数
想要函数A里边有一个函数B当调用函数A的时候B也会被调用,必须在函数A定义的时候B能够被调用。
函数和函数对象的区别

    var aa=new function (){this.a="fun"};
     var cc=function (){this.a="ccFun"};
     console.log(typeof cc);
     console.log(typeof aa);

aa是一个函数 cc是一个函数对象 call方法切换的对象的上下文。
call方法和apply方法
call方法(obj,arg1,arg2)
这个方法可以代替另一对象obj调用一个方法。 将一个函数的对象上下文从初始的上下文改变为this.obj的上下文,

  var aa=new function (){this.a="fun"};
    function  bb(x) {
        var a="myfun";
        console.log(this.a);
        console.log(x);
    }
    bb.call(aa,3);    //fun   3

调用bb的时候函数的上下文被切换到aa中,所以a被赋值为fun
apply方法(obj,[arguments])和call的功能一样但是传递的参数是不一样的

    var aa={
         a:"12121"
     };
    function  bb(x) {
        var a="myfun";
        console.log(this.a);
        console.log(x);
    }
    bb.apply(aa,[3]);   //12121  3

调用call和apply以后将obj的所有的属性和方法都给了调用的这个

 var base={
      member:'qq',
      xx:function(){
      console.log(111);
  }
  }
    function extend() {
        console.log(this.member);
        console.log(this.xx);
    }
    extend.call(base);

上面的程序和下面的程序的运行效果一致

   function base() {
        this.member='qq';
        this.xx=function(){
            console.log(111);
        }
    }
    function extend() {
        base.call(this);   //extend会继承base所有的属性和方法
        console.log(this.member);
        console.log(this.xx);
    }
    extend();

闭包

通过闭包可以突破js的函数作用域链:函数内部定义一个函数返回一个函数内部的变量 外部就可以访问这个变量

 var n;
     var aa=function (){
         var b="cc";
         n=function() {
            return b;
        }
     }
    aa();   /aa必须先执行一遍
    console.log(n());   //将b升级成了全局的变量,突破了js的作用域链

一个函数需要在其父级函数之后留住对父级作用域链的话,此时就是用闭包。。
循环中的闭包

     var aa=function (){
        var a=[];
         var i;
         for(i=0;i<3;i++){
             a[i]=function () {
                 return i;
             }
         }
         return a;
     }
    var xx=aa();
    console.log(xx[0]());
    console.log(xx[1]());
    console.log(xx[2]());

没有输出对应的1 2 3
下面的这个程序是正确的

     var aa=function (){
        var a=[];
         var i;
         for(i=0;i<3;i++){
             a[i]=(function (x) {
                 return function(){
                     return x;
                 };
             })(i)
         }
         return a;
     }
    var xx=aa();
    console.log(xx[0]());
    console.log(xx[1]());
    console.log(xx[2]());

会输出 0, 1 ,2
定义一个将变量本地化的函数MakeLocal()

 function makeLocal(x){
        return function (){
            return x;
        }
    }
     var aa=function (){
        var a=[];
         var i;
         for(i=0;i<3;i++){
             a[i]=makeLocal(i)
         }
         return a;
     }
    var xx=aa();
    console.log(xx[0]());
    console.log(xx[1]());
    console.log(xx[2]());

依然会输出0,1,2
设置secret变量的set和get的操作,这样secret变量就不可被直接访问

  var getValue,setValue;
  (function(){
      var secret=0;
     getValue=function (){
          return secret;
      };
      setValue=function (v){
          secret=v;
      }
  })();
    setValue(3);
    console.log(getValue());   //3

练习:
1、编写一个将16进制的字符串转换为颜色 将0000FF转换为0,0,255

function ge(value1,value2){
         var result=Math.pow(16,0)*value1+Math.pow(16,1)*value2;
         return result;
     }
     function getRGB(jinzhi){
         var zu=[];
         for(var i=0;i

对象

构造函数,通过constructor能够得到构造器属性

   function A(name){
       this.name=name;
   }
    var aa=new A('juan');
    console.log(aa.constructor)     //得到function  A这个函数

instanceof操作符
判断某个对象是不是某个类的实例

   function A(name){
       this.name=name;
   }
    var aa=new A('juan');
    console.log(aa instanceof A);

传递对象
当我们拷贝某个对象或者将它传递给一个函数的时候,其实就是传递这个对象的引用,对这个对象的操作都会实质性的改变这个对象。
对象之间的比较
当我们对对象进行比较的时候,当且仅当两个引用指向同一个对象时为true;

var A={name:1};
    var B={name:1};
    console.log(A==B)   //false

两个对象的引用不同,所以输出为false

内置对象

数据封装类对象 Object Array Boolean Number String
工具类对象 Math Date RegExp
错误类对象
Object
所有对象的父级对象
属性 constructor 返回构造属性 所有的构造属性都是只读的,不能被改变
方法 1、tostring() 2、valueOf()

    var A=[1,3,4]
    console.log(A.valueOf())  //[1, 3, 4]
    console.log(A.toString())  //1,3,4

Array
属性 length
方法 sort ,reverse,join,slice,push,splice
Function()
属性
length 参数的个数
caller 会返回一个调用该函数对象的外层函数的引用

  function A(){
      console.log(A.caller) ;
  }
    function B(){
        return A();
    }
   B();   //function B()

在B中执行A的结果就是返回A的caller(也就是B)

原型

每一个对象都有自己的原型

 function A(){
      console.log(1);
  }
   console.log(A.prototype)  //object

通过函数的prototype属性来为函数添加属性和方法

  function A(name){
      this.name=name;
      this.say=function () {
          console.log(this.name);
      }
  }
  var aa=new A('juanjuan');
    aa.say();
  A.prototype.www=function () {
      console.log(111)
  }
  var bb=new A('juanjuan');
  bb.www();

但是只限于添加,并不能改变原来的function中的方法,想要改变原来的对象的方法,可以先将原来对象的方法删除。再在原型上添加方法,这样就实现了改变原来对象方法的功能

var yuan=function (){
        this.say=function (x) {
            console.log(x);
        }
    }
    yuan.prototype.say=function (x) {
        console.log(x+2)
    }
    var yuan1=new yuan();
    yuan1.say(2);
    yuan.prototype.say1=function (x) {
        console.log(x+2)
    }
    yuan1.say1(2);

而且原型可以随时被修改,并且与之相关的对象都会随之改变。
原型只能向对象添加方法,但是不能改变原来的方法。这是因为如果遇上对的自身属性与原型属性同名的时候 自身属性的优先级高于原型属性 如果删除了自身的同名属性,原型上的这个同名属性就会出现

  var yuan=function (){
        this.say=function (x) {
            console.log(x);
        }
    }
    var yuan1=new yuan();
    delete yuan1.say;
    yuan.prototype.say=function (x) {
        console.log(x+2)
    }
    yuan1.say(2);

自身属性和原型属性
通过hasOwnProperty来判断

var yuan=function (name,age){
        this.name=name;
        this.age=age;
    }
    yuan.prototype={
        price:100,
        rating:3
    }
    var yuan1=new yuan("赵文娟",12);
    for(var cc in yuan1){
        console.log(cc+yuan1[cc]);  //谁输出自身和原型的所有的属性
    }
console.log(yuan1.hasOwnProperty("name"));   //true   自身有着个属性
console.log(yuan1.hasOwnProperty("price"));   //false  自身没有这个属性

当前对象是否是另一个对象的原型
isPrototypeOf()函数

    var monkey=function (name,age){
        this.name=name;
        this.age=age;
    }
    var human=function(){}
    human.prototype=monkey;
    var hh=new human();
    console.log(monkey.isPrototypeOf(hh));   //monkey是人类这个对象的原型

神秘的proto连接
我们知道当访问一个在当前对象中不存在属性的时候,原型就会被纳入查找的范围。这个属性就可以指向它的原型,

var monkey=function (){
        this.feeds='香蕉';
        this.breaths='空气';
    }
    var human=function(){}
    var mon=new monkey();
    human.prototype=mon;
    var hh=new human();
    hh.name="juanjuan";
    console.log(hh.feeds);  //香蕉
    console.log(mon.isPrototypeOf(hh));   //true
 console.log(hh.__proto__);  //monkey {feeds: "香蕉", breaths: "空气"}
    console.log(hh.prototype);   //undefined

继承

js中每一个函数都有一个名为prototype的对象的属性 new的时候会创建出一个一个对象,并且通过proto指针来连接原型,这样就形成了原型链
这里写图片描述
通过原型链实现js 中的继承

  function  shape(){
             this.name='shape';
             this.toString=function (){
                 return this.name;
             }
         }
       function TwoDshape(){
           this.name='2Dshape'
       }
       function Trigle(side,height){
           this.name='Trigle';
           this.side=side;
           this.height=height;
           this.getArea=function(){
               return this.side*this.height/2;
           }
       }
         //对对象的prototype属性重写
         TwoDshape.prototype=new shape();
         Trigle.prototype=new TwoDshape();
//对对象的prototype属性重写时,可能会对对象的constructor属性产生一个负面的影响所以
         TwoDshape.prototype.constructor=TwoDshape;
         Trigle.prototype.constructor=Trigle;
        var tt=new Trigle(3,4);
         console.log(tt.toString());    //Trigle
         console.log(tt.getArea())   //6

演示继承的效果 一定要注意的是对prototype完全覆盖以后,会对constructor有影响,所以需要

    TwoDshape.prototype.constructor=TwoDshape;
         Trigle.prototype.constructor=Trigle;

以上的实验结果的分析:
遍历tt对象中的所有属性。没有找到一个叫做toString 的方法。就查看proto所连接的实体,也就是回去TwoDshape的new出来的实体中去找,也没有找到,就会去shape的new的实体找toString这个方法 。同时我们也在原型覆盖之后重新定义了constructor这个属性,所以TwoDshape和Trigle都是本身

    console.log(tt instanceof shape);   //true
      console.log(tt instanceof TwoDshape);   //true
       console.log(shape.prototype.isPrototypeOf(tt))  //true

将需要共享的属性都迁移到原型中
当使用构造创建的属性,每一次的new都会在实体中的多一个这样的属性。所以将共享的属性和方法迁移到原型中是有必要的。

   function  shape(){}
         shape.prototype={
            name:'shape',
             toString:function (){
             return this.name;
         }
         }
       function TwoDshape(){
       }
         TwoDshape.prototype=new shape();
         TwoDshape.prototype.constructor=TwoDshape;
       function Trigle(side,height){
           this.side=side;      //因为这个属性是每一个实体独有的属性
           this.height=height;   //因为这个属性是每一个实体独有的属性
       }
         //对对象的prototype属性重写
         Trigle.prototype=new TwoDshape();
         //对对象的prototype属性重写时,可能会对对象的constructor属性产生一个负面的影响所以
         Trigle.prototype.constructor=Trigle;
         Trigle.prototype.getArea=function(){
             return this.side*this.height/2
         }
        var tt=new Trigle(3,4);
         console.log(tt.toString());    //Trigle
         console.log(tt.getArea())   //6
      console.log(tt instanceof shape);   //true
      console.log(tt instanceof TwoDshape);   //true
       console.log(tt.hasOwnProperty('name'))  //false
       console.log(tt.hasOwnProperty('height'))  //true

值得注意的是扩展原型对象之前,一定要完成继承关系的构建
只继承原型
尽可能的将重用的属性和方法添加到原型中,这样就通过原型链就实现了继承,不再需要shape的实体来实现继承关系。

   function  shape(){}
         shape.prototype={
            name:'shape',
             toString:function (){
             return this.name;
         }
         }
       function TwoDshape(){
       }
         TwoDshape.prototype=shape.prototype;
         TwoDshape.prototype.constructor=TwoDshape;
       function Trigle(side,height){
           this.side=side;      //因为这个属性是每一个实体独有的属性
           this.height=height;   //因为这个属性是每一个实体独有的属性
       }
         //对对象的prototype属性重写
         Trigle.prototype=TwoDshape.prototype;
         //对对象的prototype属性重写时,可能会对对象的constructor属性产生一个负面的影响所以
         Trigle.prototype.constructor=Trigle;
         Trigle.prototype.getArea=function(){
             return this.side*this.height/2
         }
        var tt=new Trigle(3,4);
         console.log(tt.toString());    //Trigle
         console.log(tt.getArea())   //6
      console.log(tt instanceof shape);   //true
      console.log(tt instanceof TwoDshape);   //true
       console.log(tt.hasOwnProperty('name'))  //false
       console.log(tt.hasOwnProperty('height'))  //true

测试的结果和上面的一致,但是js在找toString的时候,直接找的是原型
子对象访问父对象
js中本身没有这样的属性,但是可以通过子类调用父类的同名方法来实现

   function  shape(){}
         shape.prototype={
            name:'shape',
             toString:function (){
               var result=[];
                 if(this.constructor.urber){
                     result[result.length]=this.constructor.urber.toString();
                 }
                 result[result.length]=this.name;
                 return result.join(',')+"11";
         }
         }
       function TwoDshape(){
       }
         function F(){};
         F.prototype=shape.prototype;
         TwoDshape.prototype=new F();
         TwoDshape.prototype.constructor=TwoDshape;
         TwoDshape.urber=shape.prototype;
         TwoDshape.prototype.name='2D图形';
       function Trigle(side,height){
           this.side=side;      //因为这个属性是每一个实体独有的属性
           this.height=height;   //因为这个属性是每一个实体独有的属性
       }
         //对对象的prototype属性重写
         var F=function(){};
         F.prototype=TwoDshape.prototype;
         Trigle.prototype=new F();
         //对对象的prototype属性重写时,可能会对对象的constructor属性产生一个负面的影响所以
         Trigle.prototype.constructor=Trigle;
         Trigle.urber=TwoDshape.prototype;
         Trigle.prototype.getArea=function(){
             return this.side*this.height/2
         }
         Trigle.prototype.name="三角形";
        var tt=new Trigle(3,4);
         console.log(tt.toString());    //shape11,2D图形11,三角形11

改进了toString 用urber属性指向了父类的原型
将继承的部分封装

   function extend(child,parent) {
        var F=function () {};
        F.prototype=parent.prototype;
        child.prototype=new F();
        child.prototype.constructor=child;
        child.uber=parent.prototype;   //实现子类继承父类的属性
    }
    function  shape(){}
         shape.prototype={
            name:'shape',
             toString:function (){
               var result=[];
                 if(this.constructor.uber){
                     result[result.length]=this.constructor.uber.toString();
                 }
                 result[result.length]=this.name;
                 return result.join(',')+"11";
         }
         }
       function TwoDshape(){}
         extend(TwoDshape,shape);
         TwoDshape.prototype.name='2D图形';
       function Trigle(side,height){
           this.side=side;      //因为这个属性是每一个实体独有的属性
           this.height=height;   //因为这个属性是每一个实体独有的属性
       }
       extend(Trigle,TwoDshape);
         Trigle.prototype.getArea=function(){
             return this.side*this.height/2
         }
         Trigle.prototype.name="三角形";
        var tt=new Trigle(3,4);
         console.log(tt.toString());    //shape11,2D图形11,三角形11

对象之间的继承 浅拷贝
js中没有类 丢掉构造函数来实现继承 就是多个属性的拷贝
使用多个属性的拷贝实现了类之间的继承,中间没有使用函数,js就实现了类之间的继承

  function extendCopy(p) {
          var c={};
          for(var i in p){
              c[i]=p[i];
          }
          c.uber=p;
          return c;
      }
         var shape={
            name:'图形',
             toString:function (){
                return this.name;
             }
         }
       var twoDee=extendCopy(shape);
      twoDee.name='2D图形';
      twoDee.toString=function(){
          return this.uber.toString()+this.name;
      }
       var trigle=extendCopy(twoDee);
      trigle.name="三角形";
      trigle.toString=function(){
          return this.uber.toString()+this.name;
      }
      trigle.side=3;
      trigle.height=4;
      trigle.getArea=function(){
          return this.height*this.side/2
      }
         console.log(trigle.toString());    //图形2D图形三角形
         console.log(trigle.getArea());    //6

深拷贝
之前的extendCopy实现 的是浅拷贝,要想实现深拷贝实际上遇到一个对象引用性的属性的时候,我们需要再次调用深拷贝函数
实现深拷贝

  function deepCopy(p,c) {
        var c=c||{};
        for(var i in p){
            if(typeof p[i]=="object"){
                c[i]=(typeof p[i===Array])?[]:{};
                deepCopy(p[i],c[i])   //实际上是一个递归实现的深拷贝
            }
            else{
                c[i]=p[i];
            }
        }
        return c;
    }

比较深拷贝和浅拷贝

 function deepCopy(p,c) {
        var c=c||{};
        for(var i in p){
            if(typeof p[i]=="object"){
                c[i]=(typeof p[i===Array])?[]:{};
                deepCopy(p[i],c[i])   //实际上是一个递归实现的深拷贝
            }
            else{
                c[i]=p[i];
            }
        }
        return c;
    }
    function extendCopy(p) {
        var c={};
        for(var i in p){
            c[i]=p[i];
        }
        c.uber=p;
        return c;
    }
     var p={
         numbers:[1,2,3],
         letters:['a','b','c'],
         obj:{
             name:'zhaowenjuan'
         },
         boolean:true
     }
       var test=deepCopy(p);
       test.numbers.push(3,4);
       console.log(test.numbers);   //1,2,3,4
       console.log(p.numbers);   //1,2,3   发生的是深拷贝  备份与原来相互独立
        var test2=extendCopy(p);
      test2.numbers.push(3,4);
    console.log(test2.numbers);   //1,2,3,4
console.log(p.numbers);     //1,2,3,4    发生的是浅拷贝    备份与原来是一个
相关TAG标签
上一篇:微信小程序的出现对前端的有啥影响?
下一篇:linux之mysql数据库搭建及sql注入和防御
相关文章
图文推荐

关于我们 | 联系我们 | 广告服务 | 投资合作 | 版权申明 | 在线帮助 | 网站地图 | 作品发布 | Vip技术培训 | 举报中心

版权所有: 红黑联盟--致力于做实用的IT技术学习网站