美文网首页
由浅入深JavaScript——JavaScript秘密花园笔记

由浅入深JavaScript——JavaScript秘密花园笔记

作者: LeeYee11 | 来源:发表于2017-04-17 19:26 被阅读0次

    万物皆对象,除了undefined和null

    //除了undefined和null以外的所有值都是对象
    false.toString(); // 'false'
    [1, 2, 3].toString(); // '1,2,3'
    function Foo(){}
    Foo.bar = 1;
    Foo.bar; // 1
    

    数字对象使用时注意避免'.'被解析成浮点

    2..toString(); // 第二个点号可以正常解析
    2 .toString(); // 注意点号前面的空格
    (2).toString(); // 2先被计算
    

    对象的属性

    //属性名可以是变量名也可以是字符串字面值
    var foo = {name: 'kitten'}
    var foo = {'name': 'kitten'}
    
    //取值使可以用成员变量的方法取值也可以通过键名取值
    foo.name; // kitten
    foo['name']; // kitten
    
    //甚至可以传入一个键名的字符串来获取
    var get = 'name';
    foo[get]; // kitten
    
    //数字的字面值不能用成员变量的方法来取值,因为变量名不能为纯数字
    foo.1234; // SyntaxError
    foo['1234']; // works
    
    //在低版本的ES中,属性名与保留字相同时,只能使用字符串字面值的方法进行声明
    var foo={'delete':'0'};
    
    //删除属性仅能通过delete关键字
    delete foo.attribute;
    
    //如果对象包含一个数组,那么length只能获取到数组的长度
    //length作为属性,和name是同级别的,其他属性不会影响到length的值
    var foo=[1,2,3];
    foo.name='foo';
    foo.length; //3
    

    对象的原型

    function Foo() {
        this.value = 42;
    }
    Foo.prototype = {
        method: function() {}
    };
    
    function Bar() {}
    
    // 设置Bar的prototype属性为Foo的实例对象
    Bar.prototype = new Foo();
    Bar.prototype.foo = '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. */};
    

    上面的例子中,test 对象从 Bar.prototype 和 Foo.prototype 继承下来;因此, 它能访问 Foo 的原型方法 method。同时,它也能够访问那个定义在原型上的 Foo 实例属性 value。
    需要注意的是 new Bar() 不会创造出一个新的 Foo 实例,而是 重复使用它原型上的那个实例;因此,所有的 Bar 实例都会共享相同的 value 属性。
    使用for in遍历对象的属性时,将遍历原型链上所有的属性
    如果只遍历对象本身的属性,则需要使用hasOwnProperty进行过滤

    hasOwnProperty

    hasOwnProperty只查询对象本身是否含有某个属性而不查询对象的原型链
    唯一一个处理属性但是不查找原型链的方法

    This

    • 全局范围内this指向全局(浏览器内指window,下同)
    • 一般函数直接调用时,函数内的this指向全局
    • 对象的成员方法调用时,方法内的this指向对象本身
    • 在构造函数内部时,this指向新创建的对象
    • 当Function.prototype显示调用apply或call时,函数内的this被设置成第一个参数
    • 当对象的成员方法被赋值给一个变量后,用变量来调用方法,this指向全局

    闭包

    arguments

    • arguments是一个对象,但与数组极为相似(不能执行数组的pop,push,slice等方法)

    构造函数

    • 函数内this指向新创建的Object,新建对象的prototype指向构造函数的prototype。
    • 构造函数如果没有显式return,则隐式返回this对象。
    • 如果return的是字面值,则新建对象的构造函数还是原构造函数,如果return的是一个对象,那么新建对象的构造函数是return的对象的构造函数。
      function Bar(){
      return new Number(2);
      }
      console.log(new Bar().constructor===Number);//output: true

    工厂模式

    为了不使用new关键字,构造函数必须显式返回一个值
    function Bar(){
    var value=1;
    return {
    method: function(){
    return value;
    }
    }
    }
    Bar.prototype={
    foo:function(){}
    }
    var bar1=new Bar();
    var bar2=Bar();//调用返回值与上面一种相同
    console.log(bar1.proto===bar2.proto); //output: true
    返回一个带method方法的对象,实际上是创建了一个闭包* *

    工厂模式实例
      function Foo() {
          var obj = {};
          obj.value = 'blub';
    
          var private = 2;
          obj.someMethod = function(value) {
              this.value = value;
          }
    
          obj.getPrivate = function() {
              return private;
          }
          return obj;
      }
    

    工厂模式好处:

    • 避免通过new来调用函数
    • 充分利用私有变量
      工厂模式弊端:
    • 会占用更多内存,因为新建对象不能共享原型上的方法
    • 为实现继承,需要从另一个对象拷贝所有属性,或把一个对象作为原型

    作用域与命名空间

    JavaScript仅支持函数作用域
    声明变量时不加var会声明一个全局变量
    var foo=42;//全局变量
    function test(){
    foo=21;//全局变量
    }
    test();
    console.log(foo);//output:21

    JavaScript中局部变量只能通过两种方式生命,一种是作为函数参数,一种是通过var关键字声明

    变量声明提升
      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];
          }
      }
    

    JavaScript会自动把var和function声明提升到当前作用域顶部
    注意,仅提升声明,赋值语句不会被提升!!
    提升之后等价于如下代码:
    // 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();
    
    名称解析顺序

    当访问函数内的foo变量时,JavaScript会按以下顺序查找:

    1. 当前作用域内是否有var foo定义
    2. 函数形式参数是否有foo名称的
    3. 函数自身是否叫做foo
    4. 回溯到上一级作用域然后执行第1步
    命名空间

    命名冲突可以通过匿名包装器解决

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

    数组

    • for in语句可遍历原型链上的所有属性

    • for in的性能不如经典for语句

    • 建议用变量存储length属性而不是每次都去访问它

    • 如果数组的length被赋值为另外的其他数字,则数组会被截断
      *建议使用[]构造数组而非构造函数,理由如下
      [1, 2, 3]; // 结果: [1, 2, 3]
      new Array(1, 2, 3); // 结果: [1, 2, 3]

      [3]; // 结果: [3]
      new Array(3); // 结果: [] 
      new Array('3') // 结果: ['3']
      
      // 译者注:因此下面的代码将会使人很迷惑
      new Array(3, 4, 5); // 结果: [3, 4, 5] 
      new Array(3) // 结果: [],此数组长度为 3
      

    类型

    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
    严格等于操作符===
    • ===只能用来判断两个相同类型的值是否相等
    • 推荐显式转换类型再用===比较,而非用==直接比较
      #######比较对象
    • 只有同一个对象实例才会被认为是相等的

    typeof操作符

    Value Class Type
    "foo" String string
    new String("foo") String string
    1.2 Number object
    new Number(1.2) Number number
    true Boolean boolean
    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

    为了获取对象的 [[Class]],我们需要使用定义在 Object.prototype 上的方法toString。
    测试未定义变量
    typeof foo !== 'undefined'

    instanceof操作符

    用于比较两个操作数的构造函数,只有比较自定义对象时才有意义
    function Foo() {}
    function Bar() {}
    Bar.prototype = new Foo();

      new Bar() instanceof Bar; // true
      new Bar() instanceof Foo; // true
    
      // 如果仅仅设置 Bar.prototype 为函数 Foo 本身,而不是 Foo 构造函数的一个实例
      Bar.prototype = Foo;
      new Bar() instanceof Foo; // false
    

    类型转换

    // 下面的比较结果是: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';
    
    内置类型构造函数

    内置类型(比如 Number 和 String)的构造函数在被调用时,使用或者不使用 new 的结果完全不同。
    new Number(10) === 10; // False, 对象与数字的比较
    Number(10) === 10; // True, 数字与数字的比较
    new Number(10) + 0 === 10; // True, 由于隐式的类型转换

    • 转换为数字
      +'010' === 10
      Number('010') === 10
      parseInt('010', 10) === 10 // 用来转换为整数

      +'010.2' === 10.2
      Number('010.2') === 10.2
      parseInt('010.2', 10) === 10
      
    • 转换为布尔型
      通过使用 否 操作符两次,可以把一个值转换为布尔型。
      !!'foo'; // true
      !!''; // false
      !!'0'; // true
      !!'1'; // true
      !!'-1' // true
      !!{}; // true
      !!true; // true

    原文

    JavaScript秘密花园

    相关文章

      网友评论

          本文标题:由浅入深JavaScript——JavaScript秘密花园笔记

          本文链接:https://www.haomeiwen.com/subject/qdtxzttx.html