尼莫叮

  博客园 :: 首页 :: 新随笔 :: 联系 :: 订阅 :: 管理 ::

1. js 语言特性: 弱类型,不必声明变量类型。

    3种原始类型:布尔型,数值型,字符串型;此外还有对象类型,函数类型,空类型(null)未定义类型(undefined)

    原始类型按值传递,其他类型引用传递

    javascript中模仿借口的三种方法: 注释法,属性检查法 和 鸭式辨型发   

 

 2. JavaScript构造类以及类的继承:

     //****** Define the classA
    // 使用构造函数创建属性,prototype创建方法
    
    // 原因: 1. 使用构造函数构建属性,实例化的每个对象就会有自己的属性,并且可以有初始化时参数
    //       2. 而使用prototype构建方法的好处是,实例化的对象共享这个方法体,节省内存
    function ClassA(id, age) {
        this.id = id;
       this.age = age;
    }
     /*
     等同于上面使用构造函数的定义方法,这里使用的是匿名function定义类 
     var ClassA = function () {
       this.id = id;
        thia.age = age;
     } 
     */

    ClassA.prototype.sayId = function() {
constuctor: ClassA, alert(
this.id); }; ClassA.prototype.sayAge = function () {
     alert(
this.age);    } /* 等同于上面的定义方法的方式      ClassA.prototype = {       sayId: function() {         alert(this.id);       },       sayAge: function() {         alert(this.age);       }     }      */
    //****** Define the ClassB that inherit from ClassA 组合(构造函数+原型)继承
    function ClassB(id, name) {
        ClassA.call(this, id);
        this.name =name;                                         
    }
    ClassB.prototype = new ClassA();
ClassB.prototype.constructor = ClassB; ClassB.prototype.sayName
=function(){ alert(this.name); } var b = new ClassB(222, "nemo"); console.log(b.id); console.log(b.name); b.sayId();
// 字面量方式来定义类

function Person() {
}
Person.prototype = {
  constructor: Person,   name:
"default name",   getName: function () {     return this.name;   } }; // 原型式继承 var reader = clone(Person); function clone(object) { // 这里相当于定义一个子类的构造函数 function F () {}; // 把传进来的父类参数作为子类的prototype属性 F.prototype = object; // 最后new创建出一个新的对象 并返回 return new F; }
// clone 出来的所有子类都共享父类对象的每个属性和方法的唯一一份实例,因此相比类式继承 更节省内存空间
// 同时需要注意:对继承而来的成员的读和写的不对等性:读取时是读取原型的属性,儿写属性时则是为实例新创建一个属性并覆盖了同名的原型属性
alert(reader.name);

 说明:

  当执行 var person1 = new ClassA() 时所实际发生的事情:这里定义的ClassA 实质上只是一个function对象,C大写也只是约定。因此他和别的函数没有本质区别,而和其他功能性函数的重要区别在于函数内部定义的方式(使用了this关键字来定义域的变量,表示这些变量属于所定义的这个函数)以及调用方式(使用new来调用)。当使用new关键字来初始化这种定义方式的function时:

  1) 因为使用的new关键字,因此这时创建一个新对象

  2) 将函数的作用域赋给新对象,因此this就指向这个新对象

  3) 执行函数中的代码,这时为对象添加属性

  4) 返回new关键字定义的对象

 

====================================================================================================== 

原型,构造函数,实例之间的关系:

创建的每个函数(当然包含构造函数)都有一个原型属性,原型属性是一个对象,即prototype是一个对象。原型对象包含了构造函数所定义的所有属性和方法。

除此之外prototype默认会创建一个constructor属性,这个属性是对构造函数的一个引用,即又指向了构造函数。因此构造函数 和 其prototype之间是双向引用的关系。

而由构造函数创建的实例都包含一个__proto__属性,这个属性指向构造函数的prototype属性对象,因此每个实例才都共享同一个prototype这个对象。而实例和构造函数没有直接关系,是和构造函数的prototype直接相关。

 

 

 

 

3. JS闭包:

当在一个函数 outter 内部定义另一个函数 inner,而 inner 又引用了 outter 作用域内的变量,在 outter 之外使用 inner 函数,则形成了闭包。描述起来虽然比较复杂,在实际编程中却经常无意的使用了闭包特性。

function foo () {
    
    var a = 10;    
    
    function bar () {
        a = a * 2;
        return a;
    }
    return bar;
}

var baz = foo();
baz(); // return 20.
baz(); // return 40.
baz(); // return 80.

var bult = foo();
bult(); // return 20;

函数式运行在定义它们的作用域中(foo内部的作用域),而不是运行在调用它们的作用域中。只要bar被定义在foo中,它就能访问在foo中定义的的所有变量,即使foo的执行已经结束。

在foo返回后,它的作用域被保存下来,但只有它返回的那个函数能够访问这个作用域。即只有bar能访问这个作用域。

 

4. 用闭包实现私有成员:

var Book = function (id, name) {
    // private attributes 定义私有变量/属性,这里定义的时候没有使用this关键字,表明只存在于Book构造器中
    var id, name;

    // private method
    function checkId () {
        ...
    }
   
    // Privileged methods 定义私有变量的get,set方法,这里形成闭包,即针对一个book的实例,只有这个实例的getId这个方法能访问book内的id变量,
    this.getId = function() {
        return id; 
    }
    this.setId = function(newId) {
        if (!checkId(newId)) throw new Error ('Book: Invalid Id');
        id = newId;
    } 
    
    this.getName = function () {
        return name;
    }
    this.setName = function(newName) {
        name = newName;
    }

    // Constructor code 调用上面的get,set方法来完成构造函数的私有变量初始化工作
    this.setId(id);
    this.setName(name);
};

// public method, non-privileged method 在prototype里定义公有方法,公有方法需要访问私有属性的时候 就可以调用上面定义的get,set方法
Book.prototype = {
    display: function () {
        ...
    }
    ...
}

 

5. JS的作用域工作原理:

第一步:创建: 首先在js中方法也是一个对象,因此方法也可以有自己的属性。当方法被创建时,他的一个内部属性(仅供js引擎使用) [[scope]]被创建, 这个[[scope]]又包含一个属性叫作用域链,他包含创建这个函数的作用域中所有对象的集合( eg:如果这个函数是在全局中创建的,那作用域链中就包含:window, document, 以及定义在全局中的变量 )。我觉得这里可以忽略[[scope]] 这个属性,而记住函数在创建的时候,会随之创建与他相关的作用域链。

第二步:运行: 当运行这个方法时,会创建另一个内部对象叫运行期上下文。一个运行期上下文定义函数运行时的环境。运行期上下文有自己的作用域链,里面包含两个对象,第一个叫“激活对象”,包含访问所有局部变量,命令参数,参数集合,和this的接口。第二个是之前定义函数时创建的作用域链。

因此,在函数运行的过程中,每遇到一个变量,为了获取其值都会从运行期上下文的作用域链中从上到下进行搜索。即先从“激活对象”(局部变量, 命令参数...)中找。如果找不到,再到定义函数时的创建的作用域链中找。如果始终找不到,则被认定为未定义。

这样就可以理解:闭包中内层函数可以读取外层函数内定义的变量。

与此相关的优化工作:因为读取局部变量 比 读取创建作用域链中的变量(在更深层次中查找) 的性能开销大,因此在函数多于一次使用本地范围之外的变量值时,可以考虑先定义一个本地变量来引用这个外地变量,之后使用这个定义的本地变量。这样只需要查找一次,节省开销。简单的说,引入局部变量,消除搜索深度搜索过程。   

 

6. JS中的原型prototype

JavaScript中的对象是基于原型的。原型是其他对象的基础,定义并实现了一个新对象所必须具有的成员。原型对象为所有给定类型的对象实例所共享,因此所有实例共享原型对象的成员。  

每个对象的实例包含两种类型的成员: 实例成员(自己定义的成员),原型成员(从对象原型中继承的成员) 

可以用hasOwnProperty() 来判断一个对象是否具有特定名称的"实例成员"。 eg:book.hasOwnProperty("title");

可以用in来判读对象是否具有某个名称的属性. eg: "title" in book; 

7. 原型链:P49

8. 静态方法和属性:

9. DOM性能:轻轻的触摸DOM,并尽量保持在ECMAScript中。 

 

 

 

 

 

 

posted on 2013-02-20 09:58  尼莫叮  阅读(144)  评论(0)    收藏  举报