JS-面向对象

来源:互联网 发布:阿里云企业邮箱升级 编辑:程序博客网 时间:2024/06/05 18:57

一  对象

ECMAScript变量包含两种不同类型的值:基本类型、引用类型。

基本类型:number stringboolean nullundefined

引用类型:Object Array DateRegExp Function Math

基本包装类型(NumberStringBoolean)

 

两种类型的区别是:存储位置不同

基本类型:直接存储在栈(stack)中的简单数据段,占据空间小、大小固定,属于被频繁使用数据,所以放入栈中存储;

引用类型:存储在堆(heap)中的对象,占据空间大、大小不固定,如果存储在栈中,将会影响程序运行的性能;引用数据类型在栈中存储了指针,该指针指向堆中该实体的起始地址。当解释器寻找引用值时,会首先检索其在栈中的地址,取得地址后从堆中获得实体


对象无序属性的集合,其属性可以包含基本或者对象

创建对象-----基于Object对象方式.

var box = new Object(); //创建一个Object对象

box.name = ‘Lee’; //创建一个name属性并赋值

box.age = 100; //创建一个age属性并赋值

box.run = function () { //创建一个run()方法并返回值

  return this.name +this.age

};

alert(box.run()); //输出属性和方法的值


上面创建了一个对象,并且创建属性和方法,在run()方法里的this,就是代表box对象

本身。这种是JavaScript创建对象最基本的方法,但有个缺点,想创建一个类似的对象,就

会产生大量的代码

创建对象------对象字面量方式:

Var person={

    name: “张三”,

    age : 18,

    eat:funtion(){

  alert(“对方是否”);

   } 

}

数据属性和访问器属性---用于JS引擎,外部无法直接访问(内部值

数据属性的特性

[[configurable]]:表示能否使用delete操作符删除从而重新定义,或能否修改为访问器属性。默认为true;

[[enumberable]]:表示是否可以在 for...in 循环和Object.keys()中被枚举。默认true;

[[writable]]:表示是否可修改属性的值。默认true;

[[value]]:包含该属性的数据值。读取/写入都是该值

要修改对象属性的默认特征(默认都为true),可调用Object.defineProperty()方法,它接收三个参数:属性所在对象,属性名和一个描述符对象(必须是:configurableenumberablewritablevalue,可设置一个或多个值)

   varperson = {};

   Object.defineProperty(person,'name', {

        configurable:false,

        writable:false,

        value: 'Jack'

   });

访问器属性的特性

[[configurable]]:是否可通过delete操作符删除重新定义属性;

[[enumberable]]:是否可通过for-in循环查找该属性;

[[set]]:写入(设置)属性时调用函数,默认:undefined;一旦属性被访问读取,此方法被自动调用。

[[get]]:读取(获取)属性时调用函数,默认:undefined;一旦属性被重新赋值,此方法被自动调用。

访问器属性不能直接定义,必须使用defineProperty()来定义。

不能同时设置访问器 (get set)wriable value,否则会错,就是说想用(get set),就不能用(wriable value中的任何一个

ECMA-2625)还提供了一个Object.defineProperties()方法,可以用来一次性定义多个属性的特性---(ie9)


 var person ={};

   Object.defineProperties(person,{

        _age:{//前面的下划线是一种常用的记号,用于表示只能通过对象方法访问的属性

            value:19,

           configurable: true,

            writable:true

        },

       isAdult:{

           get:function(){

                if(this._age>=18){

                   return true;

                }else{

                   return false;

                }

            }

        }

    });

   person._age=16;

   console.log(person._age);

   console.log(person.isAdult?"成年":"未成年");



对象封装性:js中面向对象的封装手段主要是通过函数来进行

封装性之工厂模式:原料—>加工—>出厂

function createObject(name, age) { //集中实例化的函数

  var obj = newObject();

  obj.name = name;

  obj.age = age;

  obj.run = function (){

      return this.name + this.age ;

  };

 return obj;

}

var box1 = createObject('Lee', 100); //第一个实例

var box2 = createObject('Jack', 200); //第二个实例

alert(box1.run());

alert(box2.run());


工厂模式虽然解决了封装对象的问题,但还有一个问题那就是根本无法搞清楚他们到底是哪个对象的实例。

alert(typeof box1); //Object

alert(box1 instanceof Object); //true

封装性之构造函数模式

ECMAScript 中可以采用构造函数可用来创建特定的对象。类似基于Object创建对象。

构造函数模式的语法:

function Box(name, age) {

 [  this=new Object()]

      this.name =name;

      this.age = age;

      this.run =function () {

         returnthis.name + this.age;

      };

 [  return this]

}

var box1 = new Box('Lee', 100);

var box2 = new Box('Jack', 200);


使用工厂模式的方法他们不同之处如下:

1.构造函数方法没有显示的创建对象(new Object());

2.直接将属性和方法赋值给 this 对象;

3.没有 renturn 语句。

构造函数的规范:

1.函数名和实例化构造名相同且大写,(PS:非强制,但这么写有助于区分构造函数和普通函数);

2.通过构造函数创建对象,必须使用 new 运算符。

3.构造函数和普通函数的唯一区别,就是他们调用的方式不同。只不过,构造函数也是函数,必须用 new运算符来调用,否则就是普通函数。

通过构造函数创建和封装对象,那么这个对象是哪里来的?new Object()在什么地方?是怎么执行的?

1.当通过new FunName()调用构造函数时,浏览器的js解析器解析到new操作符时就默认创建了newObject();

2.将构造函数的作用域赋给新对象,(即 new Object()创建出的对象),而函数体内的this就指向新实例化出来的对象。

3.执行构造函数内的代码;

4.返回新对象(浏览器的js解析器直接返回)。


关于this指向的几种情况

1.全局中调用

var box = 2;

alert(this.box); //全局,代表 window

2.函数调用

函数中的this也指向window对象

function greeting(){

   this.name="sheila";

    alert("hello"+this.name);

}

greeting();//hello sheila

alert(window.name);//sheila

3.对象的方法调用

obj.fn();//obj对象的fn()方法中的this指向obj

4.调用构造函数

var dog=new Dog();//构造函数内的this指向新创建的实例对象


与普通函数相比,构造函数有以下明显特点

a.用new关键字调用

b.函数内部可以使用this关键字

c.默认不用return返回值

d.函数命名建议首字母大写,与普通函数(驼峰命名法)区分开

构造函数的缺点

创建多个实例时,会重复调用new Function()创建多个函数实例,这些函数实例还不是在同一个作用域中,这会造成内存浪费

functionPerson(name,age,sex){
   
this.name=name;
   
this.age=age;
   
this.sex=sex;
    /*
this.getInfo=function () {
        return this.name+"---"+
this.age+"---"+this.sex;
    }*/
   
this.getInfo=newFunction('return this.name+"---"+this.age+"---"+this.sex;')
}
varper1=newPerson('小黑',29,'公的');
varper2=newPerson('小黑',29,'母的');
console.log(per2.getInfo());

console.log(per2.getInfo==per1.getInfo);//false

在构造函数里面创建方法会形成闭包

functionObj() {
   
this.age=20;
   
this.fun=function() {
        
this.age++;
        console.log(
this.age)
    }
}
varnewObj=newObj;
varnewObj1=newObj;
newObj.fun();
newObj.fun();
newObj.fun();
newObj1.fun();








三、call , apply方法实现继承
 //Call
 
functionPerson(sname,age){
    
this.sname=sname;
    
this.age=age;
 }
 
functionStudent(sname,age,sex){
    
Person.call(this,sname,age);
    
this.sex=sex;
 }
 
varstu=newStudent('小方',18,'');
 alert
(stu.sname);


//1,第一个参数this都一样,指当前对象  
//2,
第二个参数不一样:call的是一个个的参数列表;apply的是一个数组(arguments也可以)

call, apply方法的其他使用场景
 //应用场景一

function Fruit(color, shape) {

this.color = color;

this.shape = shape;

}

Fruit.prototype = {

constructor: Fruit,

getinfo: function () {

  console.log(this.color + ',' + this.shape);

          }

}

let apple = new Fruit('orange', 'circle');

apple.getinfo();

let banner = {

color: 'yellow',

shape: 'cylinder'

}

apple.getinfo.call(banner);

apple.getinfo.apply(banner);



//
应用场景二

var array1 = [12, "foo", {name:"Joe"},-2458];

var array2 = ["Doe", 555, 100];

Array.prototype.push.apply(array1, array2);

console.log(array1);

Array.prototype.push.call(array1,"Doe", 555, 100);

console.log(array1);

 



原创粉丝点击