`

js类型, 值, 变量

阅读更多

类型:

基本类型:number,string, boolean,null, undefined,其中number,string,boolean都有wrapper objects,所以他们有对应的方法可以调用,但是null和undefined就没有。

其余的都是object类型。

普通的object类型是一个无序的key-value集合.

array,function,date,regular,error等是特殊的对象,js对这些特殊对象提供了额外的支持。

 

数字:

数学运算在js中是不报错的,比如除0,负数开方等,而是会返回特殊的结果。

js中任何数都是用二进制浮点数(binary floating-point numbers))表示的,所有无法分解为1/2(n)形式的小数都无法精确表示,比如0.1

console.log(0.3-0.2);//无法精确表示

 

String:

js使用utf-16编码来表示字符串

 

null undefined:

null是关键字,而undefined只是一个全局变量,在ECMA5之前undefined值是可以被改变的

 

Wrapper Objects:

三种基本类型:number,string和boolean都有对应的wrapper object,访问基本类型的属性或方法时,会自动进行装箱操作。比如string a="a"; a.substring(1);,调用substring方法时,会自动使用包装类将a装换成一个临时的String对象,即进行了如下的操作:var a = new String(a); 所以才可以调用a.substring方法,使用完毕后销毁。类似于java中的自动装箱。

 

var s="a";  
s.len=4;  
console.log(s.len);     //undefined  

 

 

 

理解上述代码,因为第二行代码执行时,由于访问了s的属性,此时s不是第一行中的s二是一个临时的String对象,自然在第三行中赋值时会出错。

也可以自己手动装箱:var s = new String(s);

注意:不能用length做试验,因为它和方法一样是字符串对象自带的,你去调用它也是临时生成一个String对象的,这会干扰你的判断。

var s="a";  
/*这里再用此句: s=new String(s),设置length也不会改变s.length的值。照此你可能会得出结论说:new String(s)并不能创建新对象,其实不是的,而是你打印的是s对象的自带属性length,而不是自定义属性len */ s.length =4;  
console.log(s.length);     //1  

 

同样,装箱有对应的拆箱操作,在必要的时候会把String对象拆箱为s。

 

immutable & mutable:

五种基本类型都是不可变的:number,boolean,string,undefined,null, 任何对他们的改变本质都是创建了一个新的变量。

基本类型的比较操作都是根据其值的,只有string不同,是根据其长度和每个index的字符。

object类型默认是比较引用的,比如Array。

 

类型转换:

对象转换成基本类型有如下两个方法:toString(), valueOf(), 一个是转成string,一个是转成数字。

 

function scope:

js的作用域是function scope,也就是函数内声明的局部变量在整个函数内部都是可以访问的,区别于很多语言的block scope.

用var声明的局部对象是不可以delete的。

hoisting 特性:函数内的所有变量都相当于自动在函数头部声明(注意,只是声明被移到头部,赋值部分位置不变)。所以有些js程序员喜欢在函数开头声明所有变量是有道理的。

 

[javascript] view plain copy
 
  1. function(){  
  2.      return a;  
  3.      var a=1;  
  4. }  
  5. //以上代码等价于以下代码  
  6. function(){  
  7.      var a;  
  8.      return a;  
  9.      a=1;  
  10. }  
  11.   
  12. //看看另一个代码  
  13. a = 1;  
  14. function f(){  
  15.      console.log(a);  
  16.      var a = 2;  
  17. }  
  18. f();     //输出undefined,而不是输出1,等价转换一下就明白了  
  19.   
  20. //上述代码等价一下代码  
  21. a = 1;  
  22. function f(){  
  23.      var a;  
  24.      console.log(a);  
  25.      a=2;  
  26. }  
  27. f();     //所以就很明显该输出undefined。  



 

 

eval, delete

直接调用eval(string),作用域就是当前代码的作用域,在很多实现中(除ie外),如果使用另一个名字调用eval,则作用域会自动变为全局作用域。

ie中有一个execScript和eval类似,但是作用域会变成全局作用域。

delete操作无法删除var定义的变量,delete只适合于删除某一对象的属性,但是delete操作是不会报错的。

delete不会影响父类的属性

在ECMA5 strict模式下,delete任何不能被delete的变量都会报错,并且无法删除configurable为false的属性

 

function

调用任何一个function时都有两种参数:arguments 和 context(隐式传递,即函数中的this);

四种调用方式:

1,函数调用, a(1);

2,方法调用,o.a(1);

3, 构造函数调用,new a(1);

4, 简介调用,a.call(this, 1); a.apply(this, 1);

函数调用和方法调用的区别是context的不同,函数调用的context一般是global(在E5 strict模式下是undefined),方法调用的context是o.

构造函数var a = new A(1); context是a, 如果A返回一个object类型,则a就是返回值,如果A返回的不是object类型,则返回值被忽略。

js不会检查函数的参数类型和参数个数,js中也不存在函数重载。

function hoisting

function声明和局部变量声明一样,也会被hoisting到当前作用域的顶部,赋值部分位置不变,所以:

var a=function(){};     //在此之前无法使用a(),因为只有var a;被升到顶部,而赋值部分位置不变

function a(){};     //在此之前就可以使用a,因为整个语句被升到顶部了。

method chaining

如果method总是返回this,那么可以进行链式操作,如jQuery。

 

closure

嵌套的函数声明即为闭包。

 

闭包的原理:函数的作用域是函数定义时的作用域,而不是函数调用时的作用。

闭包的实现:因为每产生一个函数都会生成一个新的scope chain, 一般情况函数结束后就没有对这个scope chaine的引用,因此scope chain被销毁,但是如果有闭包的存在,因为内部函数的scope chain引用了外部函数的scopechain,所以外部函数的scope chain不会被销毁。

 

如果调用多次外部函数,则会创造多个scope chain,因此每一个闭包访问的外部scope chain都是独立的:

 

[javascript] view plain copy
 
  1. function f(){  
  2. var a = 1;  
  3. return  function(){return ++a;};  
  4. }  
  5. f()(); f()();//都会返回2,因为调用了两个f。  
  6. var c= f();  
  7. c();c();//返回2,3,因为他们的scope chain是一样的。  



 

一个经典的错误:

 

[javascript] view plain copy
 
  1. function f(){  
  2.      var funs = [];  
  3.      for(var i=0;i<10;i++){  
  4.           funs.push(function(){return i;});;  
  5.      }  
  6.      return funs;  
  7. }  
  8. var funs = f();  
  9. funs[5]();     //总是返回10  



 

因为10个fun共享同一个i,当函数f调用结束后,i == 10;

正确的做法是,利用闭包构造多个不同的scope chain,这样每一个fun都有自己独立的scope chain。

正确的写法如下:

 

[javascript] view plain copy
 
  1. function f(){  
  2.      var funs = [];  
  3.      for(var i=0;i<10;i++){  
  4.           (function(x){  
  5.                funs.push(function(){return x;});;  
  6.           })(i);  
  7.      }  
  8.      return funs;  
  9. }  
  10. var funs = f();  
  11. funs[5]();     //总是返回10  



 

 

闭包可以用作产生block作用域,因为js是函数作用域的。严格来说这不算闭包的特性。

(function(){

//put your code here.

}());

注意最外层的()不要省略了,省略之后就是函数定义,加上()之后才是函数表达式。

 

利用闭包还可以实现bind函数,将一个函数的this绑定到一个对象上:

 

[javascript] view plain copy
 
  1. function bind(f,o){  
  2.      return function(){  
  3.           f.apply(o, arguments);  
  4.      };  
  5. }  



 

 

闭包内的函数可以直接访问外部函数的作用域,但是,内部函数的this指针并不继承自外部函数,如果想使用外部函数的this,可以使用上面的bind函数,也可以直接使用闭包,一般如下:

 

[javascript] view plain copy
 
  1. function out(){  
  2.      var self = this;     //存储this到一个局部变量,因为内部函数可以访问这个局部变量  
  3.      function inner(){  
  4.           self.xxx;     //使用外部函数的this  
  5.      }  
  6. }  



 

 

memoization

memoization 即函数返回值的缓存。如果用同样的参数调用同一个函数多次,那么从第二次开始就可以从缓存中直接取返回结果而不需计算。此例用到了闭包,当然也可以用构造函数做。

 

[html] view plain copy
 
  1. function memoize(f){  
  2.      var cache = {};  
  3.      return function(){  
  4.           var key = arguments.length + Array.prototype.join.call(arguments, ",");  
  5.           if(key in cache) return cache[key];  
  6.           else return cache[key]=f.apply(this, arguments);  
  7.      };  
  8. }  



 

for in

for(var name in object) 其中每次遍历出来的是object中属性的name 而不是value。

for in 循环只能遍历出enumerable的属性,

built-in method 和 built object不能被遍历出来,例如toString等。

所有用户自定义的属性都可以被遍历出来,用户自定义的继承属性也可以被遍历出来

一般遍历属性的顺序和这些属性声明的顺序是相同的,即先声明的属性先被遍历出来。

在ECMA5标准中,用户可以自定义属性是否是enumerable

 

 

native objects, hosting objects

native objects:由ECMAScript定义的对象,如:arrays, functions, dates, regular expressions.

hosting objects: 由宿主环境定义的变量,如dom element.

 

create objects

三种方法:

1,字面量:

var a = {a:1,b:2}; 

a.__proto__ == Object.prototype;

如果key中含有特殊字符或者key是保留字,可以用引号。

2, 构造函数

var a = new Constructor(a, b);

不同于字面量,a.__proto__ == Constructor.prototype;

3, Object.create

ECMAScript5中引入的新方法

var a = Object.create(Object.prototype); //等价于var a = new Object();

创建一个对象,第一个参数是prototype,可选的第二个参数是属性。如果不设置prototype,不会从Object继承。

原理:

  1. if (typeof Object.create !== 'function') {  
  2.     Object.create = function(o) {  
  3.         function F() { }  
  4.         F.prototype = o;  
  5.         return new F();  
  6.     }; 
  7.  } 

 

 

访问属性

假设:

a={a1:"a"};

b={b1:"b"};

b.__proto__ = a;

也就是b有自己的属性b,同时继承了a中的a1属性,那么:

1,b.b1, b.a1, 能正确的获取b和a中对应的属性值

2,b.b1 = "c" 能正确的修改属性值, 但是b.a1=“c”,不是修改了a的属性,而是添加了一个b.a1属性,从而影藏了a.a1,如果在执行delete b.a1 则此时b.a1 == a.a1;

3, 如果a.a1是只读的,那么b.a1="c"会出错,既不会在b上新增一个a1属性,也无法修改a.a1的值。

总结就是:get操作会对父类进行查询,set操作不会影响父类的属性值(最多就是因为重名而使父类属性被影藏了)

 

property attribute & object attribute

在ECMAScript5标准中,可以为property配置attribute。

每个property有四个attribute:value, writable, enumerable, configurable.

如果是个accessor property,则没有value和writable, 而对应的是get和set。

 

[javascript] view plain copy
 
  1. Object.defineProperty(obj, "p",{  
  2.      value:1,  
  3.      writable:true,  
  4.      enumerable:true,  
  5.      configurable:true  
  6. }  
  7. );  



 

同E3中对属性的的访问,如果没有p属性,则是添加操作,此时没有定义的attribute默认为false;如果p已经存在,则是修改操作,此时未定义的attribute值保持不变。

 

每个object都有三个attribue:prototype, class, extensible

prototype:访问方法:

1,obj.constructor.prototype 

2,在firefox,safari和chrome中都可以 obj.__proto__直接读写prototype,非标准不建议使用

3,E5中可以使用Object.getPrototypeOf(obj)

class:定义了obj的type,但不是不同于typeof。在E3和E5中都没有直接方法可以访问到,只能间接地通过toString方法来读取。如果下方法利用toString来获取class。

 

[javascript] view plain copy
 
  1. function classof(o){  
  2.      if(o === null) return "Null";  
  3.      if(o === undefined) return "Undefined";  
  4.      return Object.prototype.toString.call(o).slice(8,-1);     //因为有些js库会污染toString方法,所以这样调用,而不是用o.toString()  
  5. }  



 

extensible:

object是否可以被add/delete property,在E3中任何对象都是可以的,在E5中可以自定义。

Object.isExtensible(o);

Object.preventExtensible(o);一旦调用此方法之后,没有方法可以再变回去。

Object.seal():同时设置extensible false,并且改对象所有property.configurable=false。注意如果property是可写的,仍然可以改变其值,只是无法删除也无法添加新的。

Object.freeze():在seal基础上同时设置所有property为read-only。

注意:上述方法都只对object本身起作用,不影响其原型链上的东西。

 

JSON & serializing object

https://github.com/douglascrockford/JSON-js/blob/master/json2.js 文件中定义了JSON.stringify和JSON.parse函数,这两个函数现在在E5中是内置函数了,chrome,firefox,safari等高级浏览器都提供了原生的JSON对象。

 

数组

array是一个特殊的object,特殊在一下三个地方

1, 其index 是一种特殊的 object property,特殊在其值只能是32bit的整数。

2,从Array.prototype继承了一些方法

3,会自动维护一个length属性。如果设置任何一个index>=length的元素,则length=index+1;如果设置length,则删除所有index>=length的元素。

除此之外,array和object没什么区别。

所以可以理解js中的array没有out of bound错误,因为查询一个大于length-1的index时,会被当做一个普通的property来对来,自然会返回undefined而不是报错。

 

对象 === 关联数组 === hashmap

在js中,对象就是关联数组(或者理解为map),其本质就是key->value的无序集合。

稀疏数组 sparse array

sparse array是指index不是0开始并连续的数组,和element为undefined的数组是不同的。

var a = new Array(5);     //没有元素,但是length为5,这是稀疏数组。

var a = {,,,,,}; //有5个元素,值为undefined, 这是普通数组,不同于稀疏数组。

 

很多数组方法对于array-like object,比如novelist都是适用的,通过Array.prototype.xxx.call(nodelist,x)的方式来调用。

所谓arra-like object,就是有index和有length属性的object,并且能用[]操作符来取值。

在E5中,string也是array-like的,不过是一个read-only array-like。

分享到:
评论

相关推荐

    JavaScript 深入学习【词法结构值类型和变量】

    JavaScript 深入学习【词法结构值类型和变量】

    微信小程序关于变量对象data 和 前端wxml取后台js变量值

    对象data定义的变量支持各种数据类型,string,int,[],{} **第一.**wxml数据渲染,只要通过设置data值(this.setData({...}))即可 如: wxml页面:detail对象中包含有TaskBillCode与BillDate两个属性 (此图片来源于...

    引用类型按值传递举例.png|引用类型按值传递举例.png

    Js引用类型按值传递的题目:两个变量间赋值时,以及作为变量给函数传参时,只是将原变量中的值复制一个副本给对方变量或形参变量 i. 对于原始类型的值,修改新变量,不影响原变量 ii. 对于引用类型的值的值,因为...

    JS前端面试基础-变量类型与计算

    JS面试之-变量类型和计算一、JS基础1.值类型和引用类型2.typeof运算符3.深拷贝(重点)二、变量计算和类型转换1.字符串拼接2. == 和 ===3.if语句与逻辑计算三、问题解答和总结1.typeof可以判断哪些类型2. 何时使用==,...

    JS学习之变量、数据类型比较

    JavaScript的语法 (1)ECMAScript中的一切(变量、函数名和操作符)都区分大小写。 (2)JavaScript的标识符:变量、函数、属性的名字,或者函数的参数。 标识符的命名规则: ...JS的数据类型 基本

    javaScript的数据类型

    还有 1种复杂数据类型——Object,Object 本质上是由一组无序的名值对组成的。ECMAScript 不支持任何创建自定义类型的机制,而所有值最终都将是上述 6 种数据类型之一。乍一看,好像只有 6种数据类型不足以表示所有...

    【JavaScript源代码】JavaScript高级程序设计之变量与作用域.docx

     目录 1、原始值与引用值2、instanceof3、作用域 1、原始值与引用值 2、instanceof 3、作用域 1、原始值与引用值 6种简单数据类型的值都是原始值, 原始值通过变量赋值给另一个变量时,会复制一个出一个新的...

    JavaScript的类型、值和变量小结

    主要介绍了JavaScript的类型、值和变量小结的相关资料,需要的朋友可以参考下

    Web前端开发技术-认识JavaScript的数据类型.pptx

    可以给一个变量赋一个null值,下面通过代码演示null值的使用。; 数据类型检测;认识JavaScript的数据类型;认识JavaScript的数据类型; 数据类型转换;认识JavaScript的数据类型;认识JavaScript的数据类型;认识Jav

    Strongly-JS:原版 JavaScript 的强类型函数和变量

    带有运行时类型检查的 vanilla JavaScript 的强类型函数和变量。 类型 内置类型 简单的 简单类型是允许某些值的预定义过滤器。 NUMBER :此类型允许任何数字(包括NaN和Infinity )。 BIGINT :此类型允许任何 ...

    JavaScript数据类型之基本类型和引用类型的值

    ECMAScript变量包含两种不同数据类型的值:基本类型值和引用类型值。基本类型值是简单的数据段,而引用类型值指那些可能由多个值构成的对象。 在将一个值赋给变量时,解析器必须确定这个值是基本类型还是引用类型。...

    Javascript核心读书有感之类型、值和变量

    计算机程序的运行需要对值(value)比如数字3.14或者文本”hello world”进行操作,在编程语言中,能够表示并操作的值的类型叫做数据类型(type),编程语言最基本的特性就是主持多种数据类型。当程序需要将值保持起来以...

    Python全局变量-函数内部不允许修改局部变量的值

    Python还被语言流行指数的编译器Tiobe将它被评为最受欢迎的编程语言,20多年来首次将Python置于Java、C和JavaScript之上,真的非常荣幸了. 自从20世纪90年代初Python语言诞生至2022年,它已被逐渐广泛应用于系统...

    JavaScript 动态网页实例 - 数据类型转换.rar

    类型转换是网页编程不可或缺的内容,本文先介绍自动类型转换,接着是强制性的显式类型转换,最后如何...JavaScript 是一种松散类型、动态类型的语言,在声明变量时无需指定数据类型,使JavaScript 具有灵活性和简单性。

    JavaScript变量基本使用方法实例分析

    JavaScript 是一种弱类型语言,javascript的变量类型由它的值来决定。 定义变量需要用关键字 ‘var’ var iNum = 123; var sTr = 'asd'; //同时定义多个变量可以用,隔开,公用一个‘var'关键字 var iNum = 45,sTr='...

    Javascript变量函数浅析

    一、变量 在javascript变量中可以存放两种类型的值:原始值和引用值。 原始值存储在栈上的简单字段,也就是值直接存储在变量所标示的位置内。 引用值存储在堆内的对象,栈内变量保存的是指向堆内对象的指针值。 在...

    javascript 的变量、作用域和内存问题

    (一)JavaScript变量可以用来保存两种类型的值:基本类型值和引用类型值。基本类型的值源自以下5种基本数据类型:Undefined、Null、Boolean、Number和 String。基本类型值和引用类型值具有以下特点: 1.基本类型值...

    JavaScript基本数据类型及值类型和引用类型

    在JavaScript的基本类型中的数据可以是常量,也可以变量。由于JavaScript采用弱类型的形式,因而一个数据的变量或常量不必首先作声明,而是在使用或赋值时确定其数据的类型的。当然也可以先声明该数据的类型,它是...

Global site tag (gtag.js) - Google Analytics