2019-08-03

JavaScript学习第六章

1:理解对象

创建自定义对象的最简单方式为创建一个object的实例。例:

var A={

you:"a",

me:23,

love:function(){

alert()

}

}


6.1:属性类型

ECMAScript有两种属性:

1:数据属性

2:访问器属性

1.1:数据属性

1:[[Configurable]]:

表示能否通过delete删除属性从而重新定义属性,能否修改属性的特性,或者能否把属性修改为访问器属性。

用法:Configurable :true/false,

2:[[Enumerable]]:

表示能否通过for-in循环返回属性。

用法:Enumerable:true/false,

3:[[Writable]]:

表示能否修改属性的值。

用法:Writable:true/false,

4:[[Value]]:

包含这个属性的数据值。

默认值为Undefined

有关[[writable]]的例子:

var person = {

name:'Nichole'

};

Object.defineProperty(person,"name" , {

writable:false,                               // 设置属性不可修改(注意这里)

value:'Bubble'

});

console.log(person.name);          // Bubble

person.name ='Hello';

// 非严格模式下,该操作被忽略;严格模式下,会导致抛出错误。

console.log(person.name);         // Bubble 

注:一旦将属性定义为不可配置的,就不能把它变回可配置的。

1.2.访问器属性

访问器属性不包含数据值,它包含一对getter()和setter()函数。在读取访问器属性时,会调用getter(),这个函数负责返回有效的值。

在写入访问器属性时,会调用setter()并传入新值,这个函数负责如何处理数据。

访问器属性有如下特性:

1:[[Configurable]]:

表示能否通过delete删除属性从而重新定义属性,能否修改属性的特性,或者能否把属性修改为访问器属性。

2:[[Enumerable]]:

表示能否通过for-in循环返回属性。

3:[[Get]]:

在读取属性时调用的函数,默认值为undefined

4:[[Set]]:

在写入属性时调用的函数,默认值为undefined

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

var A={ 

B:'Nichole',

count:0};

Object . defineProperty(person,'name', {

get:function(){

return      this.B; 

 },

set:function(newValue){

this.B = newValue;

this.count +=1;

 }});

A.name ='Bubble';

console.log(A.B)                          // Bubble

console.log(person.count)            // 1

1.3:定义多个属性

可用Object.defineProperties()方法,定义多个属性。例:

var A={};

Object.defineProperties(A,{

B:{

Writable : true,

value : 12

},

B1:{

get : function(){

return this.B;

},

set.function(C){

if(C>11){

this.B = C;

}

}

}

});


1.3:读取属性的特性

使用 Object . getOwnPropertyDescriptor() 方法可取得给点属性的描述符。

语法

Object.getOwnPropertyDescriptor(obj   ,  prop)

obj:需要查找的目标对象

prop:目标对象内属性名称

返回值:如果指定的属性存在于对象上,则返回其属性描述符对象(property descriptor),否则返回undefined

2:创建对象

创建一个对象,如此在使用同一个接口时,无需重复创建单个对象。

2:1工厂模式

例:function createObject1(name,age)

{

    var obj=new Object();

    obj.name=A;

    obj.age=B;

    obj.run=function(){

alert(this.name);

    };

    return obj;

}

var C=createObject1("loveyousiyun",27);

在上述createObject()函数被创建后,其可被无数次地调用,并返回一个含有两个属性的对象。

注:该模式存在无法识别对象类型的问题。

2.2构造函数模式

function CreateObject2(name,age)

{

    var obj=new Object();

    obj.name=A;

    obj.age=B;

    obj.run=function(){

alert(this.name);

    };

    return obj;

}

var C= new CreateObject2("loveyousiyun",27);

 注:上述两个例子中,除了相同的部分外,CreateObject2()函数还存在以下不同之处:

    1:没有显式地创建对象;

    2:直接将属性和方法赋给了this对象;

    3:没有return语句。

注:函数名CreateObject2开头使用的是大写字母C,在调用该函数时,必须使用new 操作符。

要创建CreateObject2的新实例,必须使用new操作符。以这种方式调用构造函数实际上会经历以下4个步骤:

   (1)创建一个新对象;

   (2)将构造函数的作用域赋给新对象(因此this就指向了这个新对象);

   (3)执行构造函数中的代码(为这个新对象添加属性);

   (4)返回新对象。

2.3:原型模式

prototype()属性:该属性是一个指针,指向一个对象。

其用途为:使所有对象实例共享它所包含的属性和方法。

例:

function A(){

A.prototype.name="xiao";

A.prototype.age=19;

A.prototype.useful=function(){

alert(this.name);

};

}

var qiming=new A();

qiming.useful();                                   //xiao

var siyun=new A();

alert(siyun.age);                                    //19

siyun.useful();                                        //xiao

alert(siyun.useful==qiming.useful);        //true


由上述例子,可知:qiming和siyun访问的是同一组属性和同一个useful()函数。

注:可以通过对象实例访问保存在原型中的值,但不能通过对象实例重写原型中的值。

例:

function A(){

A.prototype.name="xiao";

A.prototype.age=19;

A.prototype.useful=function(){

alert(this.name);

};

}

var qiming=new A();

var siyun=new A();

qiming.name="li";

alert(qiming.name);        //    li — — — 来自实例

alert(siyun.name);           //    xiao — — —来自原型


由上述例子可知,qiming.name会屏蔽原型对象中保存得的同名属性。

注:可通过delete删除实例属性。例:

function A(){

A.prototype.name="xiao";

A.prototype.age=19;

A.prototype.useful=function(){

alert(this.name);

};

}

var qiming=new A();

var siyun=new A();

qiming.name="li";

alert(qiming.name);        //    "li" — — — 来自实例

alert(siyun.name);           //    "xiao" — — —来自原型

delete   qiming.anme;

alert(qiming.name);             //    "xiao" — — —来自原型

注:构造函数模式和原型模式可组合使用。

例1:

function Person(name,age){

this.name=name;

this.age=age;

this.friends=["Icarid","Chris"];

}

Person.prototype={

constructor:Person,                    //constructor是保存对函数对象指针

getName:function(){

alert(this.name)

}

}

var person1=new Person("Joe",23);

var person2=new Person("Leo",35);

person1.getName();                                           //Joe

person2.getName();                                            //Leo

alert(person1.getName==person2.getName);     //true,说明两个实例                                                                               的方法的指针相同

alert(person1.friends); //Icarid,Chris

person1.friends.push("John"); //向数组中传递参数,添加到数组末尾

alert(person1.friends);      //Icarid,Chris,John

alert(person2.friends);     //Icarid,Chris,说明实例的属性都是分的,                                           即互不影响

使用构造函数与原型混合的模式,是ECMAScript中使用最广泛,认同度最高的一种创建自定义类型的方法。

2.5:动态原型模式

该模式可通过检查某个应该存在的方法是否有效,来决定是否初始化原型。例:

function CreateObject2(name,age)

{

this.name=A;

this.age=B;

if  (typeof  this.sayname!="function"){

CreateObject2.prototype.sayname = function(){

alert(this.name);

};

}

var C= new CreateObject2("loveyousiyun","qiming");

C.sayname();

注意if(){....}中的那部分,只有在sayname()方法不存在的情况下,才会将它添加到原型中。

2.6:寄生构造函数模式

例:

function

Person(name,age,job){

var  A =newObject();

    A.name = name;

    A.age = age;

    A.job = job;

A.sayName =function(){

alert(this.name);

    }

return     A;

}

注:  首先,返回的对象构造函数或者与构造函数的原型属性之间没有关系,

也就是说,构造函数返回的对象与在构造函数外部创建的对象没有什么不同。

因此不能依赖instanceof 操作符来确定对象类型。

2.7:稳妥构造函数模式

所谓稳妥对象,指的是没有公共属性,而且其方法也不引用this对象。

稳妥对象最适合使用在一些安全的环境,或者防止数据被其他引用程序改动的时候使用。

function Person(name,age,job)

{          

    var o = new Object();             // 创建需要返回的对象


    var _name = name;

    var _age = age;

    var _job = job;                    // 在这边可以定义私有的变量和函数



    o.sayName = function(){

        alert(_name);                    // 添加需要返回的方法

    }

     return o;                               // 返回对象

}

3:继承

3.1:原型链

简介:一个引用类型继承另一个引用类型的属性和方法。

例:

function Father(){

  this.property = true; 

}

Father.prototype.useful = function(){

  return this.property;     

}

function Son(){

  this.property = false; 

}                       

        //继承了Father

Son.prototype = new Father();

Son.prototype.useless = function()

{

  return this.property; 

}

var instance = new Son();

alert(instance.useful());                                //true

上面的其实是Son继承了Father,而继承则是通过创建Father的实例,并将该实例赋给Son.prototype实现的,实现的本质就是重写原型对象,代之一个新类型的实例。

如何确定原型和实例的关系

1:使用instanceof操作符,只要这个操作符来促使实例与原型链中出现过的构造函数,结果就会返回true。

例:alert(instance instanceof  Object);         //true

2:使用insPrototypeof()方法

例:alert(Object.prototype.isPrototypeOf(instance));    //true

3.2:借用构造函数

借用构造函数实现继承的基本思想是:

在子类型的构造函数内部调用超类型的构造函数。因为函数知识在特定环境中执行代码的对象,因此可以通过apply( )方法和call( )方法在新创建的对象上执行构造函数。

例1:

function SuperType(){

this.colors=['red','blue','green'];

}

function Subtype(){

SuperType.call(this);               //在当前环境中调用SuperType函数,

}                                                    继承了SuperType()

var aaa=new Subtype();

alert(aaa.colors);                          //red,blue,green

aaa.colors.push('black');

alert(aaa.colors);                         //red,blue,green,black

var bbb=new Subtype();

alert(bbb.colors);                             //red,blue,green

上述例子中,Subtype()继承了SuperType(),代码中将Subtype()赋值于   aaa   与  bbb   。

3.3.组合继承

使用原型链实现对原型属性和方法的继承,而通过借用构造函数来实现对实例属性的继承

这样,既通过在原型上定义方法实现了函数复用,又能够保证每个实例都有它自己的属性。

例:

function SuperType(name) {

    this.name = name;

    this.numbers = [1,2,3];

}

//原型来定义方法,原型链的优点

SuperType.prototype.sayName = function () {

    alert(this.name);

};

function SubType (name, age) {

    //继承属性

    SuperType.call(this, name);

    this.age = age;

}

//继承方法

SubType.prototype = new SuperType();

//子类新定义的方法一定要在上面的继承代码之后,要不然新写的方法就没了

SubType.prototype.sayAge = function () {

    alert(this.age);

}

var instance1 = new SubType("MirrorAvatar", 3);

instance1.numbers.push(33);

instance1.numbers;  // "[1,2,3,33]"

instance1.sayName();  //MirrorAvatar

instance1.sayAge();  //3

var instance2 = new SubType("Cindy", 4);

instance2.numbers;  //"[1,2,3]"

instance2.sayName();  //Cindy

instance2.sayAge();  //4

3.4:寄生式继承

寄生式基础的思路与寄生构造函数和工厂模式类似,既创建一个仅用于封装继承过程的函数,该函数内部以某种方式来增强对象,最后再像真地是它做了所有工作一样返回对象。

function object(o){

   function F(){

   }

  F.prototype=o;

   return new F();

 };                            //这部分object(o)中,返回值是F(),其中                                          F.prototype=o

function      createAnother(original){

var    clone = object(original);              // 通过调用函数创建一个新对象

clone.sayHi =function(){                      //以某种方式增强真个对象

alert("hi");

}

 return     clone;                     //返回值是clone,其中clone

}                                             

注意:creatAnother(original)会返回clone, 其中clone=F() ,            F.prototype=original,clone.sayHi="hi",(就怕自己看不懂。。。。。。。)

在这个例子中,createAnother() 函数接收一个参数,也就是将要作为新对象基础的对象。然后把这个对象(original)传递给object()函数,将返回的结果赋值给clone。再为其添加一个sayHi方法,最后返回clone对象。

可以像下面这样使用 createAnother()方法 

var    person={

            name:"Nicholas",

            friends:["Shelby","Court","Van"]

      }

var      now = createAnother(person);

now.sayHi();                               // hi

3.5:寄生组合式继承

function   inheritPrototype(Female,Person){

var  protoType=Object.create(Person.prototype); //创建对象

protoType.constructor=Female;                            // 增强对象

Female.prototype=protoType;                                //指定对象

}         //取代了Female.prototype=new  Person();

          //也取代了Female.prototype.constrcutor=Female

inheritPrototype(Female,Person);

Female.prototype.sayAge=function(){

console.log(this.name+'   '+this.age);

}

var

fm=new   Female('skila','female',19);

 fm.sayName();           //skila female 19

fm.sayAge();                 //skila19

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,911评论 5 460
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,014评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 142,129评论 0 320
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,283评论 1 264
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,159评论 4 357
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,161评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,565评论 3 382
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,251评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,531评论 1 292
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,619评论 2 310
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,383评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,255评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,624评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,916评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,199评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,553评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,756评论 2 335

推荐阅读更多精彩内容