JavaScript基础语法

以下列出的是我认为在javascript学习中,应该要关注的一些要点,参考书籍<< Javascript高级程序设计 >>

类型检测

鉴于js是松散类型,所以我们往往需要对变量进行类型检测。

-基本类型的类型检测
typeof操作符用于检测基本类型,对一个值使用typeof操作符可能返回下列某个字符串:
“undefined”
“boolean”
“string”
“number”
“object”
“function”

这里比较特殊的是如果变量是一个对象或null,typeof只会返回object,其无法确定对象是哪里一种类型。所以typedof操作符只能检测基本类型。注意可以通过typeof检测某一对象是否有某个方法(判断其是否等于function)。

  • 检测引用类型
    对于引用类型,可以用个instanceof操作符判断其实上面类型的对象。

执行环境及作用域

当代码或函数执行时都会产生一个执行环境,执行环境定义了变量或函数有权访问的其他数据,决定了它们各自的行为。

  • 全局执行环境

    其为最外围的一个执行环境。根据ECMAScript实现所在的宿主的环境不同,表示的执行环境的对象也不一样。在web浏览器中,全局执行环境被认为是是window对象。在node中的?

  • 函数执行环境

    每个函数都有自己的执行环境,当执行流进入一个函数时,函数的环境就会被推入一个环境栈中,包含该函数中所有能访问到变量。

  • 没有块级作用域

    不像类C的语言,由花括号封闭的代码块都有自己的作用域。js中没有这样的作用域。

作用域链

**当代码在一个环境中执行时,会创建变量对象的一个作用域链。作用域链的用途,是保证对执行环境有权访问的所有变量和函数的有序访问。作用域链的前端,始终都是当前执行的代码所在环境的变量对象。如果这个环境是函数,则将其活动对象作为变量对象。作用域链中的下一个变量对象来自包含环境,而再下一个变量对象则来自下一个包含环境。这样,一直延续到全局执行环境。全局执行环境的变量对象始终都是作用域链中的最后一个对象。
标识符解析(变量的解析)是沿着作用域链一级一级地搜索标识符的过程。**

其就是类比为C++中的全局变量和局部变量,在不同的作用域是否可以访问到。以上的这段话特别重要,其不但解释了js中作用域实现原理(变量的解析过程),对闭包的理解也至关重要(在js中的闭包,无非就是变量解析的过程)。

以下是一个关于作用域的示例代码:

var color = "black";
function changeColor(){
    var anotherColor = "red";
    function swapColors(){
        var tempColor = anotherColor;
        console.log(tempColor);
        anotherColor = color;
        color = tempColor;
    }

    // 无法访问tmepColor,因为超出了tempColor的作用域
    //console.log(tempColor);
    swapColors();
}

changeColor();
//访问全局的作用域中的color
console.log(color);

匿名函数

匿名函数形式如下:

(function(){
    //code
})();

通过匿名函数限制在全局作用域中添加过多的变量和函数

var application = function(){
    //私有变量
    var components = new Array();

    //初始化
    components.push(new BaseComponent());

    //公共
    return {
        getComponentCont:function(){
            return components.length;
        },

        registerComponent:function(component){
            if (typeof component == "object"){
                components.push(component);
            }
        }
    };
}();

创建了一个application模块

js中对面向对象程序设计的支持

  • “类”其实就是引用类型

    面向对象的支持是通过引用类型来实现的。引用类型的值(对象)是引用类型的一个实例,引用类型是一种数据结构,用于将数据和功能组织在一起,它也常被称为类。 但js不具备传统的面向对象语言所支持的类和接口等基本结构。引用类型有时候也被称为对象定义,因为它们描述的是一类对象所具有的属性和方法。

  • 对象的本质

    无序属性的集合,其属性可以包含基本值,对象或函数,严格来讲,这就相当于说对象是一组没有特定顺序的值。对象的每个属性或方法都有一个名字,而每个名字都映射到一个值。正因为这样,我们可以把对象想象成散列表:无非就是一组名值对,其中值可以是数据或函数。

  • 对象的创建

    每个对象都是基于引用类型创建的,这个引用类型可以是原生类型,也可以是开发人员定义的类型。对象是某个特定引用类型的实例,新对象是使用new操作符后跟一个构造函数来创建的。构造函数本身就是一个函数,只不过该函数是出于创建新对象的目的而定义的。

创建对象的方法

  • 字面量创建对象
var person = {name:"rock",age:18,printName:function(){
    console.log(this.name);
}}

这样创建的对象的类型是object,其并不是面向对象思维的对象,算是一种数据结构,通常是向函数传递大量可选参数的首先方式。

  • 构造函数方式创建对象

js中的构造函数可以用来自定义引用类型,这个就跟传统的面向对象的类一样了

function Person(name,age)
{
    this.name = name;
    this.age = age;
    this.printName = function(){
        console.log(this.name);
    }
}

var p1 = new Person("rock",18);
console.log(p1 instanceof Person);

通过构造函数Person创建了一个Person的引用类型,p1是Person引用类型的一个值。


  • 原型模式

无论什么时候,只要创建了一个新函数,就会根据一组特定的规则为该函数创建一个prototype属性,这个属性指向函数的原型对象。当调用构造函数创建一个新的实例后,该实例的内部将包含一个指针(内部属性),指向构造函数的原型对象。ECMA-262第5版中管这个指针叫[[Protoype]]。
function Person()
{

}

Person.prototype.name = "abc";
Person.prototype.age = 18;
Person.prototype.sayName = function(){
    console.log(this.name);
}

var person1 = new Person();
person1.sayName();

var person2 = new Person();
person2.sayName();

如上代码中定义在原型对象中的属性就如同C++中的静态成员变量,被所有实例所共享。


  • 组合使用构造函数模式和原型模式

创建自定义类型的最常见方式,就是组合使用构造函数模式和原型模式。构造函数模式用于定义实例属性,而原型模式用于定义方法和共享的属性。结果,每个实例都会有自己的一个实例属性的副本,但同时又共享着对方法的引用,最大限度地节省了内存。
function Person(name,age)
{
    this.name = name;
    this.age = age;
}

Person.prototype = {
    sayName:function(){
        console.log(this.name);
    }
}

var p1 = new Person("abc",18);
var p2 = new Person("bcd",19);

这种方式创建的自定义类型就等同于class关键字定义的自定义类型了,每个对象的属性单独存储,每个对象都共享定义在prototype对象中定义的方法。


  • 私有变量

任何在函数中定义的变量,都可以认为是私有变量,因为不能在函数的外部访问这些变量。私有变量包含函数的参数,局部变量和在函数内部定义的其他函数。
不像传统的面向对象语言直接由private关键字来定义私有成员,js中通过对作用域的特性来模拟私有变量。js中通过与闭包结合来实现面向对象的封装。

function Person(age){
    //iAge为私有变量
    var  iAge = age;
    //每个实例对象有一个iAge变量
    //this.iAge = age;
    //通过闭包实现访问私有变量
    this.GetAge = function(){
        return iAge;
    }
}

var p1 = new Person(10);
console.log(p1.GetAge());

var p2 = new Person(18);
console.log(p2.GetAge());

在Person中定义局部变量iAge并不属于对象,而是存在于作用域中。

js语法层面对面向对象的支持与传统面向对象语言差距很大,都是通过语法特性来模拟面向对象的要素,很别扭很不直观。我觉得只是写业务代码的话学习js面向对象的特性就只用了解如何定义自定义类型,如何创建对象,如何实现封装。其他诸如继承,多重继承,多态等要素的实现实在是过于牵强。我觉得也不必去大费周章的去钻研通过js去实现各种面向对象的设计模式(这种传统的面向对象语言实现起来都非常绕的东西)。如果要学习面向对象的设计思想,还是选择传统的面向对象语言最好(C++/java/C#)。

引用<< 你不知道的JavaScript >>中的一段话,用于描述js的类

在js中,类是一种可选(而不是必须)的设计模式,而且在js这样的[[Prototype]]语言中实现类是很别扭的。


这种别扭的感觉不只是来源于语法,虽然语法是很重要的原因(繁琐杂乱的.prototype引用,试图调用原型链上层同名函数是的显式伪多态以及不可靠,不美观而且容易被误解成“构造函数”的.constructor)。


除此之外,类设计其实还存在更深刻的问题,传统面向类的语法中父类和子类,子类和实例之间其实是复制操作,但是在[[Prototype]]中并没有复制,相反,它们之间只是委托关联。
对象关联代码和行为委托使用了[[Prototype]]而不是将它藏起来,对比其简洁可以看出,类并不适合用于js。

在上面所描述的原型模式创建对象的方法中,其只是通过Prototype属性将两个对象关联了起来,而所谓的”类“其实也是个对象,所谓类的不同对象,也只是对象间指向了同一个原型对象,将”类”的属性和方法定义在原型中,从而达到共享的目的。这个与传统的面向对象语言是本质不同的。所以js只是通过语法去模拟类和面向对象的特性。

以上。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

mo4776

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值