1. 程序异常

try-catch语法    测试异常

try-catch语法代码如下:

try {

异常代码;     try中可以承重异常代码,

console.log(“try”)  出现异常代码后,正确代码不会执行

} catch (e) {

console.log(“e:”+e);  try中出现异常在e中展现出来

console.log(“catch”);  只有try中出现异常才执行这段代码

} finally {

console.log( 1 );  无论try中有无异常,都会执行finally代码

}

throw语法    抛出异常

throw(name: ”Tom”, age: 18)    抛出异常,抛出一个对象

2. 函数的预解析

代码如下:

console.log(fn1);

console.log(fn2);

var fn1= function () {};

function fn2(){}

表达式式函数:     var fn1= function () {};    ; 结尾

特点:没有函数名,预解析过程var fn1声明提升,”=”号的赋值没有执行,console.log(fn1)结果为undefined;

声明式函数:       function fn2(){}      不用;结尾

特点:有函数名(fn2),预解析过程已经将函数体赋值给了fn2,console.log(fn2)结果为function fn2(){}

3. 作用域经典问题

var  arr = [ { name: 'Tom' },

{ name: 'Jack' },

{ name: 'Jim' },

{ name: 'Lily' } ];

for ( var i = 0; i < arr.length; i++) {

arr[ i ].sayHello = function () {

console.log( 'name = ' + arr[ i ].name );

};

}

for ( var j = 0; j < arr.length; j++ ) {

arr[ j ].sayHello();

}

代码执行会报错,因为当执行arr[j].sayHello()时,函数中arr[i].name才执行,此时i的值已经为4了,如果把代码改为:

for ( var i = 0; i < arr.length; i++ ) {

arr[ i ].sayHello();

}

则可以顺利执行,因为调用函数sayHello()时,对i进行了重新赋值,进入函数作用域内后arr[i]也就变为动态变化的值了

该问题的由来,代码如下:

<ul>

<li>①</li>

<li>② </li>

<li>③</li>

<li>④</li>

<li>⑤ </li>

</ul>

var list = document.getElementsByTagName( 'li' );

var i;

for ( i = 0; i < list.length; i++ ){

list[ i ].onclick = function () {

alert( list[ i ].innerHTML );   点击进入函数作用域时i的值已经为5

            alert( this.innerHTML );   list[i]改为this,可以正常执行

};

}

4.函数相关参数

① arguments

arguments: 函数中默认的类似数组类型对象,里面存储了所有传入的参数

② 函数名.length

函数中所有参数的个数,若无参数则为0;

综合使用案例,封装一个extend扩展函数,代码如下:

function extend() {       这种写法,只支持最多传入两个参数

var args = arguments;

if (args.length == 1) {

for (var k in args[0]) {

this[k] = args[0][k];

}

} else {

for (var k in args[1]) {

args[0][k] = args[1][k];

}

}

}

var o1 = {name: "Tom"};

var o2 = {age: 18, gender: "male"};

var o3 = {goHome: "bus"};

extend(o1, o2);     o2混入o1之中

o3.extend = extend;

o3.extend(o1);      o1添加到o3之中

console.log(o3);

③ calleecaller

1callee: 当前函数的引用

语法:arguments.callee

function foo() {

console.log(arguments.callee === foo);   返回值为true

}

foo();

callee一般在函数内部,实现函数递归时,使用callee表示函数引用

2caller: 表示在fn1中调用fn2    兼容性不佳

语法:函数名.caller   

function fn1() {

console.log(fn1.caller);      打印调用者fn2,打印结果如下:

}                                                       function fn2() { fn1() };

function fn2() {

fn1();

}

fn2();

5.eval(“ ”):动态执行函数

eval(“var num=12;” )函数中的声明会在整个作用域起作用

eval()Function()的比较

eval:直接调用就执行eval(“alert(“执行”);”),代码执行

Function:需要调用才执行,var fn = new Function(“alert(“执行”)”),这个过程是生成了一个函数,调用函数fn();代码执行,函数内声明只会在函数内起作用

使用Function的立即执行函数(自调用函数):

( new Function(“alert(“执行”)” )) ();对函数使用 (函数)();括号结构相当于执行了函数

任意函数的立即执行:

(function fn() {

alert("立即执行");

})();

json字符串转换成对象

不严格的json格式(属性没有写双引号””)但js能够识别如下:

var data='[{name:"Tom",age:18,gender:"male"},{name:"Jim",age:20,gender:"male"]';

1)使用eval(); 传入json使用( )括起来

var obj = eval(“(+data+)”);    转换后obj为json对象

*使用eval()为何需要将data用圆括号括起来( ),变成表达式:

a ) 标识符格式:任意名 + ,例如:label:

标识符的使用:

    label:

while (true) {

console.log("第一层循环");

while (true) {

console.log("第二层循环");

while (true) {

console.log("第三层循环");

  break label;

console.log("第三层循环");

}

console.log("第二层循环");

}

console.log("第一层循环");

}

执行结果如上图所示,使用标识符后,从第三层循环直接跳出所有循环

b ) eval()中添加括号的解释:

    var s1 = '{ }';

var o1 = eval(s1);

console.log(o1)      没有任何结果undefined

    var s2 = '{name: "Tom"}';

var o2 = eval(s2);

console.log(o2)        输出Tom

    var s3 = '{name: "Tom" , age: 18}';

var o3 = eval(s3);

console.log(o1)       直接报错

出现这种现象的原因是,eval( ){ }当做代码块来执行,o2中的name:被当做标识符所以输出”Tom”,而o3中的name:, age:被判定为用 ,号分割的标识符,是错误代码,所以直接报错,若将o3改为o3=eval(‘{name: “Tom” ; age: 18}’),使用; 号分割,则输出18,原因是系统默认age:标识符替换了name:标识符,所以最后解决这个问题的办法是用( )将代码括起来,变成表达式,再给eval( )解析

2)使用Function

var obj = (new Function(‘return’+data))();

3)使用标准处理:JSON.parse()该方法必须使用严格的json格式,即属性必须写双引号””

var data='[{"name":"Tom","age":18,"gender":"male"},{"name":"Jim","age":20,"gender":"male"]'

var obj = JSON.parse(data);

6.函数的四种调用模式

函数调用模式  func()

函数名+();

function func() {

console.log(this);

}

func();

函数是window   this指向window

方法调用模式  obj.func()

宿主对象obj调用函数,this指向引导方法的对象

function func() {

console.log(this);

}

func();

var obj = {name: "object"};

obj.func = func;

obj.func();

func():函数调用模式this指向window,obj.func():方法调用模式this指向obj

构造器调用模式(constructor  使用new关键字引导

new 是一个运算符,专门用来申请创建对象,创建出的对象传递给构造函数的this,利用构造函数对其初始化

1)构造函数创建对象时的返回值(打印对象)

如果构造函数没有设置参数,在创建对象时( )可以不写,例如:

var obj = new Person这样写即可

a ) 如果没有写返回值默认返回this

function Person() {

this.name = "Tom";

this.age = 18;

this.gender = "male";

}

var obj=new Person();

console.log(obj);             Person {name: "Tom" , age: 18 , gender: "male"}

b ) 如果返回值是基本数据类型numberstring则忽略返回类型,返回this

function Person() {

this.name = "Tom";

this.age = 18;

this.gender = "male";

return "string"||123;

}

var obj=new Person();

console.log(obj);          Person {name: "Tom" , age: 18 , gender: "male"}

c ) 如果返回值是引用数据类型,[ ]或者{ },则忽略this,返回该数据类型

function Person() {

this.name = "Tom";

this.age = 18;

this.gender = "male";

return [ ] || { };  /  return { } || [ ]

}

var obj=new Person();

console.log(obj);      [ ]  /  { }

2)综合分析题,代码如下:

function Foo(){

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

return this;

}

 Foo.getName = function(){ alert(2); };

 Foo.prototype.getName = function(){ alert(3); };

var getName = function(){ alert(4); };

function getName(){ alert(5); }

Foo.getName();

2  方法调用,只有alert(2)是该方法调用

getName();               

4  函数声明提前,最后赋值为alert(4)

Foo().getName();          

1  Foo()函数调用,返回window,进入函数体,getName赋值为alert(1),且被window调用,等于函数调用模式

getName();              

1 函数调用模式,在上步已经赋值为alert(1)

new Foo.getName();

2 创建Foo.getName()构造函数的对象,等于该方法调用alert(1)

new Foo().getName();

3  new与()相结合,等于new Foo()构造函数创建的对象{}调用getName,由于构造函数没有定义getName属性,但是定义了Foo.prototype.getName,所以该对象{}继承了自己原型对象的getName属性alert(3)

new new Foo().getName();

3 同上步,new Foo()构造函数创建的对象{},所以该代码相当于new {}.getName(等于{}的方法调用模式创建对象,同理上一步,到Foo的原型对象找getName属性alert(3),这一步与上一步的区别是,上一步最后执行方法调用函数,这一步最后以上一步执行的方法调用函数为构造函数,创建对象

上下文(环境)调用模式applycall

1apply   参数以数组形式传入

a ) apply只传一个对象的函数调用

function fn() {

console.log(this);

}

var obj = {name: "Tom", age: 18};

fn();

fn.apply(null);     apply中传入一个null或者不传参数    apply( ),等于函数调用模式

obj.func =fn;

obj.func();

fn.apply(obj);    apply中传入一个对象,等于该对象的方法调用模式

上面代码的运行结果为:

fn()fn.apply(null)等价,obj.func()fn.apply(obj)等价

b ) apply传入参数的函数调用   数组参数

语法: function fn ( argu1 , argu2 ) { }; 函数

fn.apply ( obj , [argu1 , argu2] )

示例代码如下:

function fn(num1, num2) {

console.log(this);

return num1 + num2;

}

var obj = {name: "Tom", age: 18};

obj.func = fn;

console.log(obj.func( 123 , 456 ) );

console.log( fn.apply ( obj , [123, 456] ) );

c ) apply使用案例

一、 合并数组:

var arr1 = [1, 2, 3];

var arr2 = [4, 5];

arr1.push(arr2[0],arr2[1]);

 [ ].push.apply(arr1,arr2);     这个方法与上面的方法等价

二、 合并标签对象:

<div>这是div标签1</div>

<div>这是div标签2</div>

<p>这是p标签1</p>

<p>这是p标签2</p>

将上述4个标签对象放入一个数组之中:

var byTag =document.getElementsByTagName,arr=[ ];

 arr.push.apply(arr , byTag.apply(document, ["div"]));

 arr.push.apply(arr , byTag.apply(document, ["p"]));

console.log(arr);

由于getElementsByTagName( )是document的方法调用函数,所以过byTag获取该方法后,该方法必须在document对象下调用,所以在apply中传入document对象

2call  参数以独立形势传入

call用法与apply除了参数传入形势不同以外,其他基本相同

语法: function fn ( argu1 , argu2) { };函数

fn.call ( obj , argu1 , argu2 )

借用构造方法创建对象:

function Person(name, age, gender) {

 this.name = name;

this.age = age;

this.gender = gender;

}

function Student(name,age,gender,course) {

 Person.call(this, name, age, gender);

this.course = course;

}

var student=new Student("Tom",20,"male","Math");

console.log(student);

7.补充知识

bind调用  让函数绑定对象的一种方法,在调用函数时,就像是该对象在调用方法

语法:函数.bind(对象),返回一个函数

下列代码:

var byTag =document.getElementsByTagName,arr=[ ];

 arr.push.apply(arr , byTag.apply(document, ["div"]));

 arr.push.apply(arr , byTag.apply(document, ["p"]));

console.log(arr);

使用bind对代码进行修改:

    var bindT = document.getElementsByTagName.bind(document), arr = [ ];

    arr.push.apply(arr, bindT("div"));

    arr.push.apply(arr, bindT("p"));

console.log(arr);

Object.prototype基本成员介绍

1constructor

2hasOwnProperty判断属性是否为自己提供

console.log( obj.hasProperty(“name”));判断obj是否具有name属性

3propertyIsEnumerable  判断属性是否可以枚举

4isPrototypeOf判断是否为原型对象

console.log(fn.prototype.isPrototypeOf(obj)) 判断fn.prototype是obj的原型吗

5toSting( ) , toLocaleString( ) , valueOf( )

包装类型    基本类型数据本不应该包含方法调用

基本类型数据,如数字,字符串在调用方法时,解释器先将基本类型数据转换成对应的对象类型,然后调用方法,执行方法后返回结果,同时销毁其转换的对象

getset读写器

语法糖:为方便开发而给出的语法结构

var obj = (function () {

var num = 123;

return {

get num() {

console.log("执行getter读写器");

return num;

},

set num(value) {

console.log("执行setter读写器");

num = value;

return num;

}

}

})();

console.log(obj.num);

obj.num = 456;

console.log(obj.num);

JavaScript (JS) 函数补充 (含arguments、eval()、四种调用模式)的更多相关文章

  1. 【转】JavaScript中的this关键字使用的四种调用模式

    http://blog.csdn.net/itpinpai/article/details/51004266 this关键字本意:这个.这里的意思.在JavaScript中是指每一个方法或函数都会有一 ...

  2. JS面向对象函数的四种调用模式

    函数的四种调用模式 概念 在 js 中,无论是函数, 还是方法, 还是事件, 还是构造器,...这些东西的本质都是函数 函数, 方法, 事件, 构造器,...只是所处的位置不同 这四种模式分别是 函数 ...

  3. javascript中函数的四种调用模式详解

    介绍函数四种调用模式前,我们先来了解一下函数和方法的概念,其实函数和方法本质是一样,就是称呼不一样而已.函数:如果一个函数与任何对象关系,就称该函数为函数.方法:如果一个函数作为一个对象属性存在,我们 ...

  4. 函数的四种调用模式.上下文调用.call.apply

    闭包:函数就是一个闭包,一个封闭的作用域;         返回函数,要返回多个函数就用一个对象封装一下,         立即执行函数+return 回调函数   JS动态创建的DOM,不会被搜索引 ...

  5. js中this的四种调用模式

    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/ ...

  6. JS函数的四种调用模式

    函数在js中具有四种身份,分别为函数.方法.构造函数.apply或call调用 函数调用    函数调用模式中this指全局对象(window) var f1 = function() { alert ...

  7. 【javascript】函数中的this的四种绑定形式

    目录 this的默认绑定 this的隐式绑定 隐式绑定下,作为对象属性的函数,对于对象来说是独立的 在一串对象属性链中,this绑定的是最内层的对象 this的显式绑定:(call和bind方法) n ...

  8. 【javascript】函数中的this的四种绑定形式 — 大家准备好瓜子,我要讲故事啦~~

       javascript中的this和函数息息相关,所以今天,我就给大家详细地讲述一番:javascript函数中的this   一谈到this,很多让人晕晕乎乎的抽象概念就跑出来了,这里我就只说最 ...

  9. javascript函数的四种调用模式及其this关键字的区别

    方法调用模式: 当一个函数被保存为对象的一个属性时,我们称它为一个方法.当一个方法被调用时,this被绑定到该对象. //方法调用模式 var myObject = { value: 0 , incr ...

随机推荐

  1. vue axios 攻略

    Axios 是一个基于 promise 的 HTTP 库,可以用在浏览器和 node.js 中. 特点: 从浏览器中创建 XMLHttpRequest 从 node.js 发出 http 请求 支持 ...

  2. 【线性基 集合hash】uoj#138. 【UER #3】开学前的涂鸦

    还需要加强分析题目特殊性质,设计对应特殊算法,少想多写大力dfs剪枝不要管MLETLE直接上的能力 红包是一个有艺术细胞的男孩子. 红包由于NOI惨挂心情不好,暑假作业又多,于是他开始在作业本上涂鸦. ...

  3. sendmail安装与配置

    一.安装sendmail与mail 1.安装sendmail:  1) centos下可以安装命令:yum -y install sendmail 2) 安装完后启动sendmail命令:servic ...

  4. 16.2--Jenkins+Maven+Gitlab+Tomcat 自动化构建打包、部署

    分类: Linux服务篇,Linux架构篇   一.环境需求 本帖针对的是Linux环境,Windows或其他系统也可借鉴.具体只讲述Jenkins配置以及整个流程的实现. 1.JDK(或JRE)及J ...

  5. 在windows上搭建镜像yum站的方法

    在windows上搭建镜像yum站的方法(附bat脚本)   分类: 运维基本功,其他   方法一:支持rsync的网站 对于常用的centos.Ubuntu.等使用官方yum源在 http://mi ...

  6. HashMap 排序

    本文章,摘抄自:2018黑马程序最新面试题汇总 已知一个 HashMap<Integer,User>集合, User 有 name(String)和 age(int)属性.请写一个方法实现 ...

  7. JZOJ 5347. 遥远的金字塔

    Description Input Output Sample Input 5 3 1 6 1 5 3 5 4 4 4 4 Sample Output 15 Data Constraint 做法: 其 ...

  8. mem_init()

    原本由bootmem管理的内存在mem_init函数中交由伙伴系统管理. 1.free_unused_memmap_node 相邻的membank间可能存在空洞,但在bootmem阶段这些空洞页也分配 ...

  9. 2017 ACM-ICPC网络赛 H.Skiing 有向图最长路

    H.Skiing In this winter holiday, Bob has a plan for skiing at the mountain resort. This ski resort h ...

  10. 动态规划:HDU1087-Super Jumping! Jumping! Jumping!(最大上升子序列和)

    Super Jumping! Jumping! Jumping! Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 ...