定义 || 赋值

    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!

JavaScript 变量、函数与原型链的更多相关文章

  1. JavaScript之继承(原型链)

    JavaScript之继承(原型链) 我们知道继承是oo语言中不可缺少的一部分,对于JavaScript也是如此.一般的继承有两种方式:其一,接口继承,只继承方法的签名:其二,实现继承,继承实际的方法 ...

  2. JavaScript高级内容:原型链、继承、执行上下文、作用域链、闭包

    了解这些问题,我先一步步来看,先从基础说起,然后引出这些概念. 本文只用实例验证结果,并做简要说明,给大家增加些印象,因为单独一项拿出来都需要大篇幅讲解. 1.值类型 & 引用类型 funct ...

  3. JavaScript 随笔2 面向对象 原型链 继承

    第六章 面向对象的程序设计 1.创建对象的几种方式 A)工厂模式 function CreatObj(name,sex,age){ this.name=name; this.sex=sex; this ...

  4. javascript 重难点(原型链 this) 理解总有一个过程,不要急,循序渐进!

    开始补充: 1. 将函数定义作为对象的属性,称之为对象方法.2. this的指向是由它所在函数调用的上下文决定的(语境),而不是由它所在函数定义的上下文决定的.3. 因为当一个函数作为函数而不是方法来 ...

  5. javascript中继承(一)-----原型链继承的个人理解

    [寒暄]好久没有更新博客了,说来话长,因为我下定决心要从一个后台程序员转为Front End,其间走过了一段漫长而艰辛的时光,今天跟大家分享下自己对javascript中原型链继承的理解. 总的说来, ...

  6. Javascript之继承(原型链方式)

    1.原型链 原型链是JavaScript中继承的主要方法. 每个构造函数都拥有一个原型对象,原型对象都包含一个指向构造函数的指针(constructor),实例都包含一个指向原型对象的内部指针(__p ...

  7. javascript 面向对象 new 关键字 原型链 构造函数

    JavaScript面向对象JavaScript 语言使用构造函数(constructor)作为对象的模板.所谓"构造函数",就是专门用来生成实例对象的函数.它就是对象的模板,描述 ...

  8. javascript 创建对象及对象原型链属性介绍

    我们知道javascript里定义一个普通对象的方法,如: let obj = {}; obj.num = 1; obj.string = 'string'; obj.func = function( ...

  9. javascript基础学习系列-原型链模式

    1.demo代码如下: 2.画图如下: 3.规则: 1)每一个函数数据类型(普通函数/类)都有一个天生自带的属性:prototype(原型),并且这个属性是一个对象数据类型的值 2)并且prototy ...

随机推荐

  1. 在rails下新建表

    (文章都是从我的个人主页上粘贴过来的,大家也可以访问我的主页 www.iwangzheng.com) 今天需要新建表,以下是建表语句 rails generate scaffold users ema ...

  2. 阿里云服务器配置 SVN 服务器与生产站点同步

    作为linux的门外汉,一直觊觎svn的方便性,在有台aliyun的情况下,一起来搞搞.   1.环境   阿里云 centos5.5   2.安装svn   yum -y install subve ...

  3. Android-自定义meta-data扩展数据

    在接入第三方渠道SDK的时候,经常会看到其配置文件AndroidManifest.xml有类似如下的定义: [html] view plaincopy <!-- appid --> < ...

  4. 转关于垂直切分Vertical Sharding的粒度

    垂直切分的粒度指的是在做垂直切分时允许几级的关联表放在一个shard里.这个问题对应用程序和sharding实现有着很大的影响. 关联打断地越多,则受影响的join操作越多,应用程序为此做出的妥协就越 ...

  5. Java for LeetCode 025 Reverse Nodes in k-Group

    Given a linked list, reverse the nodes of a linked list k at a time and return its modified list. If ...

  6. Android Handler leak 分析及解决办法

    In Android, Handler classes should be static or leaks might occur, Messages enqueued on the applicat ...

  7. hadoop命令备忘

    hadoop dfsadmin -safemode get 查看namenode是否处于安全模式 hadoop dfsadmin -report 显示文件系统的统计信息,以及所连接的各个datanod ...

  8. 【读书笔记】读《JavaScript高级程序设计-第2版》 - 函数部分

    1. 定义 函数实际上是对象,每个函数都是Function类型的实例,而且都与其他引用类型一样具有属性和方法.由于函数是对象,因此函数名实际上也是一个指向函数对象的指针,不会与某个函数绑定. 对于函数 ...

  9. 归并排序的分析与Java实现

    归并操作(merge),也叫归并算法,指的是将两个已经排序的序列合并成一个序列的操作.归并排序算法依赖归并操作.该算法是采用分治法(Divide and Conquer)的一个非常典型的应用.归并排序 ...

  10. hdu 1166 线段树单点更新

    等线段树复习完再做个总结 1101 2 3 4 5 6 7 8 9 10Query 1 3Add 3 6Query 2 7Sub 10 2Add 6 3Query 3 10End Case 1:633 ...