说说javacsript的函数

Javascript的函数调用javascript

使用return语句时,函数会中止执行,并返回指定的值。html

JavaScript 函数内部声明的变量(使用 var)是局部变量,因此只能在函数内部访问它。(该变量的做用域是局部的)。当函数被执行完以后就会被删除,自动被销毁。java

您能够在不一样的函数中使用名称相同的局部变量,由于只有声明过该变量的函数才能识别出该变量。编程

函数的参数也是局部变量。数组

只要函数运行完毕,本地变量就会被删除。浏览器

在函数外声明的变量是全局变量,全局变量会在页面关闭后被删除,被销毁。app

向未声明的 JavaScript 变量分配值函数式编程

若是您把值赋给还没有声明的变量,该变量将被自动做为全局变量声明。函数

这条语句:学习

carname="Volvo";

将声明一个全局变量 carname,即便它在函数内执行。

函数表达式

JavaScript 函数能够经过一个表达式定义,须要以分号结束。

函数表达式能够存储在变量中:

在函数表达式存储在变量后,变量也可做为一个函数使用:

var x = function (a, b) {return a * b};

var z = x(4, 3);

以上函数其实是一个 匿名函数 (函数没有名称)

函数存储在变量中,不须要函数名称,一般经过变量名来调用。

Function() 构造函数

在以上实例中,咱们了解到函数经过关键字 function 定义。

函数一样能够经过内置的 JavaScript 函数构造器(Function())定义。

实例

var myFunction = new Function("a", "b", "return a * b");

var x = myFunction(4, 3);

实际上,你没必要使用构造函数。上面实例能够写成:

实例

var myFunction = function (a, b) {return a * b}

var x = myFunction(4, 3);

JavaScript 中,不少时候,你须要避免使用 new 关键字。

methods这一律念在JavaScript中的表现就是,一个对象的属性是一个function:一样的是函数,将其赋值给一个对象的成员之后,就不同了。将函数赋值给对象的成员后,那么这个就不在称为函数,而应该叫作方法

函数提高?

 

1var 变量预编译

 

JavaScript 的语法和 C JavaC# 相似,统称为 C 类语法。有过 C Java 编程经验的同窗应该对“先声明、后使用”的规则很熟悉,若是使用未经声明的变量或函数,在编译阶段就会报错。然而,JavaScript 却可以在变量和函数被声明以前使用它们。下面咱们就深刻了解一下其中的玄机。

 

先来看一段代码:

 (function() {

 console.log(noSuchVariable);//ReferenceError: noSuchVariable is not defined

})();

 

运行上面代码立马就报错,不过,这也正是咱们指望的,由于 noSuchVariable 变量根本就没有定义过嘛!再来看看下面的代码:

 (function() {

 console.log(declaredLater); //undefined

 var declaredLater = "Now it's defined!";

 console.log(declaredLater);// "Now it's defined!"

})();

 

 

首先,上面这段代码是正确的,没有任何问题。可是,为何不报错了?declaredLater 变量是在调用语句后面定义的啊?为何竟然输出的是 undefined

 

这实际上是 JavaScript 解析器搞的鬼,解析器将当前做用域内声明的全部变量和函数都会放到做用域的开始处,可是,只有变量的声明被提早到做用域的开始处了,而赋值操做被保留在原处。上述代码对于解析器来讲实际上是以下这个样子滴:

 (function() {

 var declaredLater; //声明被提早到做用域开始处了!

 console.log(declaredLater); // undefined

 declaredLater = "Now it's defined!"; //赋值操做还在原地!

 console.log(declaredLater);//"Now it's defined!"

})();

 

 

这就是为何上述代码不报异常的缘由!变量和函数通过“被提早”以后,declaredLater 变量其实就被放在了调用函数的前面,根据 JavaScript 语法的定义,已声明而未被赋值的变量会被自动赋值为 undefined ,因此,第一次打印 declaredLater 变量的值就是 undefined,后面咱们对 declaredLater 变量进行了赋值操做,因此,第二次再打印变量就会输出Now it's defined!

 

再来看一个例子:

var name = "Baggins";

(function () {

 console.log("Original name was " + name);// "Original name was undefined"

 var name = "Underhill";

 console.log("New name is " + name);// "New name is Underhill"

})();

 

 

上述代码中,咱们先声明了一个变量 name ,咱们的本意是但愿在第一次打印 name 变量时可以输出全局范围内定义的 name 变量,而后再在函数中定义一个局部 name 变量覆盖全局变量,最后输出局部变量的值。但是第一次输出的结果和咱们的预期彻底不一致,缘由就是咱们定义的局部变量在其做用域内被“提早”了,也就是变成了以下形式:

var name = "Baggins";

(function () {

 var name; //注意:name 变量被提早了!

 console.log("Original name was " + name);// "Original name was undefined"

 name = "Underhill";

 console.log("New name is " + name);//"New name is Underhill"

})();

 

 

因为 JavaScript 具备这样的“怪癖”,因此建议你们将变量声明放在做用域的最上方,这样就能时刻提醒本身注意了。

 

2、函数声明“被提早”

 

前边说的是变量,接下来咱们说说函数。

 

函数的“被提早”还要分两种状况,一种是函数声明,第二种是函数做为值赋值给变量,也即函数表达式。

 

先说第一种状况,上代码:

isItHoisted();//"Yes!"

function isItHoisted() {

 console.log("Yes!");

}

 

如上所示,JavaScript 解释器容许你在函数声明以前使用,也就是说,函数声明并不只仅是函数名“被提早”了,整个函数的定义也“被提早”了!因此上述代码可以正确执行。

 

再来看第二种状况:函数表达式形式。仍是先上代码:

definitionHoisted();// "Definition hoisted!"

definitionNotHoisted();// TypeError: undefined is not a function

function definitionHoisted() {

 console.log("Definition hoisted!");

}

var definitionNotHoisted = function () {

 console.log("Definition not hoisted!");

};

 

 

咱们作了一个对比,definitionHoisted 函数被妥妥的执行了,符合第一种类型;definitionNotHoisted 变量“被提早”了,可是他的赋值(也就是函数)并无被提早,从这一点上来讲,和前面咱们所讲的变量“被提早”是彻底一致的,而且,因为“被提早”的变量的默认值是 undefined ,因此报的错误属于“类型不匹配”,由于 undefined 不是函数,固然不能被调用。

 

总结

经过上面的讲解能够总结以下:

 

var的做用域是函数做用域由var定义的变量,它做用域在一个函数体内,而不是咱们其余语言理解的大括号{ }内。

 

使用var声明的变量,其做用域为该语句所在的函数内,且存在变量提高现象;

 

变量的声明被提早到做用域顶部,赋值保留在原地

函数声明整个“被提早”

函数表达式时,只有变量“被提早”了,函数没有“被提早”

3var的反作用

 

隐式全局变量和明肯定义的全局变量间有些小的差别,就是经过delete操做符让变量未定义的能力。

 

经过var建立的全局变量(任何函数以外的程序中建立)是不能被删除的。

 var建立的隐式全局变量(无视是否在函数中建立)是能被删除的。

 这代表,在技术上,隐式全局变量并非真正的全局变量,但它们是全局对象的属性。属性是能够经过delete操做符删除的,而变量是不能的:

// 定义三个全局变量

var global_var = 1;

global_novar = 2;  // 反面教材

(function () {

 global_fromfunc = 3; // 反面教材

}());

 

// 试图删除

delete global_var;  // false ,声明的变量不能够被删除

delete global_novar; // true,非严格模式下,未声明的变量能够被当作是属性能够删除

delete global_fromfunc; // true

 

// 测试该删除

typeof global_var;  // "number"

typeof global_novar; // "undefined"

typeof global_fromfunc; // "undefined"

 

 

ES5严格模式下,无论是已声明的全局变量,仍是未声明的隐示全局变量,执行删除操做上会抛出一个错误。

使用 "use strict" 指令,开启严格模式。严格模式经过在脚本或函数的头部添加 "use strict"; 表达式来声明。在函数内部声明是局部做用域 (只在函数内使用严格模式)

严格模式下不能使用未声明的变量!

 

严格模式的限制有哪些??

 

 

 

 

4、单var形式声明变量

 

在函数顶部使用单var语句是比较有用的一种形式,其好处在于:

 

提供了一个单一的地方去寻找功能所须要的全部局部变量

 防止变量在定义以前使用的逻辑错误

 少代码(类型啊传值啊单线完成)

 var形式长得就像下面这个样子:

 

function func() {

 var a = 1,

  b = 2,

  sum = a + b,

  myobject = {},

  i,

  j;

 // function body...

}

您可使用一个var语句声明多个变量,并以逗号分隔。像这种初始化变量同时初始化值的作法是很好的。这样子能够防止逻辑错误(全部未初始化但声明的变量的初始值是undefined)和增长代码的可读性。在你看到代码后,你能够根据初始化的值知道这些变量大体的用途。

 

以上就是针对javascriptvar预解析与函数声明提高的学习内容,但愿对你们的学习有所帮助。

自调用函数?(4

1  ( function(){alert(1);}() );

2  (function(){alert(1);}) ();

3  !function(){alert(1);}();

4  void function(){alert(2);}();

函数是对象

JavaScript 中使用 typeof 操做符判断函数类型将返回 "function"

可是JavaScript 函数描述为一个对象更加准确。

JavaScript 函数有 属性 和 方法。(arguments.length;??)

arguments.length 属性返回函数调用过程接收到的参数个数:

实例

function myFunction(a, b) {

    return arguments.length;

}

toString() 方法将函数做为一个字符串返回:

实例

function myFunction(a, b) {

    return a * b;

}

var txt = myFunction.toString();//function myFunction(a, b) { return a * b; }

函数参数?

javascript函数参数

js函数参数有显式参数(Parameters)即形参和隐式参数(Arguments)实参

1、显式参数(Parameters)即形参在函数定义时列出。

function functionName(parameter1, parameter2, parameter3){

    //要执行的代码

}

2、隐式参数(Arguments)即实参在函数调用时传递给函数的真正的值

function add(){

    console.log(arguments[0], arguments[1], arguments[2]);

}
add(1,2,3);//1 2 3

参数的个数

1)当实参比比函数声明指定的形参个数少时,剩下的形参都将设置为undefined

例:

function add(x, y){

    console.log(x, y);

}

add(1);//1, undefined

2)当实参比形参个数要多时,剩下的实参没办法直接得到,能够经过arguments对象来访问。在javascript中函数的参数在函数内部是用一个数组表示的。函数接收的始终都是这个数组,并不关心数组中包含哪些参数。而arguments是一个类数组对象,可使用方括号语法来访问它的每个元素。

例:

function add(x, y){

    console.log(arguments[0], arguments[1], arguments[2]);

}

add(1, 2, 3);//1 2 3

arguments对象的length属性能够显示实参的个数,函数的length属性则显示形参的个数。

例:

function add(x, y){

    console.log(arguments.length);//3}

add(1, 2, 3);

console.log(add.length);//2

形参能够提供便利,但不是必须的。

function add(){

    console.log(arguments[0] + arguments[1]);

}

add(1, 2);//3

实参与形参同步

  当形参与实参个数相同时,arguments对象的值和对应形参的值保持同步,但命名空间独立。

例:

function test(num1, num2){

    console.log(num1, arguments[0]);//1 1

    arguments[0] = 2;

    console.log(num1, arguments[0]);//2 2

    num1 = 10;

    console.log(num1, arguments[0]);//10 10}

test(1);

  在严格模式下,arguments对象的值和形参都是独立的。

例:

function test(num1, num2){

    'use strict';

    console.log(num1, arguments[0]);//1 1

    argument[0] = 2;

    comnsole.log(num1, arguments[0]);//1 2

    num1 = 10;

    console.log(num1, arguments[0]);//10 2}

test(1);

  当形参并无对应的实参时,arguments对象的值与形参的值并不对应。

例:

function test(num1, num2){

    console.log(num1, arguments[0]);//undefined, undefined

    num1 = 10;

    arguments[0] = 5;

    console.log(num1, arguments[0]);//10, 5}

test();

对象参数:当一个函数包含超过3个形参时,要记住调用函数中实参的正确顺序是一件很繁琐的事情,能够经过值对的形式来传入参数。

参数的传递

  javascript中全部函数的参数都是按值传递的。也就是说,把函数外部的值复制给函数内部的参数,就和把值从一个变量复制到另外一个变量同样,当传递的值是基本类型时,复制的是值自己。而参数为引用类型时,会把这个值在内存中的地址复制给一个局部变量。

1)基本类型值的传递(传递的值是变量值的副本。)

  在向参数传递基本类型的值时,被传递的值会被复制给一个局部变量(命名参数或arguments对象的一个元素)。

function add(num){

    num += 10;

    return num;

}var count = 20;

console.log(add(count));//30

console.log(count);//20

2)引用类型值的传递(传递的值是一个指向对象的指针。)

   在向参数传递引用类型的值时,会把存储在变量对象中的值复制一份放到为新变量分配的空间中,这个新变量的值是原对象的地址,也指向原对象。不一样的是,这个值的副本其实是一个指针,而这个指针指向存储在堆中的一个对象。复制操做结束后,两个变量实际上引用同一个对象,所以改变其中一个变量,就会影响另一个变量。

var person = {

    name:'Tom'

};function obj(peo){

    peo.name = 'Jerry';

    return peo;

}var result = obj(person);

console.log(result.name);//Jerry

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

  在上面的例子中,把personperson是一个指向{name‘Tom’}这个对象的指针)复制传入obj()中并赋值给了局部变量peo(按值传递),peoperson指向了同一个对象,而在obj()函数中peo指针经过引用修改了对象中的name属性,其实修改了personpeo共同指向的对象的name属性,相对应的外部person引用的name属性也就改变了,因此打印出来的为Jerry

咱们再看一个例子:

3)共享类型值的传递

var person = {

    name:'Tom'

};function obj(peo){

    peo = {

        name:'Jerry'

    };

    return peo;

}var result = obj(person);

console.log(result.name);//Jerry

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

  在上述例子中,与前一个并无什么不一样,咱们只是在函数内对peo变量进行了从新赋值,将一个新对象的引用地址赋值给了peo,因此peo指向的是函数内部建立的新对象,和所有变量person指向老的对象是不同的。

注:

1)引用传递:指在调用函数时,即传递是原对象引用的一个副本(原对象的地址),可是这个副本跟原对象的引用指向的都是内存中的对象!

2)共享传递:在共享传递中对函数形参的直接赋值也就是给形参直接赋值后,形参的值再也不是原对象的地址了,指向了另一个对象,所以不会影响实参的值,即原对象的值

 

Arguments 对象

 

JavaScript 函数有个内置的对象 arguments 对象。

javascript中的arguments对象

js中一切都是对象,连函数也是对象,函数名实际上是引用函数定义对象的变量。

1、什么是arguments

这个函数体内的arguments很是特殊,其实是所在函数的一个内置类数组对象,能够用数组的[i].lengtharguments对象是比较特别的一个对象,其实是当前函数的一个内置属性。arguments很是相似Array,但实际上又不是一个Array实例。

arguments.length是有实参决定,即函数调用时候里面的参数个数决定!

 

arguments对象的长度是由实参个数而不是形参个数决定的。形参是函数内部从新开辟内存空间存储的变量,可是其与arguments对象内存空间并不重叠。对于arguments和值都存在的状况下,二者值是同步的,可是针对其中一个无值的状况下,对于此无值的情形值不会得以同步。以下代码能够得以验证。

 1 function f(a, b, c){

 2     alert(arguments.length);   // result: "2"

 3     a = 100;

 4     alert(arguments[0]);       // result: "100"

 5     arguments[0] = "qqyumidi";

 6     alert(a);                  // result: "qqyumidi"

 7     alert(c);                  // result: "undefined"

 8     c = 2012;

 9     alert(arguments[2]);       // result: "undefined"

10 }

11

12 f(1, 2);

 

JavaScript中函数的声明和调用特性,能够看出JavaScript中函数是不能重载的。

 

根据其余语言中重载的依据:"函数返回值不一样或形参个数不一样",咱们能够得出上述结论:

 

第一:Javascript函数的声明是没有返回值类型这一说法的

 

第二:JavaScript中形参的个数严格意义上来说只是为了方便在函数中的变量操做,实际上实参已经存储在arguments对象中了。

 

另外,从JavaScript函数自己深刻理解为何JavaScript中函数是不能重载的:在JavaScript中,函数其实也是对象,函数名是关于函数的引用,或者说函数名自己就是变量。对于以下所示的函数声明与函数表达式,其实含义上是同样的(在不考虑函数声明与函数表达式区别的前提下),很是有利于咱们理解JavaScript中函数是不能重载的这一特性。

function f(a){

   return a + 10;

 }

function f(a){

return a - 10;}

 

 // 在不考虑函数声明与函数表达式区别的前提下,其等价于以下

var f = function(a){

eturn a + 10;}

var f = function(a){

 return a - 10;}

2、有什么做用?

js语法不支持重载!但可用arguments对象模拟重载效果。

arguments对象:函数对象内,自动建立的专门接收全部参数值得类数组对象。
arguments[i]: 得到传入的下标为i的参数值
arguments.length: 得到传入的参数个数!

重载:

  程序中可定义多个相同函数名,不一样参数列表的函数,
  调用者没必要区分每一个函数的参数,
  执行时,程序根据传入的参数个数,自动判断选择哪一个函数执行。

例子以下:

// 1、若是用户传入一个参数,求平方

    function sum(a){

        console.log(a*a);

    }

 

    //若是用户传入两个参数,就求和

    function sum(a,b){

        console.log(a+b);

    }

    sum(4); //

    sum(4,5); //

上述例子中本意是想让同名函数sum()根据参数不一样输出不一样结果,可是sum是函数名字,本质也是个变量,

第二个会覆盖第一个,因此上述的正确输出答案是:NaN,9.因此这样显然不能够。

若是用arguments,就简单多了。

以下2个例子:

//2

    function calc(){

        //若是用户传入一个参数,求平方

        if(arguments.length==1){

            console.log(arguments[0]*arguments[0]);

        }else if(arguments.length==2){

        //若是用户传入两个参数,就求和

            console.log(arguments[0]+arguments[1]);

        }

    }

    calc(4); //16

    calc(4,5); //9

/*3、不管用户传入几个数字,均可以求和*/

    function add(){

        //arguments:[]

        //遍历arguments中每一个元素,并累加

        for(var i=0,sum=0;i<arguments.length;sum+=arguments[i++]);

        return sum;//返回和    }

 

    console.log(add(1,2,3)); //6

    console.log(add(1,2,3,4,5,6)); //21

这就是JS利用arguments重载的效果,简单理解就是一个函数重复利用.

arguments.length是有实参决定,即函数调用时候里面的参数个数决定!

 

4arguments对象中有一个很是有用的属性:calleearguments.callee返回此arguments对象所在的当前函数引用。在使用函数递归调用时推荐使用arguments.callee代替函数名自己。

 

以下:

 function count(a){

    if(a==1){

         return 1;}

 return a + arguments.callee(--a);

}

 var mm = count(10);

 alert(mm);

 

函数式编程的特性,??

函数的调用?

javascript的执行函数的四种方式

javascript的函数调用和构造函数调用

 

1 函数调用

Function绝对是JavaScript中的重中之重。在JavaScript中,Function承担了procedures, methods, constructors甚至是classes以及modules的功能。 
在面向对象程序设计中,functions,methods以及class constructor每每是三件不一样的事情,由不一样的语法来实现。可是在JavaScript中,这三个概念都由function来实现,经过三种不一样的模式。 
最简单的使用模式就是function 调用:

function hello(username) {

  return "hello, " + username;

}

hello("Keyser Söze"); // "hello, Keyser Söze"

 

/*函数调用模式*/

    

    var add=function(a,b){

        alert(this)//this被绑顶到window

            return a+b;

        }

    var sum=add(3,4);

    alert(sum)

2 方法调用

methods这一律念在JavaScript中的表现就是,一个对象的属性是一个function,一样的是函数,将其赋值给一个对象的成员之后,就不同了。将函数赋值给对象的成员后,那么这个就不在称为函数,而应该叫作方法。

var obj = {

  hello: function() {

    return "hello, " + this.username;

  },

  username: "Hans Gruber"

};

obj.hello(); // "hello, Hans Gruber"  

 

 

/*方法调用模式*/

    var myobject={

            value:0,

            inc:function(){

                    alert(this.value)

                }

        }

    myobject.inc()

 

 

真正的行为是,调用自己才会决定this会绑定到哪一个对象,即: 
obj1.hello()会将this绑定到obj1,obj2.hello()则会将this绑定到obj2。记住一句话,谁是最后调用方法的,this就指向谁。 
正由于this绑定的这种规则,在下面的用法也是可行的:

function hello() {

  return "hello, " + this.username;

}

 

var obj1 = {

  hello: hello,

  username: "Gordon Gekko"

};

obj1.hello(); // "hello, Gordon Gekko"

 

var obj2 = {

  hello: hello,

  username: "Biff Tannen"

};_

obj2.hello(); // "hello, Biff Tannen"

可是,在一个普通的函数中,如上面的hello函数,使用this关键字是不太好的方式,当它被直接调用的时候,this的指向就成了问题。在这种状况下,this每每被指向全局对象(GlobalObject),在浏览器上通常就是window对象。 
而这种行为是不肯定和没有意义的。 
因此在ES5标准中,若是使用了strict mode,那么this会被设置为undefined:

function hello() {

  "use strict";

  return "hello, " + this.username;

}

hello(); // error: cannot read property "username" of undefined

以上这种作法是为了让潜在的错误更快的暴露出来,避免了误操做和难以找到的bug。 
区别普通函数调用和方法调用,直接看这个例子就明确了。

var func = function() {

  alert(this);

};

var o = {};

o.fn = func;//”=”号给o对象自身添加一个属性,并把一个函数赋值给该属性,也便是方法。

// 比较

alert(o.fn === func);//true

 

// 调用

func();//[object Window]

o.fn();//[object Object]

这里的运行结果是,两个函数是相同的,所以打印结果是 true。可是因为两个函数的调用是不同的,func 的调用,打印的是 [object Window],而o.fn 的打印结果是 [object Object]。 
这里即是函数调用与方法调用的区别,函数调用中,this 专指全局对象 window,而在方法中 this 专指当前对象,即 o.fn 中的 this 指的就是对象o。

3 构造函数

function的第三种使用模式就是讲它做为constructor: 
构造器中的this 
咱们须要分析建立对象的过程,方能知道this的意义. 以下面代码:

/*构造器调用模式  摒弃*/

    

    var quo=function(string){

            this.status=string;

        }

    quo.prototype.get_status=function(){

            return this.status;

        }

    var qq=new quo("aaa");

    alert(qq.get_status());

 

 

var Person = function() {

 this.name = "小平果";

};

var p = new Person();

这里首先定义了函数Person,下面分析一下整个执行: 
程序在执行到第一句的时候,不会执行函数体,所以 JavaScript的解释器并不知道这个函数的内容. 
接下来执行new关键字,建立对象,解释器开辟内存,获得对象的引用,将新对象的引用交给函数. 
紧接着执行函数,将传过来的对象引用交给this. 也就是说,在构造方法中,this就是刚刚被new建立出来的对象. 
而后为this 添加成员,也就是为对象添加成员. 
最后函数结束,返回this,将this交给左边的变量. 
分析过构造函数的执行之后,能够获得,构造函数中的this就是当前对象. 
构造器中的return 
在构造函数中return的意义发生了变化,首先若是在构造函数中,若是返回的是一个对象,那么就保留原意. 若是返回的是非对象,好比数字、布尔和字符串,那么就返回this,若是没有return语句,那么也返回this. 看下面代码:

// 返回一个对象的 return

var ctr = function() {

 this.name = "赵晓虎";

 return {

 name:"牛亮亮"

 };

};

// 建立对象

var p = new ctr();

// 访问name属性

alert(p.name);

//执行代码,这里打印的结果是”牛亮亮”. 由于构造方法中返回的是一个对象,那么保留return的意义,返回内容为return后面的对象. 再看下面代码:

// 定义返回非对象数据的构造器

var ctr = function() {

 this.name = "赵晓虎";

 return "牛亮亮";

};

// 建立对象

var p = new ctr();

// 使用

alert(p);

alert(p.name);

代码运行结果是,先弹窗打印[object Object],而后打印”赵晓虎”. 由于这里 return 的是一个字符串,属于基本类型,那么这里的return语句无效,返回的是this对象. 所以第一个打印的是[object Object]而第二个不会打印undefined.

function User(name, passwordHash) {

  this.name = name;

  this.passwordHash = passwordHash;

}

var u = new User("sfalken",

  "0ef33ae791068ec64b502d6cb0191387");

u.name; // "sfalken"

使用new关键将function做为constructor进行调用。和function以及method调用不同的是,constructor会传入一个新的对象并将它绑定到this,而后返回该对象做为constructor的返回值。而constructor function自己的做用就是为了初始化该对象。 
构造函数调用常犯的一个错误 
兴致勃勃地定义了下面这么个构造函数:

var Coder = function( nick ){

this.nick = nick;

};

定义构造函数结束后呢?没错,赶忙实例化:

var coder = Coder( 'casper' );

  • 1

这个coder兄弟叫什么名字?赶忙打印下:

console.log( coder.nick ); //undefined 

居然是undefined!!再回过头看看实例化的那个语句,不难发现问题出在哪里:少了个new

var coder = Coder( 'casper' ); //看成普通的函数来调用,故内部的this指针其实指向window对象

console.log( window.nick); //输出:casper

var coder = new Coder( 'casper' ); //加上new,一切皆不一样,this正确地指向了当前建立的实例

console.log( coder.nick ); //输出:casper

这样的错误貌似挺低级的,但出现的几率挺高的,肿么去避免或减小这种状况的发生呢? 
能够在内部实现里面动下手脚:

var Coder = function( nick ){

  if( !(this instanceof Coder) ){

    return new Coder( nick );

  }

    this.nick = nick;

};

其实很简单,实例化的时候,内部判断下,当前this指向的对象的类型便可,若是非当前构造函数的类型,强制从新调用一遍构造函数。 
忽然以为Coder这名字不够洋气?想用Hacker,好吧,我改。。。数了下,一共有三处要改,这不科学,有没有办法只把构造函数的名字改了就行? 
固然有:

var Coder = function( nick ){

  if( !(this instanceof arguments.callee) ){

    return new arguments.callee( nick );

  }

  this.nick = nick;

};

4 间接调用

JavaScript , 函数是对象。JavaScript 函数有它的属性和方法。

call() apply() 是预约义的函数方法。 两个方法可用于调用函数,两个方法的第一个参数必须是对象自己。

区分apply,call就一句话,

foo.call(this, arg1,arg2,arg3) == foo.apply(this, arguments)==this.foo(arg1, arg2, arg3) 

例如: 
A, B类都有一个message属性(面向对象中所说的成员), 
A有获取消息的getMessage方法
B有设置消息的setMessage方法,

var b = new B();

//给对象a动态指派bsetMessage方法,注意,a自己是没有这方法的!

b.setMessage.call(a, "a的消息");

//下面将显示"a的消息"

alert(a.getMessage());

//给对象b动态指派agetMessage方法,注意,b自己也是没有这方法的!

alert(b.setMessage());

这就是动态语言 JavaScript call的威力所在!

简直是无中生有”,对象的方法能够任意指派,而对象自己一直都是没有这方法的,注意是指派,通俗点就是,方法是借给另外一个对象的调用去完成任务,原理上是方法执行时上下文对象改变了.

因此 b.setMessage.call(a, “a的消息”); 就等于用a做执行时上下文对象调用b对象的setMessage方法,而这过程当中与b一点关系都没有, 做用等效于a.setMessage( “a的消息”);

call, apply做用就是借用别人的方法来调用,就像调用本身的同样.

,理解了call, apply相同处—–做用后,再来看看它们的区别,看过上面例子,相信您大概知道了.

b.setMessage.call(a, “a的消息”) 等效于 a.setMessage( “a的消息”) 能够看出, “a的消息call中做为一个参数传递,

call, apply方法区别是,从第二个参数起, call方法参数将依次传递给借用的方法做参数, apply直接将这些参数放到一个数组中再传递, 最后借用方法的参数列表是同样的.当参数明确时可用call, 当参数不明确时可用apply给合arguments

相关文章
相关标签/搜索