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

2017-04-17  本文已影响0人  LeeYee11

万物皆对象,除了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

闭包

arguments

构造函数

工厂模式

为了不使用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;
  }

工厂模式好处:

作用域与命名空间

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(){
           //对外公开的 函数,创建了闭包
       }
   })();//立即执行

数组

类型

JavaScript是弱类型语言

等于操作符==
严格等于操作符===

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, 由于隐式的类型转换

原文

JavaScript秘密花园

上一篇下一篇

猜你喜欢

热点阅读