JavaScript高级程序设计

本文深入探讨JavaScript的关键概念,包括函数内部属性、面向对象编程、闭包及作用域链等高级特性,通过具体示例帮助读者理解这些概念的实际应用。

一:

JavaScript是一种专为网页交互而设计的脚本语言,由下列三个不同的部分组成

  • ECMAScript:由ECMA-262定义,提供核心语言功能

  • 文档对象模型( DOM ),提供访问和操作网页内容的方法和接口

  • 浏览器对象模型(BOM),提供与浏览器交互的方法和接口

二:在HTML中使用JavaScript

五:引用类型

函数内部属性
arguments是一个类数组对象,包含着传入函数中的所有参数,有一个名叫callee属性,该属性是一个指针,指向拥有这个arguments对象的函数

六:面向对象

继承

组合继承:结合原型继承和构造函数继承

使用原型链实现对原型属性和方法的继承- —共享
借用构造函数来实现对实例属性的继承——-各自独有

function SuperType(name){
    this.name = name ;
    this.colors = ["red","blue","green"];
}
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("Ellie" ,20);
instance1.colors.push("black");
alert(instance1.colors);//"red,blue,green,black"
instance1.sayName();//Ellie
instance1.sayAge();//20

var instance2 = new SubType("Andi" ,10);
alert(instance1.colors);//"red,blue,green"
instance1.sayName();//Andi
instance1.sayAge();//10

两个不同的SubType实例既分别拥有自己的属性–包括colors属性,又可以使用相同的方法

函数表达式

递归

在一个函数通过名字调用自身的情况下构成的

function factorial(num){
    if(num <= 1){
        return 1;
    }else{
    return num * factorial(num - 1);
    }
}

var anotherFactorial = factorial;
factorial = null;
alert( anotherFactorial(4)); //出错

将factorial变量设置为Null,结果指向原始函数的引用只剩下一个。但在截下来调用anotherFactorial()时,由于必须指向factorial() ,但factorial不再是函数,所以导致错误

arguments.callee 是一个指向正在执行的函数的指针,可以用它来实现对函数的递归调用

function factorial( num ){
    if(num <= 1){
        return 1;
    }else{
        return num * arguments.callee(num -1);
    }
}

通过使用arguments.callee代替函数名,可以确保无论怎样调用函数都不会出问题
但在严格模式下,不能通过脚本访问arguments.callee访问这个属性会出错。不过可以使用命名函数表达式来达成相同的效果

var factorial = ( function f(num){
    if(num <1){
        return 1;
    }else{
        return num * f( num - 1 );
    }
});

闭包

有权访问另一个函数作用域中的变量的函数

createComparisonFunction(propertyName){
    return function(object1,object2){
        var value1= object1[propertyName];//访问外部函数中的变量
        var value2= object2[propertyName];//

        if(value1 < value2){
            return -1;
        }elseif(value1 > value2){
            return 1;
        }else{
            return 0;
        }
    };
}

//创建函数
var compareNames = createComparisonFunction("name");
//调用函数
var result = compareNames({name:"Ellie"},{name:"Andi"});
//解除对匿名函数的引用(以便释放内存)
compareNames = null;

闭包只能取得包含函数中任何变量的最后一个值。
闭包所保存的是整个变量对象

function createFunction(){
    var result = new Array();

    for( var  i = 0 ; i < 10 ; i++){
        result[i] = function(){
            return i ;
        }
    }
}

这个函数会返回一个函数数组,每个函数都返回10.
因为每个函数的作用域链中都保存着createFunctions()函数的活动对象,所以它们引用的都是同一个变量i。当createFunction()函数返回够,变量i的值是10,此时每个函数都引用着保存变量i的同一个对象,所以在每个函数内部i的值都是10

改进:

function createFunctions(){
    var result = new Array();

    for(var i = 0; i < 10 ; i++){
        result[i] = function(num){
            return function(){
                return num;
            };
        }(i);
    }
    return result;
}

每个函数返回各自不同的索引值
解析:
定义了一个匿名函数,并将立即执行该匿名函数的结果赋给数组。这里的匿名函数有一个参数num,也就是最终的函数要返回的值。在调用每个匿名函数时,我们传入了变量i。由于函数参数是按值传递的,所以就会将变量i 的当前值复制给参数num。而在这个匿名函数内部,又创建并返回了一个访问num的闭包。这样一来,result数组中的每个函数都有自己num变量的一个副本,因此就可以返回各自不同的数值了

this

作用域

作用域就是变量与函数的可访问范围,即作用域控制着变量与函数的可见性和生命周期。在JavaScript中,变量的作用域有全局作用域和局部作用域两种。

在代码中任何地方都能访问到的对象拥有全局作用域

作用域链

在JavaScript中,函数也是对象,实际上,JavaScript里一切都是对象。函数对象和其它对象一样,拥有可以通过代码访问的属性和一系列仅供JavaScript引擎访问的内部属性。其中一个内部属性是[[Scope]],该内部属性包含了函数被创建的作用域中对象的集合,这个集合被称为函数的作用域链,它决定了哪些数据能被函数访问

当一个函数创建后,它实际上保存一个作用域链,并且作用域链会被创建此函数的作用域中可访问的数据对象填充。例如定义下面这样一个函数:

 function func() {
            var num = 1;
            alert(num);
        }
        func();

在函数func创建时,它的作用域链中会填入一个全局对象,该全局对象包含了所有全局变量,如下图所示(注意:图片只例举了全部变量中的一部分)
这里写图片描述

执行此函数时会创建一个称为“运行期上下文(execution context)”(有人称为运行环境)的内部对象,运行期上下文定义了函数执行时的环境。每个运行期上下文都有自己的作用域链,用于标识符解析,当运行期上下文被创建时,而它的作用域链初始化为当前运行函数的[[Scope]]所包含的对象。

  这些值按照它们出现在函数中的顺序被复制到运行期上下文的作用域链中。它们共同组成了一个新的对象,叫“活动对象(activation object)”,该对象包含了函数的所有局部变量、命名参数、参数集合以及this,然后此对象会被推入作用域链的前端,当运行期上下文被销毁,活动对象也随之销毁。

这里写图片描述

var x = 10;
function fn() {
    console.log(x);
}

function show(f) {
    var x = 20;
        fn();
}

show(fn);

x是10,决定函数作用域的是其内部的[[scope]]属性,这个属性是在定义函数时决定的,所以无论你如何调用fn函数,x的值都是10

匿名函数

匿名函数执行的时候相当于调用了window上面的定义的方法。
this指向window

var i = 9 ; 
(function(){console.log(this.i);})();//9

var o = 8 ; 
(function(){console.log(o);})(); //8

constructor属性

这里写图片描述

constructor 属性返回对创建此对象的数组函数的引用。

function Employee(name,job,born)
{
this.name=name;
this.job=job;
this.born=born;
}

var bill=new Employee("Bill Gates","Engineer",1985);

document.write(bill.constructor);

//function Employee(name,job,born) { this.name=name; this.job=job; this.born=born; } 

alert(bill.prototype)//undefined  

function定义的对象Employee有一个prototype属性,使用new生成的对象就没有这个prototype属性。

prototype属性又指向了一个prototype对象,注意prototype属性与prototype对象是两个不同的东西,要注意区别。在prototype对象中又有一个constructor属性,这个constructor属性同样指向一个constructor对象,而这个constructor对象恰恰就是这个function函数本身。

prototype 属性

prototype 属性使您有能力向对象添加属性和方法。
语法

object.prototype.name=value
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值