JS对象

三种创建对象的方法

一、使用关键字new构造函数创建对象

  obj = new object()

二、自定义创建对象

//工厂模式创建对象
    function createObject(name,age){
        var obj = new Object();
        obj.name = name;
        obj.age = age;
        obj.sayHi = function (){
            console.log(this.name,this.age)
        };
        return obj;
    }
    var p1=createObject("ss",12);
    p1.sayHi();
// 自定义构造函数
    function Person(name,age){
        this.name = name;
        this.age = age;
        this.sayHi = function(){
            console.log(this.name,this.age);
        };
    }
    var p1 = new Person("ss",22);
    p1.sayHi();

this

  永远指向函数正在执行时所在的对象,而不是指向函数创建时所在的对象,(类似Python类中的self,代指实例)
  匿名函数或不处于任何对象中的函数都是指向window

函数的this值取决于函数的调用模式:
  方法调用模式:当函数作为对象的一个属性时,函数就是这个对象的方法,this指向的就是这个对象
  函数调用模式:当函数不作为一个属性,直接调用时,this指向的是全局对象
  某个方法中的内部函数的this值也是指向全局对象,而不是外部函数的this
  构造函数模式:当使用new方法构造一个函数时,this指向的就是这个新产生的函数对象(实例对象)
  call和apply调用:使用这种方法,this指向的是这个方法的第一个参数

var that =this (保存原先this,使得this发生改变时,that依旧指向原先的this)

三、字面量创建方式

  obj = {name:“ss”}

类型传递

简单类型(值类型):number ,string ,boolean

复杂类型(引用类型):object

空类型:null , undefined

对象在堆上存储,地址在栈上存储

值类型在栈上存储

值类型传递的是值

引用类型传递的是地址

例:

 // 值类型传递       
    var num1 = 10var num2 = num1;//传递的是值
    
    function f1(x){
        x = 20;
    }
    var num = 10;
    f1(num);    
    console.log(num);    //结果是10  ,传递的是值 
//引用类型传递    
  obj = {
        name : "ss"
    };
    function f1(obj2){
        obj2.name = "yy"
    }
    console.log(obj.name);   //结果是ss
    f1(obj);
    console.log(obj.name);   //结果是yy   ,传递的是地址引用

原型

利用构造函数的原型对象可以实现共享数据,节省内存

构造函数包含原型对象(prototype),prototype中存在constructor构造器,指向自己原型所在的构造的函数

实例对象存在(__proto__),指向该构造函数的原型对象

构造函数的prototype可以被实例对象自接访问

//prototype
    function Perpon(name,age,sex){
        this.name = name;      /*这些通过this添加的属性是实例属性*/
        this.age = age;
        this.sex = sex;
    }
    Perpon.prototype.sayHi = function(){   /*向构造函数的原型对象中添加属性*/
        console.log("My name"+this.name+"\n"+"age"+this.age)
    };
    var p1 = new Perpon("ss",23,"man");
    p1.sayHi();
    var p2 = new Perpon("yy",25,"man");   /*两个实例对象可以调用相同的原型对象属性*/
    p2.sayHi();
    console.dir(Perpon);
    console.dir(p1);             /*实例中不存在prototype*/

注意

  构造函数中通过this添加的属性都是实例对象属性而不是构造函数的属性

  而通过prototype添加的原型对象属性是构造函数的属性,实例属性不存在prototype,但有的支持非标准的__proto__指向原型对象

为原型对象添加属性(两种方式)

  Perpon.prototype.eat = function(){};
    Perpon.prototype.height = "178cm";
    Perpon.prototype.weight = "55kg";
    
    Perpon.prototype = {
        constructor:Perpon,    /*注意这种方式添加原型对象属性方法,需要手动添加构造器*/
        height:"178cm",
        weight:"55kg",
        eat:function(){}
    }

原型链:是一种关系,是实例对象和原型对象之间的关系,通过(__proto__)产生关联

原型的指向可以改变

当原型指向发生改变后,再添加方法就可以再使用这个方法

改变原型的指向,可以实现继承

但存在实例后属性值相同的情况,使用借用构造函数方法继承可避免,但借用构造函数不能继承方法

使用组合继承:原型继承+借用构造函数继承

function Perpon(name,age){
        this.name = name;
        this.age = age;
    }
    Perpon.prototype.eat = function () {
        console.log("Perpon eat");
    };

    function Student(name,sex) {
        this.name = name;
        this.sex = sex;
    }
    Student.prototype.study = function(){
        console.log("going study");
    };

    Student.prototype = new Perpon("ss",22);    /*原型对象指向发生改变,让它指向另外一个实例*/
    var st = new Student("yy",23);
    st.eat();

继承

改变原型的指向,可以实现继承

但存在实例后属性值相同的情况,使用借用构造函数方法继承可避免,但借用构造函数不能继承方法

使用组合继承:原型继承+借用构造函数继承

function Perpon(name,age){
        this.name = name;
        this.age = age;
    }
    Perpon.prototype.eat = function () {
        console.log("Perpon eat");
    };

    function Student(name,age,sroce) {
        Perpon.call(this,name,age);      /*借用构造函数继承,使得值由子构造函数传入*/
        this.sroce = sroce;
    }
    //借用构造函数只能解决属性值重复的情况,不能继承方法,需要改变原型指向继承方法
    Student.prototype = new Perpon();     /*这里构造函数不传值,因为子构造函数已借用父构造函数*/
    var st1 = new Student("ss",22,"100");
    console.log(st1.name,st1.age,st1.sroce);
    st1.eat();
    var st2 = new Student("yy",25,"120");
    console.log(st2.name,st2.age,st2.sroce);
    st2.eat();

实例对象中有__proto__原型指向构造函数的prototype,prototype也是对象,它也有__proto__原型,指向object的prototype

而object.prototype.__proto__指向的是null

面向对象对象编程

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        #dv{
            width: 200px;
            height: 300px;
            background-color: chocolate;
        }
        #pp{
            width: 200px;
            height: 300px;
            background-color: chocolate;
        }
    </style>
</head>
<body>
<input type="button" id="btn" value="change">
<div id="dv" ></div>
<p id="pp"></p>
<script>
  function my$(id){
    return document.getElementById(id);
  }
function ChangeStyle(btnobj,dvobj,json) { this.btnobj = btnobj; this.dvobj = dvobj; this.json = json; } ChangeStyle.prototype.init = function() { var that = this; /*保存这个this,当this改变时,that依然是原先的this*/ this.btnobj.onclick = function() { /*这里this和上面的this不同*/ for (var key in that.json) { /*that这里就是指this,是this.btnobj*/ that.dvobj.style[key] = that.json[key]; } } }; var json = {"width":"300px","height":"500px","backgroundColor":"blue","opacity":"0.2"}; var p1 = new ChangeStyle(my$("btn"),my$("dv"),json); p1.init(); var json1 = {"width":"300px","height":"500px","backgroundColor":"blue","opacity":"0.2"}; var p2 = new ChangeStyle(my$("pp"),my$("dv"),json1); p2.init(); </script> </body> </html>

使得局部变量能在全局使用

<script>
    //通过自调用访问局部属性
    (function (window) {    /*接收传过来的window实参*/
        function Random(){
        }
        Random.prototype.getRandom = function(min,max){
            return Math.floor(Math.random()*(max-min)+min)
        };
        window.Random = Random;     /*将内部的变量赋值到顶级对象window下,外部就可用,对象之间传递地址引用*/
    })(window);    /*将window传入到函数中*/
    var rm = new Random();       /*new window.Random(),window可省略*/
    console.log(rm.getRandom(0,5));
</script>

在匿名函数直接执行时,将顶级对象window传入到函数中,再将函数内部的属性变量传递给window

posted @ 2019-08-12 22:17  saber゛  Views(195)  Comments(0Edit  收藏  举报