Skip to content

javascript学习笔记

ZefengYu edited this page Jan 8, 2016 · 4 revisions

@(javascript)[javascript][学习笔记]

javascript学习笔记

!!

undefined and null is not equral to false, so it have to use ! to force undefined and null to a boolean type false. And it can use the second ! to get the reverse boolean type value.

//input
var obj = {
    bar: 1,
    foo: 2,
    baz: 3
};
obj.bar = !!undefined;
obj.foo = !!null;
delete obj.baz;
console.log('--------');
for(var i in obj) {
    if (obj.hasOwnProperty(i)) {
        console.log(i, '' + obj[i]);
    }
}
//output
"--------"
"bar"
"false"
"foo"
"false"

prototpye原型继承

function Foo(){
  this.value = 42;
}
Foo.prototype = {
  method: function(){}
};
function Bar(){}
//设置Bar的prototype属性为Foo的实例对象
Bar.prototype = new Foo();
Bar.prototype = 'hello world';
//修正Bar.prototype.constructor为Bar本身
Bar.prototype.constructor = Bar;
var test = new Bar();// 创建Bar的一个新实例
// 原型链
test [Bar的实例]
    Bar.prototype [Foo的实例] 
        { foo: 'Hello World' }
        Foo.prototype
            {method: ...};
            Object.prototype
                {toString: ... /* etc. */};

each map

  • each返回的是原来的数组,并不会新创建一个数组。
  • map方法会返回一个新的数组。如果在没有必要的情况下使用map,则有可能造成内存浪费。

解析(hoisted) 赋值

  • 代码运行前:解析(hoisted)
foo(); // 正常运行,因为foo在代码运行前已经被创建
function foo() {}
var bar;
  • 代码运行时:赋值
foo = function() {};
//---------------
baz; // 'undefined'
baz(); // 出错:TypeError
var baz = function() {};

全局对象

全局对象 浏览器环境中就是window对象。

this

晚绑定特性

function Foo() {}
Foo.prototype.method = function() {};
 
function Bar() {}
Bar.prototype = Foo.prototype;
 
new Bar().method();

method 被调用时,this 将会指向 Bar 的实例对象。

闭包和引用

闭包是 JavaScript 一个非常重要的特性,这意味着当前作用域总是能够访问外部作用域中的变量。 因为 函数 是 JavaScript 中唯一拥有自身作用域的结构,因此闭包的创建依赖于函数

function Counter(start){
  var count = start;
  return {
    increment:function(){
      count++;
    },
    get:function(){
      return count;
    }
  }
}

var foo = Counter(4);
foo.increment();
foo.get();
console.log(foo.get());

循环中的闭包

匿名函数

for(var i = 0; i < 10; i++){
    setTimeout(function(){
      console.log(i);
    },1000);
}

console.log 被调用的时候,匿名函数保持对外部变量 i的引用,此时 for循环已经结束, i的值被修改成了 10.

匿名包裹器

for(var i = 0; i < 10; i++){
  (function(e){
    setTimeout(function(){
      console.log(e);
    },1000);
  })(i);
}

外部的匿名函数会立即执行,并把 i 作为它的参数,此时函数内 e 变量就拥有了i的一个拷贝。 当传递给 setTimeout的匿名函数执行时,它就拥有了对 e 的引用,而这个值是不会被循环改变的。

== and ===

  1. 对于string,number等基础类型,=====是有区别的
  • 不同类型间比较,==之比较“转化成同一类型后的值”看“值”是否相等,===如果类型不同,其结果就是不等
  • 同类型比较,直接进行“值”比较,两者结果一样
  1. 对于Array,Object等高级类型,=====是没有区别的 进行“指针地址”比较
  2. 基础类型与高级类型,=====是有区别的
  • 对于==,将高级转化为基础类型,进行“值”比较
  • 因为类型不同,===结果为false

作用域与命名空间

  • 尽管 JavaScript 支持一对花括号创建的代码段,但是并不支持块级作用域; 而仅仅支持函数作用域。
  • JavaScript 中没有显式的命名空间定义,这就意味着所有对象都定义在一个全局共享的命名空间下面。 全局变量
// 脚本 A
foo = '42';//隐式的全局变量
// 脚本 B
var foo = '42'
// 全局作用域
var foo = 42;
function test() {
   // 局部作用域
   foo = 21;
}
test();//foo = 21
  • 局部变量 JavaScript 中局部变量只可能通过两种方式声明,一个是作为函数参数,另一个是通过 var 关键字声明。

变量声明提升(Hoisting)[解析]

bar();
var bar = function() {};
var someValue = 42;
 
test();
function test(data) {
    if (false) {
        goo = 1;
 
    } else {
        var goo = 2;
    }
    for(var i = 0; i < 100; i++) {
        var e = data[i];
    }
}
// var 表达式被移动到这里
var bar, someValue; // 缺省值是 'undefined'
 
// 函数声明也会提升
function test(data) {
    var goo, i, e; // 没有块级作用域,这些变量被移动到函数顶部
    if (false) {
        goo = 1;
 
    } else {
        goo = 2;
    }
    for(i = 0; i < 100; i++) {
        e = data[i];
    }
}
 
bar(); // 出错:TypeError,因为 bar 依然是 'undefined'
someValue = 42; // 赋值语句不会被提升规则(hoisting)影响
bar = function() {};
 
test();
// 译者注:来自 Nettuts+ 的一段代码,生动的阐述了 JavaScript 中变量声明提升规则
var myvar = 'my value';  
 
(function() {  
    alert(myvar); // undefined  
    var myvar = 'local value';  
})();  

名称解析顺序 比如,当访问函数内的 foo 变量时,JavaScript 会按照下面顺序查找:

  • 当前作用域内是否有 var foo 的定义。
  • 函数形式参数是否有使用 foo 名称的。
  • 函数自身是否叫做 foo。
  • 回溯到上一级作用域,然后从 #1 重新开始。

命名空间 只有一个全局作用域导致的常见错误是命名冲突。在 JavaScript中,这可以通过 匿名包装器 轻松解决。

(function() {
    // 函数创建一个命名空间
 
    window.foo = function() {
        // 对外公开的函数,创建了闭包
    };
 
})(); // 立即执行此匿名函数

// 另外两种方式
+function(){}();
(function(){}());

相等和比较

等于操作符

等于操作符由两个等号组成:==

JavaScript 是弱类型语言,这就意味着,等于操作符会为了比较两个值而进行强制类型转换。

""           ==   "0"           // false
0            ==   ""            // true
0            ==   "0"           // true
false        ==   "false"       // false
false        ==   "0"           // true
false        ==   undefined     // false
false        ==   null          // false
null         ==   undefined     // true
" \t\r\n"    ==   0             // true

严格等于操作符

严格等于操作符由三个等号组成:===

不像普通的等于操作符,严格等于操作符不会进行强制类型转换。

""           ===   "0"           // false
0            ===   ""            // false
0            ===   "0"           // false
false        ===   "false"       // false
false        ===   "0"           // false
false        ===   undefined     // false
false        ===   null          // false
null         ===   undefined     // false
" \t\r\n"    ===   0             // false

比较对象

虽然 == 和 === 操作符都是等于操作符,但是当其中有一个操作数为对象时,行为就不同了。

{} === {};                   // false
new String('foo') === 'foo'; // false
new Number(10) === 10;       // false
var foo = {};
foo === foo;                 // true

typeof 操作符

typeof 只有一个实际的应用(译者注:这个实际应用是用来检测一个对象是否已经定义或者是否已经赋值)

Value               Class      Type
-------------------------------------
"foo"               String     string
new String("foo")   String     object
1.2                 Number     number
new Number(1.2)     Number     object
true                Boolean    boolean
new Boolean(true)   Boolean    object
new Date()          Date       object
new Error()         Error      object
[1,2,3]             Array      object
new Array(1, 2, 3)  Array      object
new Function("")    Function   function
/abc/g              RegExp     object (function in Nitro/V8)
new RegExp("meow")  RegExp     object (function in Nitro/V8)
{}                  Object     object
new Object()        Object     object

为了检测一个对象的类型,强烈推荐使用 Object.prototype.toString 方法; 因为这是唯一一个可依赖的方式。正如上面表格所示,typeof 的一些返回值在标准文档中并未定义, 因此不同的引擎实现可能不同。

除非为了检测一个变量是否已经定义,我们应尽量避免使用 typeof 操作符。

Object.prototype.toString.call([])  // "[object Array]"
Object.prototype.toString.call({})  // "[object Object]"
Object.prototype.toString.call(2)   // "[object Number]"

instanceof 操作符

instanceof 操作符用来比较两个操作数的构造函数。只有在比较自定义的对象时才有意义。 如果用来比较内置类型,将会和 typeof 操作符 一样用处不大。

类型转换

// 下面的比较结果是:true
new Number(10) == 10; // Number.toString() 返回的字符串被再次转换为数字
 
10 == '10';           // 字符串被转换为数字
10 == '+10 ';         // 同上
10 == '010';          // 同上 
isNaN(null) == false; // null 被转换为数字 0
                      // 0 当然不是一个 NaN(译者注:否定之否定)
 
// 下面的比较结果是:false
10 == 010;
10 == '-10';


new Number(10) === 10;     // False, 对象与数字的比较
Number(10) === 10;         // True, 数字与数字的比较
new Number(10) + 0 === 10; // True, 由于隐式的类型转换

'' + 10 === '10'; // true,转换为字符串
+'10' === 10; // true,转换为数字
!!'foo';   // true,转换为布尔型
!!'';      // false
!!'0';     // true
!!'1';     // true
!!'-1'     // true
!!{};      // true
!!true;    // true

核心