js的一些语言特性

函数的一些内部属性

1.arguments

arguments保存了函数的参数,是一个类数组对象。该对象有一个属性callee,指向arguments所属的函数对象,下面是一个阶乘的例子:

    <pre><code>    

    function factorial(num){

            if (num <= 1) {

                return 1;

            } else {

                return num * arguments.callee(num-1)

            }

        }

        var trueFactorial = factorial;

       

        factorial = function(){

            return 0;

        };

       

        alert(trueFactorial(5)); //120

        alert(factorial(5)); //0</code></pre>

2.this指针<br/> &nbsp; &nbsp; &nbsp; &nbsp;this指针指向了调用该函数的上下文对象<br/>

3.caller<br/> &nbsp; &nbsp; &nbsp; &nbsp;

caller返回一个对函数的引用,该函数调用了当前函数。如果函数是由顶层调用的,那么 caller 包含的就是 null 。<br/>

3.length<br/> &nbsp; &nbsp; &nbsp; &nbsp;

length属性返回函数希望接受的命名参数的个数。</br>

4.prototype属性<br/> &nbsp; &nbsp; &nbsp; &nbsp;

prototype下面有两个属性:apply和call。aplly和call的目的相同:都是为了在特定的作用域中调用函数,实际上等于设置函数体内this的值。但用法稍微有些区别。<br/> &nbsp; &nbsp; &nbsp; &nbsp;

apply接受的参数是:在其中运行的作用域,和一个参数数组(可以是一个Array,也可以是arguments对象)<br/> &nbsp; &nbsp; &nbsp; &nbsp;

call接受的参数:第一个也是this,后面是直接传进来的列举出来的参数。<br/> &nbsp; &nbsp; &nbsp; &nbsp;

<pre><code> 

    window.color = "red";

        var o = { color: "blue" };

       

        function sayColor(){

            alert(this.color);

        }

       

        sayColor(); //red

       

        sayColor.call(this); //red

        sayColor.call(window); //red

        sayColor.call(o); //blue</code></pre>

<br/> &nbsp; &nbsp; &nbsp; &nbsp;

bind()创建了一个函数,当这个函数在被调用的时候,它的 this 关键词会被设置成被传入的值(这里指调用bind()时传入的参数)。bind()的一种实现方式如下:

<pre><code>

Function.prototype.bind = function (scope) {

    var fn = this;

    return function () {

        return fn.apply(scope);

    };

}

</code></pre>

<br/> &nbsp; &nbsp; &nbsp; &nbsp;

</p>

##JavaScript面向对象程序设计

1.Object与属性特性

<br/> &nbsp; &nbsp; &nbsp; &nbsp;

对象的属性里含有各种特性:可以通过Object对象提供的API来进行设置。下面是一些常用的特性(attribute)<br/>

*    

[[Value]]: 属性的数据值

*    

[[Writable]]:是否能够修改属性的数据值

*    

[[get]]:读取属性时调用的函数

*    

[[set]]:写入属性时调用的函数

<br/>

可以使用Object.defineProperty(),Object.defineProperties()和Object.getOwnPropertyDescriptor()方法对这些特性进行修改及获取。</br>

2.创建对象的模式<br/>

2.1使用Object对象

<br/> &nbsp; &nbsp; &nbsp; &nbsp;

<pre><code>var person=new Object();

person.name="fsk";

person.age=25;

person.info=function(){

   alert("name: "+this.name +"  "+"age: "+this.age);

};</pre></code>

2.2字面量创建

<pre><code>

var person={

name:"fsk",

age:25,

info:function(){

   alert("name: "+this.name +"  "+"age: "+this.age);

}

};

</pre></code>

2.3工厂模式

<pre><code>

function createPerson(name,age)

{

  var o=new Object();

  o.name=name;

  o.age=age;

  o.info=function(){

    alert("name: "+this.name +"  "+"age: "+this.age);

  }

  return o;

}

//产生一个对象。

var person=createPerson("fsk",25);

</pre></code>

2.4构造函数模式

<pre><code>

function Person(name, age) {

  this.name = name;

  this.age = age;

  this.info = function() {

    alert("name: " + this.name + "  " + "age: " + this.age);

  };

}

var person = new Person("fsk", 25);

</pre></code>

这种方式构造对象经历的步骤如下:

*    

创建一个新对象;

*    

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

*    

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

*    

返回新对象;

这种模式相对于2.3的好处在于,可以识别对象的类型。通过构造函数创建的新实例都有一个constructor属性,该属性指向Person。instanceof操作符也可以判别构造出对象的类型。

构造函数也可以直接作为函数来使用

<pre><code>

    function Person(name, age, job){

            this.name = name;

            this.age = age;

            this.job = job;

            this.sayName = function(){

                alert(this.name);

            };

        }

       

        var person = new Person("Nicholas", 29, "Software Engineer");

        person.sayName(); //"Nicholas"

       

        Person("Greg", 27, "Doctor"); //adds to window

        window.sayName(); //"Greg"

       

        var o = new Object();

        Person.call(o, "Kristen", 25, "Nurse");

        o.sayName(); //"Kristen"

</pre></code>

使用构造函数的主要问题,就是在每一个方法都要在每个实例上创建一遍

2.5原型模式

创建的每个函数都有一个prototype(原型)属性,这个属性是一个指针,指向一个对象,而这个对象的用途是包含可以有特定类型的所有实例类型共享的属性和方法。

在默认情况下,所有原型对象都会自动获得一个constructor属性,这个属性包含一个指向prototype属性所在函数的指针。Person.prototype.constructor指向Person自身。

通过构造函数创建的实例包含一个指针,指向构造函数的原型对象。这个指针的名字叫[[Prototype]]。这个指针对于脚本是不可见的。原型对象的结构如下图所示

!

[](file:///C:/Users/由美/AppData/Local/Temp/calibre_oihsxy/bjpgnj_ebook_iter/OEBPS/images/f185-01.jpg)

对原型对象所做的任何修改都会立即从实例上反应出来,即使是先创建了实例后修改原型也是这样:

<pre><code>

    function Person(){

        }

       

        var friend = new Person();

               

        Person.prototype = {

            constructor: Person,

            name : "Nicholas",

            age : 29,

            job : "Software Engineer",

            sayName : function () {

                alert(this.name);

            }

        };

       

        friend.sayName(); //error

</code></pre>

重写原型对象切断了现有原型与之前已经存在的对象实例的联系,它们引用的仍然是最初的原型。

!

[](file:///C:/Users/由美/AppData/Local/Temp/calibre_oihsxy/bjpgnj_ebook_iter/OEBPS/images/f195-01.jpg)

原型模式缺点:它省略了为构造函数传递初始化参数这一环节,结果所有实例在默认情况下都将取得相同的属性值。原型中所有属性是被很多实例共享的,这种对于函数非常适合,对那些包含基本值的属性到也说得过去。可以通过在实例上添加一个同名属性,可以隐藏原型中的对应属性。然而,对于包含引用类型值的属性,它是指向同一个指针的。

2.6组合使用构造函数模式和原型模式</br>

此组合模式是创建自定义类型最常见方式,构造函数模式用于定义实例属性,而原型模式用于定义方法和共享的属性。

<pre><code>

 function Person(name, age) {

    this.name = name;

    this.age = age;

  }

  Person.prototype = {

    constructor: Person,

    info: function() {

      alert("name: " + this.name + "  " + "age: " + this.age);

    }

  }

  var person = new Person("singsong", 23);

  person.info();

}

</code></pre>

2.7动态原型模式</br>

动态原型模式把所有信息都封装在构造函数中。通过在构造函数中初始化原型,有保持了同时使用构造函数和原型的优点。

<pre><code>

function Person(name, age) {

  this.name = name;

  this.age = age;

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

    Person.prototype.info = function() {

      alert("name: " + this.name + "  " + "age: " + this.age);

    }

  };

}

var person = new Person("singsong", 23);

person.info();

</pre></code>

使用动态原型模式时,不能使用对象字面量重写原型,如果在已经创建了实例的情况下重写原型,那么就会切断现有实例与新原型之间的联系。

2.8寄生构造函数模式

这种模式的基本思想是创建一个函数,该函数的作用仅仅是封装创建对象的代码,然后返回新创建的对象。

<pre><code>

function Person(name, age) {

    var o = new Object();

    o.name = name;

    o.age = age;

    o.info = function() {

      alert("name: " + this.name + "  " + "age: " + this.age);

    };

    return o;

  }

  var person = new Person("singsong", 23);

  person.info();

</pre></code>

除了使用new操作符并把使用的包装函数叫做构造函数之外,这个模式跟工厂模式其实是一模一样。构造函数在不返回值得情况下,默认会返回新对象实例。而通过在构造函数的末尾添加一个return语句,可以重写调用构造函数时返回的值。</br>

这个模式可以在特殊的情况下用来为对象创建构造函数。如由于不能直接修改原生对象的构造函数,可以借助此模式,重创建构造函数来添加额外方法。</br>

注意:寄生构造函数模式返回的对象与构造函数或者与构造函数的原型属性之间没有关系;也就是说,构造函数返回的对象与在构造函数外部创建的对象没有什么不同。因此,就不能依赖instanceof操作符来确定对象类型了。由于存在此上述问题,建议在可以使用其他模式的情况下,不要使用这种模式。

3.继承的实质

js将原型链作为实现继承的主要方法。如以下代码:

<pre><code>

function SuperType(){

    this.property = true;

}

                   

SuperType.prototype.getSuperValue = function(){

    return this.property;

};

                   

function SubType(){

    this.subproperty = false;

}

                   

//inherit from SuperType

SubType.prototype = new SuperType();

                   

SubType.prototype.getSubValue = function (){

    return this.subproperty;

};

                   

var instance = new SubType();

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

</code></pre>

在上述代码中,subType的prototype作为了Supertype的实例出现。于是subType.prototype中的constructor属性消失了,它就像一个实例一样拥有了[[Prototype]]属性,该属性指向了SuperType.prototype.

!

[](file:///C:/Users/由美/AppData/Local/Temp/calibre_oihsxy/bjpgnj_ebook_iter/OEBPS/images/f203-01.jpg)

因为所有的函数的默认原型都是Object的实例,因此默认原型都会包含一个内部指针,指向Object.prototype。这也正是所有自定义类型都继承toString(),valueOf()等默认方法的原因

!

[](file:///C:/Users/由美/AppData/Local/Temp/calibre_oihsxy/bjpgnj_ebook_iter/OEBPS/images/f204-01.jpg)

##闭包

闭包是指有权访问另一个函数作用域中变量的函数。如下列代码:</br>

<pre><code>

function createComparisonFunction(propertyName) {

                   

    return function(object1, object2){

        var value1 = object1[propertyName];

        var value2 = object2[propertyName];

        if (value1 < value2){

            return -1;

        } else if (value1 > value2){

            return 1;

        } else {

            return 0;

        }

    };

}

</code></pre>

内部函数的前两行访问了外部函数的变量propertyName,即使这个函数返回了,而且在其它的函数进行调用,它仍然可以访问变量propertyName。因为内部函数的作用域链包含了createComparisonFunction的作用域链。

createComparisonFunction()执行完毕后,其活动对象也不会销毁,因为匿名函数的作用域链仍然在引用这个活动对象。被销毁是它的作用域链,但是活动对象仍然在内存中,直到匿名函数被销毁后,createComparisonFunction()的活动对象才会被销毁。

!

[](file:///C:/Users/由美/AppData/Local/Temp/calibre_oihsxy/bjpgnj_ebook_iter/OEBPS/images/f223-01.jpg)

在闭包中传递this对象也可能会导致一些问题。下列代码执行时:

<pre><code>

var name = "The Window";

                   

var object = {

    name : "My Object",

                   

    getNameFunc : function(){

        var that = this;

        return function(){

            return that.name;

        };

    }

};

                   

alert(object.getNameFunc()());  //"My Object"

</code></pre>

每个函数在被调用时都会获得两个特殊变量:this和arguments。内部函数在搜索这两个变量时,只会搜索到其活动对象为止,因此永远不可能直接访问到外部函数中的这两个变量。

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

推荐阅读更多精彩内容