js面向对象

<!--
    Created by wangyang on 2019-05-16.
    itwangyang@gmail.com
    http://www.itwangyang.xyz
-->
<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<meta http-equiv="X-UA-Compatible" content="IE=Edge">
	<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
	<meta name="apple-mobile-web-app-capable" content="yes">
	<meta name="apple-mobile-web-app-status-bar-style" content="black">
	<meta name="format-detection" content="telephone=no">
	<title>Title</title>
	<meta name="description" content="">
	<meta name="keywords" content="">
	<!--所有的IE都起作用:-->
	<!--[if IE]>
	<link rel="stylesheet" type="text/css" href="all-ie-only.css/> <![endif]-->

</head>
<body>

<script>
  /**
   * 数据类型,----值类型:数字、字符串、布尔值、null、undefined
   * 复杂数据类型:引用类型,对象:数组、函数、正则表达式、Date
   */

  //变量没有声明过,--》如果获取变量的值,是会产生语法错误的    console.log(a);

  /**
   * undefined场景:
   * 1.一个变量声明了,但是没有赋值    var a; console.log(a);
   * 2.一个变量声明了,并且赋值了一个undefined的值,var b = undefined;  console.log(b);
   * 3.一个对象中,获取某个不存在的属性的值  var c ={};console.log(c.name);
   */


  /**
   * 面向对象:
   * 对象是键值对的集合:对象是由属性和方法构成的;
   */

  /**
   * 对象属性的操作:
   * 1.  第一种方式:.语法
   * student.name
   * 缺陷:后面不能使用js中的关键字、保留字(class/this/function/)
   *      后面不能使用数字的
   *
   *
   * 2.  第二种:使用更广,推荐
   * student["name"];  等价于  student.name
   *
   *设置属性:
   * student ["gender"] = "男";
   *
   *
   * 删除属性:
   * delete student["gender"]
   *
   */

    //1.创建对象
  const Person = {
      gender: '男',
      height: 185,
      toShanghai: function () {
        console.log('做?去上海');
      }
    };
  //2.获取属性
  console.log(Person.gender);
  console.log(Person['height']);
  //3.设置属性
  Person.address = "上海市闸北区";
  Person.height = 180;
  //4.删除属性
  delete Person.gender;
  delete Person.a;
  //5.清空对象
  Person = {};  //Person对象不再具有任何属性
  Person = null; //表示将Person变量的值赋为null,从此以后person不再是一个对象了



</script>
</body>
</html>

1.构造函数

<!--
    Created by wangyang on 2019-05-16.
    itwangyang@gmail.com
    http://www.itwangyang.xyz
-->
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=Edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
  <meta name="apple-mobile-web-app-capable" content="yes">
  <meta name="apple-mobile-web-app-status-bar-style" content="black">
  <meta name="format-detection" content="telephone=no">
  <title>Title</title>
  <meta name="description" content="">
  <meta name="keywords" content="">
  <!--所有的IE都起作用:-->
  <!--[if IE]>
  <link rel="stylesheet" type="text/css" href="all-ie-only.css/> <![endif]-->

</head>
<body>


<script>
  function Person(age, gender) {
    this.age = age;
    this.gender = gender;

    //此时的内存依然浪费了---》原型
    this.syaHello = function () {

    }
  }

  //Person是p1的构造函数
  let p1 = new Person(5, '女');
  let p2 = new Person(51, '女');
  let p3 = new Person(52, '女');
  let p4 = new Person(15, '女');
  let p5 = new Person(25, '女');
  console.log(p1, p2, p3, p4, p5);
</script>
</body>
</html>

2.构造函数的返回值

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    
</body>
<script>
    //1、
    function _fn(){
        return 5;
    }
    var s=new _fn();
    //s是_fn构造函数的实例

    //2、
    function _fn3(){}
    var q1=new _fn3();
    //q1是_fn3构造函数的实例

    //3、
    function fn3(){
        return [1,3,5]; 
    }
    var qw=new fn3();//qw=[1,3,5]
    console.log(qw);
    //qw不是fn3构造函数的实例

    //如何判断一个数据是否是复杂数据类型?
    //使用排除法:
    //a、看它的值是不是:数字、字符串、布尔值、null、undefined,
    //b、如果不是以上5种值,那就是复杂数据类型

    //  举例:
    // [1,3,5]
    //  /abc/
    //  function(){}
    //  new Object();


    //为什么要理解构造函数的返回值?
    //String是一个内置函数
    //a、String()
    //b、new String()
    
    //结论:一个函数通过new调用,或者不通过new调用,很多时候会有截然不同的返回值

    //我如何分辨出一个对象到底是不是某个构造函数的实例?
    //a、var isTrue=xxx instanceof Person

    function Person(){

    }
    var p1=new Person();
    console.log(p1 instanceof Person);//true,就是Person的实例

    function Student(){
        return 100;
    }
    var s1=new Student();
    console.log(s1 instanceof Student);//true,就是Student的实例

    function Programmer(){
        return [1,3,5]
    }
    var pro=new Programmer();//pro并不是Programmer的实例
    console.log(pro instanceof Programmer);//false
    
    console.log("是数组的实例吗?",pro instanceof Array);//true

    //小技巧:如何通过肉眼识别xxx对象时哪个构造函数的实例?
    //xxx.__proto__属性,也是对象,该对象中一般都会有一个constructor属性,这个只想PPP函数,那么就可以认为:xxx是PPP构造函数的实例


    //typeof运算符,只能判断:数字、字符串、布尔值、undefined、函数

    //切记:千万不能使用typeof运算符来判断对象的构造函数

    //typeof null === "object"
    //typeof {}  === "object"
    //typeof []  === "object"
    //typeof function(){} === "function"
    //typeof /abc/     === "object"

</script>
</html>

3.为什么要继承? 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    
</body>
<script>
    function Person(name,age){
        this.name=name;
        this.age=age;
        this.say=function(){}
    }
    var p1=new Person();
    var p2=new Person();
    
    //p1对象和p2对象的say方法是否是同一个方法:false
    console.log(p1.say===p2.say);

    //由于say方法可能功能相似,但是不是同一个方法(没有指向同一块内存,会造成内存浪费)
    //解决方案:把say方法写在他们共同的(父对象)中
    //其实他们共同的父对象,就可以通过:Person.prototype来获取

    //-->只要把say方法写在Person.prototype中,那么say方法就是同一个方法
    Person.prototype.run=function(){
        console.log('时速500KM');
    }
    //此时p1和p2都可以访问到run方法
    p1.run();
    p2.run();
    //验证p1.run和p2.run是否是同一个方法?
    console.log(p1.run == p2.run); //指向同一个方法,这种方法避免了内存的浪费
    
    console.log(p1.run == Person.prototype.run);
    //true

    var p3=new Person();
    console.log(p3.run == p1.run); //true
    console.log(p3.run === p1.run);//true
    //结论:只要往某个构造函数的prototype对象中添加某个属性、方法,那么这样的属性、方法都可以被所有的构造函数的实例所共享
    //==>这里的【构造函数的prototype对象】称之为原型对象
    //  Person.prototype是 p1 p2 p3 的原型对象
    //  Person.prototype是Person构造函数的【实例】的原型对象

    //猜猜看?
    //  Person的原型对象是谁呢?
    //  -->首先要知道Person的构造函数:-->Function
    //  -->所以Person的原型对象是:Function.prototype

    //  p1的原型对象是谁呢?
    //  -->首先要知道p1是谁创建的?    -->Person
    //  -->所以p1的原型对象时:     Person.prototype

</script>
</html>

 

4.继承

<!--
    Created by wangyang on 2019-05-17.
    itwangyang@gmail.com
    http://www.itwangyang.xyz
-->
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=Edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
  <meta name="apple-mobile-web-app-capable" content="yes">
  <meta name="apple-mobile-web-app-status-bar-style" content="black">
  <meta name="format-detection" content="telephone=no">
  <title>Title</title>
  <meta name="description" content="">
  <meta name="keywords" content="">
  <!--所有的IE都起作用:-->
  <!--[if IE]>  <link rel="stylesheet" type="text/css" href="all-ie-only.css/> <![endif]-->

</head>
<body>



<script>
  function Person(name,age) {
    this.name = name;
    this.age = age;
    this.sayHello = function () {

    };
  }
  let p1 = new Person();
  let p2 = new Person();
  console.log(p1.sayHello === p2.sayHello);//false
  //没有指向同一块内存,会造成内存浪费;解决方案:吧sayHello写在他们共同的(父对象)中

  //其实他们共同的父对象,就可以通过Person.prototype来获取,就可以指向同一块内存中

  Person.prototype.run = function () {
    console.log('hha');
  };
  p1.run();
  p2.run();
  console.log(p1.run === p2.run);//true

  //结论:只要往某个构造函数的prototype对象中添加某个属性,方法,那么这样的属性,方法都可以被所有的构造函数的实例所共享

  //----》在这里,【构造函数的prototype对象】称为原型对象

  /**
   * Person的原型对象是谁?
   * ---》手写要知道Person的构造函数:-----》Function
   * --->所有Person的原型对象是:Function.prototype
   *
   */




  //继承第一种方式
  function Tiger() {
    
  }
  
  Tiger.prototype = {
    sayHello:function () {

    },
    eat:function () {
      
    }
  };
  let tiger = new Tiger();
  console.log(tiger.sayHello);
  console.log(tiger.eat);
  //缺点:添加1,2个无所谓,但是如果太多了,内存浪费

 


   //继承的第一种方式:原型链继承1
  /**  
   *  Person.prototype.say=function(){
   *    console.log("你好")
   * }
   缺点:添加1、2个方法无所谓,但是如果方法很多会导致过多的代码冗余
  
  
  
  // 继承的第二种方式:原型链继承2

   Person.prototype={
    constructor:Person,
    say:function(){
      console.log("你好");
    },
    run:function(){
      console.log("正在进行百米冲刺");
    }
  }
   注意点:
   a、一般情况下,应该先改变原型对象,再创建对象
   b、一般情况下,对于新原型,会添加一个constructor属性,从而不破坏原有的原型对象的结构
   
   
   //继承的第三种方式:拷贝继承(混入继承)

   场景:有时候想使用某个对象中的属性,但是又不能直接修改它,于是就可以创建一个该对象的拷贝
   实现1: js var source={name:"李白",age:15} var target={}; target.name=source.name target.age=source.age;

   上面的方式很明显无法重用,实际代码编写过程中,很多时候都会使用拷贝继承的方式,所以为了重用,可以编写一个函数把他们封装起来: js function extend(target,source){ for(key in source){ target[key]=source[key]; } return target; } extend(target,source)

   由于拷贝继承在实际开发中使用场景非常多,所以很多库都对此有了实现

   jquery:$.extend
   es6中有了对象扩展运算符仿佛就是专门为了拷贝继承而生: js var source={name:"李白",age:15} var target={ ...source }

   //继承的第四种方式:原型式继承

   场景:
   创建一个纯洁的对象
   创建一个继承自某个父对象的子对象
   使用方式:
   - 空对象:Object.create(null)
   var o1={ say:function(){} }
   var o2=Object.create(o1);
   继承的第五种方式:借用构造函数实现继承

   场景:适用于2种构造函数之间逻辑有相似的情况
   function Animal(name){ this.name=name; } function Person(name,age){ this.name=name; this.age=age; }

   以上代码用借用构造函数实现 js function Animal(name,age){ this.name=name; this.age=age; } function Person(name,age,address){ Animal.call(this,name); //this.name=name; //this.age=age; this.address=address; }


   * 
   */
 





</script>
</body>
</html>

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值