定义 || 赋值

    1-函数的定义
      函数定义的两种方式:
        “定义式”函数:function fn(){ alert("哟,哟!"); }
        “赋值式”函数:var fn = function(){ alert("切可闹!"); }
        @页面加载时,浏览器会对JavaScript代码进行扫描,并将 定义式函数进行预处理(类似C等的编译)。【函数声明提升】
         处理完再由上至下执行,遇到赋值式函数 则只是将函数赋值给一个变量,不进行预处理,待调用时才进行处理。
        @在定义前面调用函数时,定义式函数正常执行,赋值式函数会报错 (提示:oFn is not a function)。

    2-变量与函数的定义
      变量:①var a; 定义变量a。
         ②var a = 123;  定义变量a,再给变量a赋值。
      函数:①function fn(...){...}  声明函数fn。
         ②var oFn = function(...){...}  先定义变量oFn和一个匿名函数,再将匿名函数赋值给变量oFn。
        @定义变量和定义函数都会先预处理,变量赋值则是在执行中完成。
        @定义变量的作用:只是指明变量作用域。
         有定义没赋值的变量 和 使用没定义的变量 值都为undefined。
        @定义函数的作用:除了指明函数作用域,同时定义函数体结构——包括函数体内部的变量定义和函数定,此过程递归。

            alert(a);    //function a(){}
alert(b); //function b(){}
alert(c); //undefined
var a = "a";
function a() {}
function b() {}
var b = "b";
var c = "c";
var c = function() {}
alert(a); //a
alert(b); //b
alert(c); //function(){} ①虽然第一个 alert(a) 在最前面,但是你会发现它输出的值竟然是 function a() {},这说明,函数定义确实在整个程序执行之前就已经完成了。
②再来看 b,函数 b 定义在变量 b 之前,但是第一个 alert(b) 输出的仍然是 function b() {},这说明,变量定义确实不对变量做什么,仅仅是声明它的作用域而已,它不会覆盖函数定义。
③最后看 c,第一个 alert(c) 输出的是 undefined,这说明 var c = function() {} 不是对函数 c 定义,仅仅是定义一个变量 c 和一个匿名函数。
④再来看第二个 alert(a),你会发现输出的竟然是 a,这说明赋值语句确实是在执行过程中完成的,因此,它覆盖了函数 a 的定义。
⑤第二个 alert(b) 当然也一样,输出的是 b,这说明不管赋值语句写在函数定义之前还是函数定义之后,对一个跟函数同名的变量赋值总会覆盖函数定义。
⑥第二个 alert(c) 输出的是 function() {},这说明,赋值语句是顺序执行的,后面的赋值覆盖了前面的赋值,不管赋的值是函数还是其它对象。

    3-变量赋值
      对于弱类型的JavaScript,声明变量不需要声明其类型。
      随之的问题,在使用 直接量和引用量 却混乱一片:
        ①var x = "111";  var y = x;  x = "222";  alert(y);
          在JavaScript中,此时y值为111,即字符串的赋值是直接量操作,直接把数据赋值给y的存储空间。
          在java等语言中,y的值为222,即x在存储器中将地址(指针)赋给变量y。
        ②var x = ["111"];  var y = x;  x[0] = "222";  alert(y[0]);
          在JavaScript中,此时却与①不同,y[0]值为222,引用量操作,即x把在存储器中的地址(指针)赋给了y。
        ③var x = ["111"];  var y = x;  x = ["222","333"];  alert(y[0]);
          在Javascript中,此时y的值又是111,即此赋值又是直接量操作。
      JavaScript解析器 对不同类型的差异:
        var x = "xxxx";  var y = ["11","22"];
        ①在字符串中,解析器直接把字符串赋给变量x(直接量)。
        ②在数组中,解析器把数组的指针赋给变量y(引用量)。
        上述问题②中,x[o] = "222"由于没有给x新定义值,没有新开辟存储空间,只修改了它存储空间里的数据,故还是引用量。
        上述问题③中,创建var x = ["111"]时,解析器在内存中为数组创建存储空间,x则获得该空间的地址(指针),
               再执行x = ["2","3"]给数组新定义值时,解析器会开辟新存储空间放这个数组,x则为新存储空间的指针。

      由上述可知,JavaScript的变量能存储直接量 也能存储引用量。
        在大字符串连接 和 循环里赋值等地方,需留意此变量特性对执行效率的影响。

var x="";
var big = "这里是一大坨字符串...";
for (i=0; i<100; i++){
a += big;
}
x = a; //因为是字符串操作,使用直接量,每次循环都要操作大字符串,非常笨重,效率低下。如果改用引用量操作,即通过数组,效率甚至会提高十几倍: var s = "这里又是一大坨字符串...";
var a = [];
for (i=0; i<100; i++){
a[i] = s;
}
s = a.join("");

    4-原型的定义和赋值
      原型:如果构造器有个原型对象A,由构造器创建的对象实例(Object Instance)都复制于原型对象A。
        ①每个对象都有一个原型链,由自身向上包含一个或多个对象,本身为起始对象。
        ②在JavaScript中,一个对象 或 一个对象实例没有原型,不存在“持有某个原型”的说法,只存在“构造自某个原型”的说法。
                构造器才有原型,<构造器>.prototype属性指向原型。

function fn() {
var name = "大虾";
var age = 23;
function code() {
alert("切克闹!");
};
}
var obj = new fn();

        上述代码中:
          ①obj为对象实例,fn为一个构造器。
          ②obj.prototype;  //undefined,对象实例没有原型。
           fn.prototype;  //[object Object],原型是一个对象。
          ③obj.constructor;  //输出fn()的函数代码。
           fn.construtor;  //function Function(){[native code]},native code表示JavaScript引擎的内置函数。
           obj.construtor == fn;  //true,obj构造自fn。
          ④fn.prototype.construtor == fn;  //true,函数原型的构造器 默认为函数本身。

      对象实例 复制构造器的原型对象时,采用的是读遍历机制复制的。
        读遍历机制:指仅当写某个实例的成员时,将成员信息复制到实例映像中。
              即构造的新对象里面的属性 指向原型中的属性。读取对象实例的属性时,获取的是原型对象的属性值。

    Object.prototype.value = "abc";
var obj1 = new Object();
var obj2 = new Object();
obj2.value = 10; alert(obj1.value);//输出abc,读取的是原型Object中的value
alert(obj2.value);//输出10,读取的是obj2成员列表中的value
delete obj2.value;//删除obj2中的value,即在obj2的成员列表中将value删除掉
alert(obj2.value);//输出abc,读取的是原型Object中的value

              

      上述说明了读遍历机制 如何管理实例对象成员列表 和 原型中的对象成员。
        ①只有第一次对属性进行写操作时,才会在对象的成员列表中 添加该属性的记录。
        ②当obj1和obj2通过new构造出来,只是一个指向原型的引用,这样的读遍历 避免了创建对象实例可能的大量内存分配。
        ③obj2.value属性被赋值10时,obj2的成员表中添加了一个value成员并赋值10。
          此成员表记录了对象发送了修改的成员名、值与类型。遵循2个原则:
          a、保证在读取是首先访问。
          b、对象中午指定属性时,遍历对象的整条原型链,直到原型为空或找到该属性。
        ④delete obj2.value删除的是成员表的属性。

      原型的构造器
        函数的原型 是内置的Object()构造器的一个实例。但该对象实例创建后,constructor属性总会先被赋值为当前函数。
        究其根源在于构造器(构造函数)的原型(prototype)的constructor属性指向构造器本身。

function MyObject() {
} alert(MyObject.prototype.constructor == MyObject); //显示true,表明原型的构造器总是指向函数自身的 delete MyObject.prototype.constructor; //删除该成员(指向自身的原型构造器) alert(MyObject.prototype.constructor == Object);
alert(MyObject.prototype.constructor == new Object().constructor);
//删除操作使该成员指向了父代类原型中的值
//均显示为true

        上例中,myObject.protptype与new Object()没有实质区别,只是在创建时将myObject的constructor值赋值为自身。
        函数与构造器并没有明显的界限:
          当指定一个函数的prototype时,该函数就会成为构造器。
          此时用new创建实例时,引擎会构造一个新对象,把这个新对象的原型链 连接向该函数prototype属性就可以了。

      原型继承中的“原型复制”
        通过设置 不同构造器创建出来的实例的constructor属性,能指向同个构造器。

function MyObject() {
}
function MyObjectEx() {
}
MyObjectEx.prototype = new MyObject();
var obj1 = new MyObject();
var obj2 = new MyObjectEx();
alert(obj2.constructor == MyObject); //true
alert(MyObjectEx.prototype.constructor == MyObject); //true

        obj1和obj2是由不同的两个构造器(MyObject和MyObjectEx)产生的实例。然而,两个alert都会输出true,即由两个不相同的构造器产生的实例,它们的constructor属性却指向了相同的构造器。这体现了原型继承中的“原型复制”。MyObjectEx的原型是由MyObject构造出来的对象实例,即obj1和obj2都是从MyObject原型中复制出来的对象,因此它们的constructor指向的都是MyObject!

最新文章

  1. hexo+github搭建个人博客
  2. .NET的ExcelOperate
  3. ReactNative win10初体验
  4. LInux_System_Call_INT_80h
  5. qmake的使用(可设置c编译器flag参数)
  6. 【团队项目演示】FZU5BOYS之团队项目链接汇总
  7. Android软键盘弹出时把布局顶上去的解决方法
  8. ylbtech-QQ(腾讯)-群空间-数据库设计
  9. C++中的头文件和源文件
  10. object C—类中函数的调用
  11. IE6与W3C标准的盒模型差异
  12. 如何让input之间无空隙
  13. 武汉科技大学ACM:1005: 单位转换
  14. hbmy周赛1--A
  15. MySQL 的几种进入方式
  16. Netty 系列二(传输).
  17. volatile 关键字了解与使用
  18. JavaScript 中的匿名函数((function() {})();)与变量的作用域
  19. GNU make使用(二)
  20. python 读csv文件时,在csv类型上执行类型转换

热门文章

  1. angular js 自定义指令
  2. (部署新java程序,程序报错,需copy的一个包)——java使用siger 获取服务器硬件信息
  3. less,sass,stylus配置和应用教程及三者比较
  4. JavaScript 使用 sort() 方法从数值上对数组进行排序
  5. CI框架初探
  6. centos 单独安装PHP的mysql和mysqli扩展
  7. Hadoop入门程序WordCount的执行过程
  8. ubuntu 13.10 amd64安装ia32-libs
  9. mybatis异常:Improper inline parameter map format. Should be: #{propName,attr1=val1,attr2=val2}问题分析及解决
  10. CodeForces - 426B(对称图形)