• [No0000102]JavaScript-基础课程2


    var bob = new Object();
    bob.age = 17;
    // 这一次我们已经添加了一个方法,setAge
    bob.setAge = function (newAge){
      bob.age = newAge;
    };
    
    bob.getYearOfBirth = function () {
      return 2014 - bob.age;
    };
    console.log(bob.getYearOfBirth());

    setAge()方法非常适合bob对象,因为他可以更新bob.age,但是如果我们想用于其它对象呢?

    实际上我们可以用一个新的关键字“this”来让这个方法适用于多个对象。 this关键字作为一个占位符,将引用任何调用此方法的对象。

    // 在这里,我们使用this
    var setAge = function (newAge) {
      this.age = newAge;
    };
    // now we make bob
    var bob = new Object();
    bob.age = 30;
    // 在这里,我们只使用方法
    bob.setAge = setAge;

    这意味着我们键入bob.setAge()时,在setAge方法中,this.age就是bob.age

     太棒了!我们可以利用这一特性,可以在不同的对象中重复使用该方法,这使我们能够避免每次都输入一个自定义的方法,这一切都是因为我们使用了占位符。

    1.创建对象的另一个方法是使用对象字面量,也就是用“{}“。创建一个新的对象,在括号中定义对象的属性。

    另一种不使用花括号{ }的方式创建对象是使用关键字 new。这被称为使用构造函数来创建一个对象。

    使用new关键字创建一个空对象的方法是:

    var objectName = new Object();

    当我们使用new关键字时,我们就是使用构造函数来创建了一个对象。

    对于复杂的对象,我们可以创建自己的构造函数,加入我们想要的属性和方法。

    查看例子,我们的Rabbit构造函数,定义了一个adjective属性,和一个describeMyself方法。

    回想使用这些构造函数是多么重要,因为它们使我们能够轻松地做出许多类似的对象。

    function Rabbit(adjective) {
        this.adjective = adjective;
        this.describeMyself = function() {
            console.log("I am a " + this.adjective + " rabbit");
        };
    }

     使用构造函数每次添加一个属性是乏味的,我们可以使用自己的构造函数。这样我们就可以在创建的时候设置一些属性,而不是使用Object的空的构造函数。我们可以设置自己的构造函数具有某些属性

    function Person(name,age) {
      this.name = name;
      this.age = age;
    }
    
    // 让bob和susan再次使用我们的构造函数
    var bob = new Person("Bob Smith", 30);
    var susan = new Person("Susan Jordan", 25);
    // Person 的构造函数
    function Person (name, age) {
        this.name = name;
        this.age = age;
    }
    
    // 现在我们可以创建一个人的数组
    var family = new Array();
    family[0] = new Person("alice", 40);
    family[1] = new Person("bob", 42);
    family[2] = new Person("michelle", 8);

     2.对象为我们提供了一种表示现实世界或虚拟东西的方法。我们可以通过保存对象的属性信息做到这一点。创建对象有两种基本方法:

     1、字面量,在这里我们使用

    var Name = { };

    2、构造函数方法,我们使用new关键字。

    var spencer = {
      age: 22,
      country: "United States"
    };
    var spencer2 = new Object(); 
    spencer2.age = 22; 
    spencer2.country = 'United States'; // 创建spencer2对象

     属性就像一个变量一样,但它只属于对象,我们可以使用它来存储对象的信息。属性的访问有两种方式:

    • 使用点操作符,ObjectName.PropertyName
    • 使用中括号,ObjectName["PropertyName"],(别忘了引号)

     除了基本的Object构造函数,我们可以定义自己的构造函数。这些都是非常有用的,有两个原因:

    • 我们可以在创建对象时通过传递参数来分配对象的属性;
    • 我们可以让我们的对象在创建时就具有某些方法;

     方法就像是一个特定相关对象的一个函数。

     3.因为数组编号从0开始,数组中的最后一个元素的编号是数组元素的个数减一。因此在数组最后一个元素之后插入一个对象,可以这样写:

    contacts[contacts.length] = {
        firstName: firstName,
        lastName: lastName,
        phoneNumber: phoneNumber,
        email: email
    };

    假设我们有一个变量,我们不知道是什么类型,我们可以调用typeof来运算出来。一般常有的类型是:

    • number
    • String
    • function
    • Object
    var someObject = {someProperty: someValue};
    console.log( typeof someObject );//将打印“Object”:
    // 显示适当的类型
    var anObj = { job: "I'm an object!" };
    var aNumber = 42;
    var aString = "I'm a string!";
    
    console.log(typeof  anObj ); // 应该输出 "object"
    console.log(typeof  aNumber ); //应该输出"number"
    console.log(typeof  aString ); //应该输出"string"

     4.在javascript中的每个对象还自带有一些功能,它包含一个名为hasOwnProperty的方法,它可以判断,对象是否包含有指定的属性。

    当你创建了一个构造函数,你其实是定义一个新的类。一个类可以被认为是一种类型或类别的对象 ,有点像JavaScript中的数值和字符串。

    一般来说,我们想添加一个方法到类,让类的所有成员都可以使用它,我们使用下面的语法来扩展原型:

    className.prototype.newMethod = function() {
        statements;
    };
    function Dog (breed) {
      this.breed = breed;
    };
    
    // 这里我们为Dog添加了一个新方法
    var buddy = new Dog("golden Retriever");
    Dog.prototype.bark = function() {
      console.log("Woof");
    };
    buddy.bark();
    
    // 这里我们创建了一个snoopy
    var snoopy = new Dog("Beagle");
    // 它可以工作!
    snoopy.bark();

    编程“DRY”的原则:Don’t Repeat Yourself。

    继承可以在这里帮助我们,企鹅是一只动物,所以它应该具有Animal的所有属性和方法。每当X is-a Y的关系存在,这就是我们使用继承的一个好的机会。

    Penguin.prototype = new Animal();

    这意味着PenguinAnimal继承方法和属性

    Penguin继承了Animalemperor继承了Penguin,那么emperor继承Animal吗?当然!

     “原型链”在JavaScript中知道这一点。如果javascript不能在当前类找到方法或属性,它会在原型链中去查找,因为它继承自那个类。如果找不到会继续向上查找,直到最顶部:Object.prototype。默认情况下,所有的类都直接继承自Object,除非我们改变类的原型,就像Emperor继承Penguin一样。

    • 记得原型链是如何工作的:如果类中没有定义这个属性,这个类的原型链将向上遍历,直到在父类中找到或达到最顶部Object类为止。
    // 原始类
    function Animal(name, numLegs) {
        this.name = name;
        this.numLegs = numLegs;
        this.isAlive = true;
    }
    function Penguin(name) {
        this.name = name;
        this.numLegs = 2;
    }
    function Emperor(name) {
        this.name = name;
        this.saying = "Waddle waddle";
    }
    
    //建立原型链
    Penguin.prototype = new Animal();
    Emperor.prototype = new Penguin();
    
    var myEmperor = new Emperor("Jules");
    
    console.log(myEmperor.saying); // 应该输出"Waddle waddle"
    console.log(myEmperor.numLegs); //应该输出2
    console.log(myEmperor.isAlive); //应该输出true

    我们可以自由地访问firstNamelastName属性,这就是说他们是公开的。

    就像函数可以有局部变量,我们只能从这个函数内部访问,对象可以有私有变量。私有变量是一些你不想公开的信息,只能在类的内部访问。

    Person类中已经被修改添加了一个名为bankBalance的私有变量,请注意,它看起来就像一个正常的变量,但里面定义的构造函数没有使用这个,而是使用var。这使得bankBalance是一个私有变量。

    function Person(first,last,age) {
       this.firstname = first;
       this.lastname = last;
       this.age = age;
       var bankBalance = 7500;
    }

    虽然我们不能直接从类的外部访问私有变量,有一种方法来解决这个问题。我们可以定义一个返回私有变量的值的公共方法。

    function Person(first,last,age) {
       this.firstname = first;
       this.lastname = last;
       this.age = age;
       var bankBalance = 7500;
      
       this.getBalance = function() {
          //您的代码应该返回bankBalance
         return bankBalance;
       };
    }
    
    var john = new Person('John','Smith',30);
    console.log(john.bankBalance);
    
    // 创建一个新变量myBalance ,调用getBalance()返回值给他
    console.log(john.getBalance());

     方法也可以是私有的,无法在类外部访问。改变上个练习中this.returnBalancevar returnBalance使它成为私有方法。如果你运行程序,试图调用这个方法会得到一个undefined错误。

    Person类内部创建一个askTeller方法,它返回returnBalance方法,这意味着,它返回方法本身,而不是返回调用该方法的结果。所以你返回returnBalance后不应该有括号。

    因为askTeller返回一个方法。

    function Person(first,last,age) {
       this.firstname = first;
       this.lastname = last;
       this.age = age;
       var bankBalance = 7500;
      
       var returnBalance = function() {
          return bankBalance;
       };
           
       // 创建一个新的方法
       this.askTeller = function(){ 
         return returnBalance;//它返回returnBalance方法本身,而不是返回调用该方法的结果。所以此返回returnBalance后不应该有括号。
       };
    }
    
    var john = new Person('John','Smith',30);
    console.log(john.returnBalance);
    var myBalanceMethod = john.askTeller();
    var myBalance = myBalanceMethod();
    console.log(myBalance);
    console.log( john.askTeller()());

    程序设计语言,主要可以分为两种,一种是我们平时接触较多的,工业级的程序设计语 言如 C/C++, JAVA,Object Pascal(DELPHI)等,从本质上来讲,这些语言是基于程序 存储原理,即冯.诺依曼体系的,一般被称为命令式编程语言,而另一种,是根据阿隆左.丘奇的 lambda 演算而产生的,如 Lisp,Scheme,被称为函数式编程语言。这两个体系一般情况下是互不干涉,泾渭分明的,这一现象直到 JavaScript 的逐渐成熟之后才被打破。

    数组 Array 在 JavaScript 中是一个保留字,与其他语言不同的是,Array 更像是一个哈希表,而对 Array 的操作则可以类比为栈结构,或者 Lisp 中的 List,总之,数组是一个复杂的对象,值得我们花时间深入探究。

    闭包,是函数式编程语言所特有的一种结构,使用它可以是代码更简洁,有是更是非它不可,但是,不小心的设计往往容易造成内存泄漏(特别是在 IE 浏览器的早期版本中)。

    JavaScript 是一门动态的,弱类型,基于原型的脚本语言。在 JavaScript 中“一切皆对象”,在这一方面,它比其他的OO语言来的更为彻底,即使作为代码本身载体的function,也是对象,数据与代码的界限在 JavaScript 中已经相当模糊。虽然它被广泛的应用在 WEB客户端,但是其应用范围远远未局限于此。

    动态性是指,在一个 JavaScript 对象中,要为一个属性赋值,我们不必事先创建一个字段,只需要在使用的时候做赋值操作即可

    //定义一个对象
    var obj = new Object();
    
    //动态创建属性name
    obj.name = "an object";
    
    //动态创建属性sayHi
    obj.sayHi = function(){
    return "Hi";
    }
    obj.sayHi();

    与 Java,C/C++不同,JavaScript 是弱类型的,它的数据类型无需在声明时指定,解释 器会根据上下文对变量进行实例化

    //定义一个变量s,并赋值为字符串
    var s = "text";
    print(s);
    
    //赋值s为整型
    s = 12+5;
    print(s);
    
    //赋值s为浮点型
    s = 6.3;
    print(s);
    
    //赋值s为一个对象
    s = new Object();
    s.name = "object";
    
    print(s.name);

    弱类型的好处在于,一个变量可以很大程度的进行复用,比如 String 类型的 name 字 段,在被使用后,可以赋值为另一个 Number 型的对象,而无需重新创建一个新的变量。不过,弱类型也有其不利的一面,比如在开发面向对象的 JavaScript 的时候,没有类型的判断将会是比较麻烦的问题,不过我们可以通过别的途径来解决此问题。

    通常来说,JavaScript 是一门解释型的语言,特别是在浏览器中的 JavaScript,所有的主流浏览器都将 JavaScript 作为一个解释型的脚本来进行解析,然而,这并非定则,在 Java 版的 JavaScript 解释器 rhino 中,脚本是可以被编译为 Java 字节码的。Google 的 V8 引擎则直接将 JavaScript 代码编译为本地代码,无需解释。

    解释型的语言有一定的好处,即可以随时修改代码,无需编译,刷新页面即可重新解释, 可以实时看到程序的结果,但是由于每一次都需要解释,程序的开销较大;而编译型的语言则仅需要编译一次,每次都运行编译过的代码即可,但是又丧失了动态性。

    当 JavaScript 第一次出现的时候,是为了给页面带来更多的动态,使得用户可以与页 面进行交互为目的的,虽然 JavaScript 在 WEB 客户端取得了很大的成功,但是 ECMA 标准并没有局限其应用范围。事实上,现在的 JavaScript 大多运行与客户端,但是仍有部分运行于服务器端,如 Servlet,ASP 等,当然,JavaScript 作为一个独立的语言,同样可以运行在其他的应用程序中,比如 Java 版的 JavaScript 引擎 Rhino,C 语言版的SpiderMonkey 等,使用这些引擎,可以将 JavaScript 应用在任何应用之中。

    客户端的 JavaScript 随着 AJAX 技术的复兴,越来越凸显了 JavaScript 的特点,也 有越来越多的开发人员开始进行 JavaScript 的学习,使用 JavaScript,你可以使你的 WEB页面更加生动,通过 AJAX,无刷新的更新页面内容,可以大大的提高用户体验,随着大量的 JavaScript 包如 jQuery, ExtJS,Mootools 等的涌现,越来越多的绚丽,高体验的WEB 应用被开发出来,这些都离不来幕后的 JavaScript 的支持。

    闭包是可以包含自由(未绑定到特定对象)变量的代码块;这些变量不是在这个代码块内或者任何全局上下文中定义的,而是在定义代码块的环境中定义(局部变量)。"闭包" 一词来源于以下两者的结合:要执行的代码块(由于自由变量被包含在代码块中,这些自由变量以及它们引用的对象没有被释放)和为自由变量提供绑定的计算环境(作用域)。在 Scala、Scheme、Common Lisp、Smalltalk、Groovy、JavaScript、Ruby、 Python、Go、Lua、objective c 以及Java(Java8及以上)等语言中都能找到对闭包不同程度的支持。

    由于 JavaScript 中的“一切皆对象”,在掌握了这些基本的概念之后,读者就可以较为轻松的理解诸如作用域,调用对象,闭包,currying 等等较难理解的概念了。

     JavaScript 中的数据类型分为两种基本数据类型和对象类型,其中对象类型包含对象,数组,以及函数,基本数据类型在必要是会被隐式的转换为对象

     在 JavaScript 中,包含六种基本的数据类型字符串(string),数值(number),布尔值(boolean),undefined,null 及对象(object)。

    这里提到的对象不是对象本身,而是指一种类型,此处的对象包括,对象(属性的集合,即键值的散列表),数组(有序的列表),函数(包含可执行的代码)。

    而将对象转换为基本类型则是通过这样的方式:通过调用对象的 valueOf()方法来取得 对象的值,如果和上下文的类型匹配,则使用该值。如果 valueOf 取不到值的话,则需要 调用对象的 toString()方法,而如果上下文为数值型,则又需要将此字符串转换为数值。 由于 JavaScript 是弱类型的,所以 JavaScript 引擎需要根据上下文来“猜测”对象的类 型,这就使得 JavaScript 的效率比编译型的语言要差一些。valueOf()的优先级要高于 toString()。

    valueOf()的作用是,将一个对象的值转换成一种合乎上下文需求的基本类型,toString()则名副其实,可以打印出对象对应的字符串,当然前提是你已经“重载”了 Object的 toString()方法。

    所有的非空对象,在布尔值环境下, 都会被转成 true

    var obj = {};
    var array = ["one", "two", "three", "four"];
    
    alert(typeof obj);//object
    alert(typeof array); //object
    alert(obj instanceof Array);//false
    alert(array instanceof Array);//true
    var array = [1,2,3,4,5];
    var arrayRef = array;
    
    array.push(6);
    alert(arrayRef);

    引用指向的是地址,也就是说,引用不会指向引用本身,而是指向该引用所对应的实际对象。因此通过修改 array 指向的数组,则 arrayRef 指向的是同一个对象,因此运行效果如下:

    1,2,3,4,5,6

    变量被定义的区域即为其作用域,全局变量具有全局作用域;局部变量,比如声明在函 数内部的变量则具有局部作用域,在函数的外部是不能直接访问的

    应该注意的是,在函数内 var 关键字是必须的,如果使用了变量而没有写 var 关键字, 则默认的操作是对全局对象的

    var ref = {
    id : "reference1",
    func : function(){
    return this.id;
    }
    };
    var obj = {
    id : "object1",
    "self.ref" : ref
    };

     当我们尝试访问 obj 的”self.ref”这个属性的时候:obj.self.ref,解释器会以为 obj 中有个名为 self 的属性,而 self 对象又有个 ref 的属性,这样会发生不可预知的错误,一个好的解决方法是使用中括号([])运算符来访问:

    print(obj["self.ref"].func());

     在这种情况下,中括号操作符成为唯一可行的方式,因此,建议在不知道对象的内部结构的时候(比如要遍历对象来获取某个属性的值),一定要使用中括号操作符,这样可以避免一些意想不到的 bug。

    如果操作数的类型不同,则按照这样的情况来判断:

    • null 和 undefined 相等
    • 其中一个是数字,另一个是字符串,则将字符串转换为数字,再做比较
    • 其中一个是 true,先转换成 1(false 则转换为 0)在做比较
    • 如果一个值是对象,另一个是数字/字符串,则将对象转换为原始值(通过 toString()或者 valueOf()方法)
    • 其他情况,则直接返回 false

    而不等(!=)和不等同(!==),则与相等(==)/等同(!==)相反。因此,在 JavaScript中,使用相等/等同,不等/不等同的时候,一定要注意类型的转换,这里推荐使用等同/不 等同来进行判断,这样可以避免一些难以调试的 bug。

    JavaScript 对象与传统的面向对象中的对象几乎没有相似之处,传统的面向对象语言中,创建一个对象必须先有对象的模板:类,类中定义了对象的属性和操作这些属性的方法。通过实例化来构建一个对象,然后使用对象间的协作来完成一项功能,通过功能的集合来完成整个工程。而 Javascript中是没有类的概念的,借助 JavaScript 的动态性,我们完全可以创建一个空的对象(而不是类),通过向对象动态的添加属性来完善对象的功能。

    JSON 是 JavaScript 中对象的字面量,是对象的表示方法,通过使用 JSON,可以减少中间变量,使代码的结构更加清晰,也更加直观。使用 JSON,可以动态的构建对象,而不必通过类来进行实例化,大大的提高了编码的效率。

    JavaScript 对象其实就是属性的集合(以及一个原型对象),这里的集合与数学上的集合是等价的,即具有确定性,无序性和互异性,也就是说,给定一个 JavaScript对象,我们可以明确的知道一个属性是不是这个对象的属性,对象中的属性是无序的,并且是各不相同的(如果有同名的,则后声明的覆盖先声明的)。

    一般来说,我们声明对象的时候对象往往只是一个空的集合,不包含任何的属性,通过不断的添加属性,使得该对象成为一个有完整功能的对象,而不用通过创建一个类,然后实例化该类这种模式,这样我们的代码具有更高的灵活性,我们可以任意的增删对象的属性。

    果读者有python或其他类似的动态语言的经验,就可以更好的理解JavaScript的对象,JavaScript 对象的本身就是一个字典(dictionary),或者 Java 语言中的 Map,或者称为关联数组,即通过键来关联一个对象,这个对象本身又可以是一个对象,根据此定义,我们可以知道 JavaScript 对象可以表示任意复杂的数据结构。

    属性是由键-值对组成的,即属性的名字和属性的值。属性的名字是一个字符串,而值可以为任意的JavaScript对象(JavaScript中的一切皆对象,包括函数)

    var ja = jack.addr;
    ja = jack["addr"];

    后者是为了避免这种情况,设想对象有一个属性本身包含一个点(.),这在 JavaScript 中是合法的,比如说名字为 foo.bar,当使用 jack.foo.bar 的时候,解释器会误以为 foo 属性下有一个 bar 的字段,因此可以使用 jack[foo.bar]来进行访问。通常来说,我们在开发通用的工具包时,应该对用户可能的输入不做任何假设,通过[属性名]这种形式则总是可以保证正确性的。

     事实上,对象的属性和我们之前所说的变量其实是一回事。

    JavaScript 引擎在初始化时,会构建一个全局对象,在客户端环境中,这个全局对象即为 window。如果在其他的 JavaScript 环境中需要引用这个全局对象,只需要在顶级作用域(即所有函数声明之外的作用域)中声明:

    var global = this;

     我们在顶级作用域中声明的变量将作为全局对象的属性被保存,从这一点上来看,变量其实就是属性。比如,在客户端,经常会出现这样的代码:

     v = "global";
    
    var array = ["hello", "world"];
    
    function func(id){
    var element = document.getElementById(id);
    //对elemen做一些操作
    }
    window.v = "global";
    
    window.array = ["hello", "world"];
    
    window.func = function(id){
    var element = document.getElementById(id);
    //对elemen做一些操作
    }

     原型(prototype),是 JavaScript 特有的一个概念,通过使用原型,JavaScript 可以建立其传统 OO 语言中的继承,从而体现对象的层次关系。JavaScript 本身是基于原型的每个对象都有一个 prototype 的属性,这个 prototype 本身也是一个对象,因此它本身也可以有自己的原型,这样就构成了一个链结构

    访问一个属性的时候,解析器需要从下向上的遍历这个链结构,直到遇到该属性,则返回属性对应的值,或者遇到原型为 null 的对象(JavaScript 的基对象 Object 的构造器的默认 prototype 有一个 null 原型),如果此对象仍没有该属性,则返回 undefined.

    //声明一个对象base
    function Base(name){
    this.name = name;
    this.getName = function(){
    return this.name;
    }
    }
    //声明一个对象child
    function Child(id){
    this.id = id;
    this.getId = function(){
    return this.id;
    }
    }
    //将child的原型指向一个新的base对象
    Child.prototype = new Base("base");
    
    //实例化一个child对象
    var c1 = new Child("child");
    
    //c1本身具有getId方法
    print(c1.getId());
    
    //由于c1从原型链上"继承"到了getName方法,因此可以访问
    print(c1.getName());

     由于遍历原型链的时候,是由下而上的,所以最先遇到的属性值最先返回,通过这种机制可以完成继承及重载等传统的 OO 机制。

    通过原型链,可以实现继承/重载等面向对象的的 JavaScript 代码,当然这个机制并非基于类,而是基于原型。

    JavaScript 中最容易使人迷惑的恐怕就数 this 指针了,this 指针在传统 OO 语言中,是在类中声明的,表示对象本身,而在 JavaScript 中,this 表示当前上下文,即调用者的引用

    //定义一个人,名字为jack
    var jack = {
    name : "jack",
    age : 26
    }
    //定义另一个人,名字为abruzzi
    var abruzzi = {
    name : "abruzzi",
    age : 26
    }
    //定义一个全局的函数对象
    function printName(){
    return this.name;
    }
    //设置printName的上下文为jack, 此时的this为jack
    print(printName.call(jack));
    //设置printName的上下文为abruzzi,此时的this为abruzzi
    print(printName.call(abruzzi));

     应该注意的是,this 的值并非函数如何被声明而确定,而是被函数如何被调用而确定,这 一点与传统的面向对象语言截然不同,call 是 Function 内置对象上的一个方法。

    对象的声明有三种方式

    • 通过 new 操作符作用于 Object 对象,构造一个新的对象,然后动态的添加属性,从无到有的构建一个对象。
    • 定义对象的“类”:原型,然后使用 new 操作符来批量的构建新的对象。
    • 使用 JSON,这个在下一节来进行详细说明。
    //定义一个"类",Address
    function Address(street, xno){
    this.street = street || 'Huang Quan Road';
    this.xno = xno || 135;
    this.toString = function(){
    return "street : " + this.street + ", No : " + this.xno;
    }
    }
    
    //定义另一个"类",Person
    function Person (name, age, addr) {
     this.name = name || 'unknown';
     this.age = age;
     this.addr = addr || new Address(null, null);
     this.getName = function () {return this.name;}
     this.getAge = function(){return this.age;}
     this.getAddr = function(){return this.addr.toString();
     }
    }
    
    //通过new操作符来创建两个对象,注意,这两个对象是相互独立的实体
    var jack = new Person('jack', 26, new Address('Qing Hai Road', 123));
    var abruzzi = new Person('abruzzi', 26);
    
    //查看结果
    print(jack.getName());
    print(jack.getAge());
    print(jack.getAddr());
    
    print(abruzzi.getName());
    print(abruzzi.getAge());
    print(abruzzi.getAddr());
    jack
    26
    street : Qing Hai Road, No : 123
    abruzzi
    26
    street : Huang Quan Road, No : 135

     JSON 全称为 JavaScript 对象表示法(JavaScript Object Notation),即通过字面量来表 示一个对象,从简单到复杂均可使用此方式。

    var obj = {
    name : "abruzzi",
    age : 26,
    birthday : new Date(1984, 4, 5),
    addr : {
    street : "Huang Quan Road",
    xno : "135"
    }
    }

    这种方式,显然比上边的例子简洁多了,没有冗余的中间变量,很清晰的表达了 obj 这样一个对象的结构。事实上,大多数有经验的 JavaScript 程序员更倾向与使用这种表示法,包括很多 JavaScript 的工具包如 jQuery,ExtJS 等都大量的使用了JSON。JSON事实上已经作为一种前端与服务器端的数据交换格式,前端程序通过 Ajax 发送 JSON 对象到后 端,服务器端脚本对 JSON 进行解析,还原成服务器端对象,然后做一些处理,反馈给前端的仍然是 JSON 对象,使用同一的数据格式,可以降低出错的概率。使用 JSON 作为数据交换格式,在一定程度上比 XML 更高效,冗余更小。

    而且,JSON 格式的数据本身是可以递归的,也就是说,可以表达任意复杂的数据形式。 JSON 的写法很简单,即用花括号括起来的键值对,键值对通过冒号隔开,而值可以是任意的 JavaScript 对象,如简单对象 String,Boolean,Number,Null,或者复杂对象如 Date,Object,其他自定义的对象等。

    JSON 的另一个应用场景是:当一个函数拥有多个返回值时,在传统的面向对象语言中,我们需要组织一个对象,然后返回,而 JavaScript 则完全不需要这么麻烦。

    function point(left, top){
    this.left = left;
    this.top = top;
    
    //handle the left and top
    return {x: this.left, y:this.top};
    }

     直接动态的构建一个新的匿名对象返回即可:

    var pos = point(3, 4);
    //pos.x = 3;
    //pos.y = 4;

     使用 JSON 返回对象,这个对象可以有任意复杂的结构,甚至可以包括函数对象。

    在实际的编程中,我们通常需要遍历一个 JavaScript 对象,事先我们对对象的内容一无所知。怎么做呢JavaScript 提供了 for..in 形式的语法糖:

    for(var item in json){
    //item为键
    //json[item]为值
    }
    var style = {
    border:"1px solid#cc",
    color:"blue"
    };
    for(var item in style){
    //使用jQuery的选择器
    $("div#element").css(item, style[item]);
    }

     我们在给$("div#element")添加属性的时候,我们对 style 的结构是不清楚的。

     函数,在 C 语言之类的过程式语言中,是顶级的实体,而在 Java/C++之类的面向对象的语言中,则被对象包装起来,一般称为对象的方法。而在 JavaScript 中,函数本身与其他任何的内置对象在地位上是没有任何区别的,也就是说,函数本身也是对象

    总的来说,函数在 JavaScript 中可以:

    • 被赋值给一个变量
    • 被赋值为对象的属性
    • 作为参数被传入别的函数
    • 作为函数的结果被返回
    • 用字面量来创建

     创建 JavaScript 函数的一种不常用的方式(几乎没有人用)是通过 new 操作符来作用于 Function“构造器”:

    var funcName = new Function( [argname1, [... argnameN,]] body );

    参数列表中可以有任意多的参数,然后紧跟着是函数体,比如:

    var add = new Function("x", "y", "return(x+y)");
    print(add(2, 4));

     但是,谁会用如此难用的方式来创建一个函数呢?如果函数体比较复杂,那拼接这个 String要花费很大的力气,所以 JavaScript 提供了一种语法糖,即通过字面量来创建函数:

    function add(x, y){
    return x + y;
    }

     或

    var add = function(x, y){
    return x + y;
    }

     事实上,这样的语法糖更容易使传统领域的程序员产生误解,function 关键字会调用Function 来 new 一个对象,并将参数表和函数体准确的传递给Function 的构造器。通常来说,在全局作用域(作用域将在下一节详细介绍)内声明一个对象,只不过是对一个属性赋值而已,比如上例中的 add 函数,事实上只是为全局对象添加了一个属性,属性名为add,而属性的值是一个对象,即 function(x, y){return x+y;},理解这一点很重要。

     为了说明函数跟其他的对象一样,都是作为一个独立的对象而存在于 JavaScript 的运行系统,我们不妨看这样一个例子:

    function p(){
    print("invoke p by ()");
    }
    
    p.id = "func";
    p.type = "function";
    
    var print = function(parament){console.log(parament)}
    
    print(p);
    print(p.id+":"+p.type);
    print(p());

     没有错,p 虽然引用了一个匿名函数(对象),但是同时又可以拥有属性,完全跟其他对象一样,运行结果如下:

    function (){
    print("invoke p by ()");
    }
    func:function
    invoke p by ()
  • 相关阅读:
    Mysql常用函数总结(二)
    mysql百万的数据快速创建索引
    php 中的sprintf 坑
    php5.5之后新特性整理
    mysql实践总结
    php下载远程图片到本地
    搜藏一个php文件上传类
    Attribute基本介绍
    Fiddler4抓包工具使用教程一
    HTTP传输数据压缩
  • 原文地址:https://www.cnblogs.com/Chary/p/No0000102.html
Copyright © 2020-2023  润新知