javascript深入浅出学习笔记

一.数据类型:
1.对象与对象是不相等的,比如:console.log(new Object() == new Object())//结果是false;console.log([1,2] == [1,2]);//结果是false;但是有一个例外的就是console.log(null === null)//结果是true
2.NaN和NaN是不同的,console.log(NaN == NaN)//结果是false
3.类型检测的几种方法:typeof、 instanceof、 Object.prototype.toString、 constructor、 duck type。
4.typeof返回某对象的原型,typeof obj //
5.instanceof用来判断一个对象是不是另外一个对象的实例,[1,2] instanceof Array(首字母是大写的)//结果是true
6.Object.prototype.toString常用的几个例子:

        Object.prototype.toString.apply([]); //=== “[object Array]”;
    Object.prototype.toString.apply(function(){}); //=== “[object Function]”;
    Object.prototype.toString.apply(null); //=== “[object Null]”;

    Object.prototype.toString.apply({}); //=== “[object object]”;

    Object.prototype.toString.apply(new Date()); //=== “[object Date]”;

    Object.prototype.toString.apply(undefined); //=== “[object Undefined]”;

7.javascrpt隐藏机制:当把一个基本类型以对象的形式去使用的时候,javascript会将其转换为包装类型对象(就是相当于new了一个对象),但是当操作完毕后这个临时包装对象就会被销毁
var a="string";
a.length;//6这里就会转换为包装类型对象,即相当于new String("string"),所以这里拥有length属性
a.t=3;
alert(a.t);//undefined,t已经被销毁了,所以是undefined
调用它属性时会临时创建对象,调用完后就销毁,创建它的t属性时,也会创建临时对象,但创建完t属性后就销毁了,然后你再调用t属性,又会创建临时对象,但此时t是木有的.
同样这种方法也是针对number(var nu = new Number(123)/new Number('123')对象,boolean对象的.

二.表达式和运算符:
1.删除对象的属性使用delete
var obj = {x:1};
obj.x;//1
delete obj.x;//true
obj.x//undefined
但是ie9之后就会使用defineProperty这样一个方法来控制删除
var obj = {};
Object.defineProrperty(obj,"x",{
configurable:false, //就是表示不能删除
value:1
});
delete obj.x;//false
obj.x; //1
2.void运算符返回的都是undefined,比如:void(0)//undefined void("123")//undefined


三.语句,严格模式
1.块语句:块语句常用于组合0~多个语句,块语句用一对花括号定义.(需要注意的一点是没有块级作用域)比如:
{语句1;语句2;...语句n},if(true){console.log(123)},for(var i=0;i<19;i++){...}等
因为没有块级作用域,所以for(var i=0;i<19;i++){...}等价于var i=0;for(;i<29;i++){...}所以我们可以看出for循环中变量i是全局变量
需要注意的一点是,区分函数作用域和块语句:

 函数作用域: function foo() {
    var a = 1;//这里a是局部变量,外部不可以访问
    console.log(a); // 1
    }
    foo();
    console.log(typeof a); // undefined

块语句:
var a = [];
for (var i = 0; i < 10; i++) { //这里i是全局变量
  a[i] = function () {
    console.log(i);
  };
}
a[6](); // 因为i是全局变量,所以这里值为全局的值10
2.try catch finally
1.1.1 try后面至少要有catch,finally中的一个,所以就有三种方式:
      try,catch;try,finally;try,catch,finally;
1.1.2 catch中的语句是在抛出异常之后才去执行的,当让catch中也可以抛出异常
1.1.3 如果有finally,那么不管有没有执行catch都会执行finally的
1.1.4 当try中发生异常时会跳到最近的catch语句中进行处理(这里就是涉及到嵌套)
下面来看几个例子:

try {
  try {
    throw new Error("oops");
    }
  finally {
    console.log("finally");
    }
 }
catch (ex) {
console.error("outer", ex.message);

}

执行路径:try(抛出异常) => finally(虽然抛出了异常,但是这里要先执行finally) => catch

所以这里的结果是:"finally" "outer" "oops"

try {
  try {
    throw new Error("oops");
    }
  catch (ex) {
    console.error("inner", ex.message);
    }
  finally {
    console.log("finally");
    }
 }
catch (ex) {//因为上面已经执行了catch来处理异常了,所以这里的catch是不会再执行了
console.error("outer", ex.message);
}

执行路径:try => catch(内部的) => finally 

执行的结果:"inner" "oops"  "finally"

try {
  try {
    throw new Error("oops");
  }
  catch (ex) {
    console.error("inner", ex.message);
    throw ex;//这里又抛出了异常,所以会执行最后面的那个catch
  }
  finally {
    console.log("finally");
  }
}
catch (ex) {
  console.error("outer", ex.message);
}

执行路径:try => catch(内部的) => finally => catch(外部的)
执行结果:"inner" "oops" "finally" "outer" "oops"

3.函数的声明function f(){...};函数的表达式var f = function f(){...};
函数声明可以被预先处理,也可以叫函数前置,比如:
f();//true
function f(){...}

fe();//TypeError
var fe = function(){...}
4.for in
特点:顺序不确定,enmuerable为false时不会出现,for in对象属性时是受原型链影响
5.switch语句:
1.1 default是当所有的case都不满足时去执行default语句
1.2 如果没有break语句,那么switch语句会从满足case的地方一直顺序执行到结束
6.严格模式
不允许未声明的变量被赋值;
不允许使用with;
arguments变为参数的静态副本,这里有几个重要的例子:(! function (){}(1) 表示该函数是一个函数表达式而不是函数声明,后面的(1)是将参数1传递进去,前面的!,你可以理解成它是将函数声明转化成函数表达式的一种方法。

!function (){}(1)也等同于(function (){})(1);,!也可换成+、-这样的一元运算符,都可以起到相同的作用。

函数也是一种对象,arguments是它的一个属性,函数的属性还包括name,length等等,arguments是参数对象的意思,不用写形参在函数上,也可以获取到函数上放进来的实参,利用arguments.length来获取参数个数,arguments[0],来获取第一个实参.)

!function(a){
arguments[0] = 100;
console.log(a);//这里的结果是undefined
}()//这里没有传入参数,所以输出的结果是undefined

!function(){
arguments[0] = 100;
console.log(a);
}(1);//这里虽然传入了参数,但是回报错,因为a没有定义

!function(a){
arguments[0] = 100;//非严格模式下,arguments是和传入的参数有帮定的,所以这里arguments[0]就是代表a
console.log(a);//这里结果是100
}(1);

'use strict';
!function(a){
arguments[0] = 100;
console.log(a);//这里结果是1,因为严格模式下,arguments成为了静态副本,不再和a有绑定
}(1);

'use strict';
!function(a){
arguments[0].x = 100;
console.log(a.x);//这里输出来的是100,因为在严格模式下,如果传入的参数是对象的话,修改arguments属性是会对传入参数属性会影响的
}(x:1);
7.delete参数,函数名报错
!function(a){
'use strict';
delete a;//这里会报错,如果是非严格模式下,结果为false
}(1);
8.delete不可配置的属性报错
!function(a){
'use strict';
var obj = {};
Object.definePrperty(obj,"a",{configurable:false});
delete obj.a;//这里会报错TypeError
}(1);
9.对象字面量重复属性名报错.
10.禁止八进制字面量.
11.eval, arguments变为关键字,不能作为变量、函数名
三、对象
1、对象包含一系列的属性,这些属性是无序的,每个属性都有一个字符串key和相对应的value。
2、对象中访问属性的顺序:某一实例对象obj => foo.prototype => Object.prototype => null,所以下面的typeof obj.toString 返回的是'function',
当访问对象属性时,会一直按上面的方式往上面查找,如果一直没有找到,就返回undefined

3、如果是赋值的话就不会像上面一样往上面查找,只会在本对象上查找,如果没有找到就创建一个,所以不会改变原型链上的值,同样delete可以用来删除属性,但是它只会删除本对象上的属性,不会修改掉原型链上的属性。


4、可以使用Object.create({x:1})来创建一个对象的属性,var obj = Object.create({x:1});这句话的意思就是在原型{x:1}中创建一个对象obj,所以obj的原型是{x:1}。如果使用成这样,那么这个属性是属于(原型是)null上的,所以没有任何方法。

5、for in 循环中因为使用的是in,所以这个循环可能会把原型链上的属性都遍历出来了,但是如果是原型链上的花只能是原型链上可以枚举的属性(一般来说原型链上的属性是不可枚举的),就是说遍历原型链上enumerable为true的属性,如果是false的,for in仍然是遍历不出来的。

var o = {x : 1, y : 2, z : 3};

'toString' in o; // true

o.propertyIsEnumerable('toString');// false 我们可以使用这个方法来查看某个属性是否是可枚举的

var key;

for (key in o) { console.log(key); // x, y, z  这里就只会for in出可以枚举的属性

}

一般使用Object.create来创建的属性是可以枚举的。比如:

var obj = Object.create(o); obj.a = 4; var key; for (key in obj) { console.log(key); // a, x, y, z }

所以我们可以使用下面的方法来for in只属于本对象的属性。

var obj = Object.create(o); obj.a = 4; var key; for (key in obj) { if (obj.hasOwnProperty(key)) { console.log(key); // a } }


6、对于delete,可以用来删除对象上的一些属性,但是并非所有的属性,比如:
1.1、delete Object.prototype;就会报错,表示不可以删除这个属性,我们可以使用var descriptor = Object.getOwnPropertyDescriptor(Object,"prototype");descriptor.configurable;//false 的方式来查看原型上的某个属性标签为true还是false来判断该属性是否是可枚举的(这里是查看Object.prototype),结果为false,所以不可以枚举。
1.2、全局变量用var 来声明的变量不可以delete删除,但是隐式的创建变量,然后使用window的变量是可以删除的,比如:a = 1;window.a//1 delete a //true.同样声明的函数不可以删除。
7.对象的属性标签:writable,enumerable,configurable,get/set,value等。
8.
2)属性操作
对象里的属性有如下特性:
数据属性:
configurable:设置属性是否能被删除,属性的特性是否能被设置,能否修改属性的值等;
enumerable:设置属性是否可枚举
writable:设置属性的值能否被修改
value:设置属性的值
在添加一个对象的属性时默认上面的特性都为true,而value则是属性的值,如果想通过自定义这些特性来设置对象属性,可以通过Object.defineProperty,如下:
var person = {name:"张三"};
Object.defineProperty(person,name,{configurable:true,enumerable:true,writable:true,value:"李四”});
在上面所设置的特性当中,configurable如果为false表示属性特性设置在之后不能被改动(除了writable,writable在configurable为false时仍然可以设置成false),而且configurable一旦为false后就不能再设置成true了,
而enumberable如果为false则表示该属性不可枚举,用for in循环输出对象属性时该属性不会被输出;
writable很明显,为false时则表示不可修改该属性的值(不过当configurable为true时可以通过修改value的值直接改写或者将writable修改为true)
Object.defineProperty(person,name,{configurable:false});   
delete person.name;    //delete操作不成功
Object.defineProperty(person,name,{enumerable:false});  //操作不成功
...
访问器属性
configurable:设置属性是否能被删除,属性的特性是否能被设置,能否修改属性的值等;
enumerable:设置属性是否可枚举
get / set :在读写属性时会自动调用的函数
比如:
var book = {
   _year:2004,
   edition:1
};
Object.defineProperty(book,"year",{
   get:function(){
        return this._year;
   },
   set:function(newValue){
       this._year = newValue;
       this.edition += newValue - 2004;
   }
});
 
book.year = 2005; //当要设置year属性时,会自动调用set方法
alert(book.edition);
 
如果要的不止是配置单单一个属性,而是要同时配置多个,可以通过Object.defineProperties,如下:
var person = {name:"张三"};
Object.defineProperty(person,{
      name:{value:"李四”,configurable:false},
      sex:{value:"man",writable:false}
});
在配置完属性后或者通过Object.defineProperty更改过属性后想读者该属性,可以通过Object.getOwnPropertyDescriptor读取
Object.getOwnPropertyDescriptor(book,"edition");        //读取book对象中的edition属性
 
 
3)对象标签
[[proto]]:
对象中有个属性[[proto]]指向它的构造器的原型
 
[[class]]:
看不懂视频里在讲啥- -,没说为啥是通过Object.prototype.toString去获取[[class]]的,所以还是不懂[[class]]的含义
 
[[extensible]]:
var obj = {x:1,y:2};
Object.isExtensible(obj);   //检测对象是否可扩展,一般来说默认都是true
Object.preventExtensions(obj);  //禁止对象可扩展
Object.defineProperty(obj,"x",{value:2});   //虽然禁止了对象扩展,但是删除或者修改属性的值以及标签
Object.seal(obj);   //禁止对象属性被删除以及配置属性标签
Object.isSealed(obj);   //判断对象是否被seal
 
Object.freeze(obj); //冻结对象,禁止对象属性值被改写
Object.isFrozen(obj);   //判断对象是否被freeze
 
4)序列化
在向后台发送请求数据时,用JSON.stringify将对象转化为字符串,用JSON.parse将字符串解析为对象
但是,在用JSON.stringify将对象转化为字符串时如果对象属性的值为undefined,那么它将不会出现在转化后的字符串里
如果我们想自定义序列化,可以在对象里自定义toJSON方法,同理,我们在将对象toString或者valueOf时也可以自定义toString方法和valueOf方法
 
对象转化为基本类型的过程:
在后台首先会自动调用valueOf方法尝试将对象转化为基本类型,如果valueOf不存在或者无法转化为基本类型则会调用toString方法继续尝试,如果两种都无法将对象转化为基本类型则会报错
 总结来看:继承的几种方法:
function Person(){}
funciton Student(){}
Student.prototpe.constructor = Student;
1.Student.prototype = new Person();//传参可能有问题
2.Student.prototype = Person.prototype;//这种方法的缺点就是父类和子类的原型都指向了同一个对象,如果改变一个会导致两个都受影响
3.Student.prototype = Object.create(Person.prototype);//注意这种方法是要在ES5之后才能用,但是时最实用的,所以我们引出了第四种
4.if(!Object.create){
Object.create = function(proto){
function F(){}
F.prototype = proto;//proto是原型对象
retrun new F;
};
}
原文地址:https://www.cnblogs.com/fireporsche/p/6560270.html