function


Javascript定义类(class)的三种方法紫陌兰溪关注

JS Prototype和原型链详解

function Obj() {
    var a = 0;                  //私有变量
    var fn = function(){}       //私有函数
    Obj.a1 = 1;                 //静态变量
    Obj.fn1 = function(){}      //静态函数
    this.a2 = 2;                //实例变量
    this.fn2 = function(){}     //实例函数
}
var o = new Obj();
console.log(o.a2);              //2
console.log(o.a)                //undefined
console.log(o.a1);              //undefined
console.log(Obj.a1)             //1

var o1 = {}
var o2 = new Object();
var f1 = function() {};
var f2 = new Function('str', 'consoloe.log(str)');
console.log(typeof o);          //object
console.log(typeof o1);         //object
console.log(typeof o2);         //object
console.log(typeof f1);         //function
console.log(typeof f2);         //function
console.log(typeof o.fn2);      //function
JS中万物该对象,分为普通对象Object和函数对象function。  Obj本质是通过new Function创建的函数对象

原型链执行过程:
1.代码读取某个对象的某个属性的时候,搜索具有给定名字的属性,
2.搜索首先从对象实例开始,如果在实例中找到该属性则返回,
3.如果没有则查找prototype,如果还是没有找到
4.则继续递归prototype的prototype对象,直到找到为止,
5.如果递归到object仍然没有则返回错误。

JS在创建对象时,都有一个__proto__内置属性,用于指向创建它的函数对象的prototype,经过多重继承向上查找后,最终指向Object对象。
Objerct.__proto__指向null.

实例对过构造函数创建的,实例具有两个属性:
1.constructor   指向构造函数
2.__proto__     指向原型对象
原型对象有一个指针指向构造函数
Person.prototype.constructor = Person;

通过return的形式暴露出简单的使用名称,以达到public/private的效果,修改后的代码如下:
Calculator.prototype = function () {
    add = function (x, y) {
         return x + y;
    },
    subtract = function (x, y) {
         return x - y;
    }
    return {
         add: add,
         subtract: subtract
    }
} ();
(new Calculator()).add(11, 3);

Javascript 面向对象编程

定义对象

    Member = function(id, name) {
        this.id = id;
        this.name = name;
    }
或者
function Member(id,name) {
    this.id = id;
    this.name = name;
    this.showMe = function() {
        document.write();
    }
    this.do = todo;
}
function todo() {
    alert('todo');
}
Member.prototype.log = function() {
    alert('log');
}
Member.prototype = {
    greet: function() {
        alert('hello' + this.name);
    }
    info : function() {
        alert('id:' + this.id + ', name:' + this.name);
    }
}
m1 = new Member(1, 'tom');
m2 = new Member(2,'jenny');
m1.showMe();
m2.showMe();                //函数定义在内部,每次构造实例,都会定义一次,消耗系统资源
m1.greet();
m2.greet();                 //函数定义在prototype, 每个实例由prototype指向一个函数引用

继承

function Animal(name){
    this.name = name;
    this.showName = function(){
        alert(this.name);
    }
}
function Cat(name){
    Animal.call(this, name);
}
var cat = new Cat("Black Cat");
cat.showName();



或者:
 Cat.prototype = new Animal();
 Cat.prototype.constructor = Cat;
 var cat1 = new Cat("大毛","黄色");
 alert(cat1.species); // 动物

或者:
 Cat.prototype = Animal.prototype;
 Cat.prototype.constructor = Cat;
 var cat1 = new Cat("大毛","黄色");
 alert(cat1.species); // 动物

或者:
 var F = function(){};
 F.prototype = Animal.prototype;
 Cat.prototype = new F();
 Cat.prototype.constructor = Cat;

将上面的方法,封装成一个函数,便于使用。
function extend(Child, Parent) {
  var F = function(){};
  F.prototype = Parent.prototype;
  Child.prototype = new F();
  Child.prototype.constructor = Child;
  Child.uber = Parent.prototype;
}
uber是一个德语词,意思是"向上"、"上一层",即保存了父类的prototype

使用的时候,方法如下
 extend(Cat,Animal);
 var cat1 = new Cat("大毛","黄色");
 alert(cat1.species); // 动物
这个extend函数,就是YUI库如何实现继承的方法

拷贝继承

function extend2(Child, Parent) {
  var p = Parent.prototype;
  var c = Child.prototype;
  for (var i in p) {
    c[i] = p[i];
    }
  c.uber = p;
}

使用的时候,这样写:
 extend2(Cat, Animal);
 var cat1 = new Cat("大毛","黄色");
 alert(cat1.species); // 动物

非构造函数的继承

有一个对象,叫做"中国人"。
 var Chinese = {
   nation:'中国'
 };
还有一个对象,叫做"医生"。
 var Doctor ={
   career:'医生'
 }

 function object(o) {
   function F() {}
   F.prototype = o;
   return new F();
 }

使用的时候,第一步先在父对象的基础上,生成子对象:
  var Doctor = object(Chinese);
然后,再加上子对象本身的属性:
  Doctor.career = '医生';
这时,子对象已经继承了父对象的属性了。
  alert(Doctor.nation); //中国

浅拷贝

 function extendCopy(p) {
    var c = {};
    for (var i in p) { 
      c[i] = p[i];
    }
    c.uber = p;
    return c;
 }
使用的时候,这样写:
  var Doctor = extendCopy(Chinese);
  Doctor.career = '医生';
  alert(Doctor.nation); // 中国

深拷贝

  function deepCopy(p, c) {
    var c = c || {};
    for (var i in p) {
      if (typeof p[i] === 'object') {
        c[i] = (p[i].constructor === Array) ? [] : {};
        deepCopy(p[i], c[i]);
      } else {
         c[i] = p[i];
      }
    }
    return c;
  }
使用的时候这样写:
  var Doctor = deepCopy(Chinese);

现在,给父对象加一个属性,值为数组。然后,在子对象上修改这个属性:
  Chinese.birthPlaces = ['北京','上海','香港'];
  Doctor.birthPlaces.push('厦门');
这时,父对象就不会受到影响了。
  alert(Doctor.birthPlaces); //北京, 上海, 香港, 厦门
  alert(Chinese.birthPlaces); //北京, 上海, 香港
目前,jQuery库使用的就是这种继承方法。