一、原始类型和引用类型
1.1 对象的两种类型:
JavaScript使用一个变量对象追踪变量的生存期。
原始类型保存为简单的值,
引用类型则保存为对象,其本质是指向内存位置的引用。
1.2 原始类型
1..2.1 五种原始类型:
Boolean
Number
String
Null
Undefined
1.2.2 鉴别原始类型
使用typeof 操作符
console.log(typeof 10); //"number"
console.log(typeof “123”); //“string”
console.log(typeof true); //"boolean"
console.log(typeof undefined); //"undefined"
//null为特例,可通过和null值进行比较判断
console.log(typeof null); //"object"
console.log(value===null); //true or false
1.3 引用类型:
1.3.1创建对象(实例化对象)
使用new操作符
var object = new Object();
该代码实例化了一个通用对象,并将它的引用保存在object中。object变量实际上并不保存对象的实例,而是一个指向内存中实际对象所在位置的指针(或者说引用)。
1.3.2 引用对象解除
解除引用的最佳手段是将对象变量置为null。在不使用对象时将其引用解除,会让垃圾收集器对那块内存进行释放。
var object1 = new Object();
//doing something
object = null;
1.3.3 六种内建类型:
Object
Array
Function
Date
RegExp
Error
内建类型实例化
使用new操作符来实例化每一个内建引用类型:
var object = new Object();
var items = new Array();
var func = new Function("console.log('hi');"); //称为构造函数
var now = new Date();
var re = new RegExp("\\d+");
var error = new Error("something bad happened.");
字面形式,字面形式允许不使用new操作符和构造函数显示创建对象的情况下生成引用值。
//对象字面形式
var person = {
name:"liang",
sayName:function(){
return this.name;
}
};
person.year = 1992; //添加对象的属性
var items = ["item1","item2","item3"];
//函数字面形式,函数声明
function func(value){
return value;
}
//函数字面形式,函数表达式(匿名函数)
var func = function(){
statement;
};
//正则表达式字面形式
var numbers = /\d+/g;
1.3.4 访问属性
var array = [];
array.push(123); //使用点号
array["push"](456); //使用中括号
//中括号允许使用动态访问方法
var method = "push";
array[method](789);
点号更易读,但使用中括号可允许你在属性名字上使用特殊字符。
1.3.5 鉴别引用类型
对于函数,typeof 操作符返回“function”;
其他非函数的引用类型,typeof 操作符都返回“object”。因此,使用instanceof 操作符来区分其他引用类型。
instanceof 操作符以一个对象和一个构造函数为参数。如果对象是构造函数所指定的类型的一个实例,instanceof 返回true;否则返回false。
var items = [];
var object = {};
function reflect(){
return value;
}
console.log(typeof reflect); //"function"
console.log(items instanceof Array); //true
console.log(object instanceof Object); //true
console.log(reflect instanceof Function); //true
//这些引用类型也都是Object的实例,instanceof 操作符可鉴别继承类型。
console.log(items instanceof Object); //true
console.log(reflect instanceof Object); //true
1.3.6 鉴别数组
instanceof 可以鉴别数组,但有一个例外,当你把一个数组从一个框架传到另一个框架时,instanceof 就无法识别,因为这个数组是来自不同框架的Array的实例。
使用Array.isArray()鉴别数组,IE8及更早版本不支持。
var items = [];
console.log(Aray.isArray(items)); //true
1.4 原始封装类型
原始封装类型共有3种(String, Number 和 Boolean)。
当读取字符串、数字或布尔值时,原始封装类型将被自动创建。这种特殊引用类型的存在使得原始类型用起来和对象一样方便。
//第二行代码把name当成一个对象,调用了charAt方法
var name = "liang";
var firstChar = name.charAt(0);
console.log(firstChar); //"l"
/*
背后的工作原理:创建了一个临时对象,随后被销毁
var name = "liang";
var temp = new String(name);
var firstChar = temp.charAt(0);
temp = null;
console.log(firstChar); //"l"
*/
//临时对象仅在值被读取时创建,instanceof并没有真的读取任何东西,因此为false
console.log(typeof name); //string
console.log(name instanceof String); //false
二、函数
函数其实就是对象。使函数不同于其他对象的决定性特点是函数存在一个被称为[[call]]的内部属性。
内部属性无法通过代码访问,它定义了代码执行时的行为。
[[call]]是函数独有的,表明该对象可以被执行。
2.1 声明还是表达式
函数有两种字面形式。第一种以function关键字开头,后面跟着函数的名字。第二种是函数表达式,function后面不需要跟着函数名,这种函数被称为匿名函数。
//函数声明
function add(num1,num2){
return num1 + num2;
}
//函数表达式
var push = function(num1,num2){
return num1 + num2;
};
两者中最重要的区别是,函数声明会被提升至上下文的顶部。意味着可以先使用函数,后声明。
而函数表达式是通过变量引用,因此无法提升。
var sum = add(3,5);
function add(num1,num2){
return num1 + num2;
}
2.2 函数就是值
记住函数就是对象,可以将函数当成参数传递给其他的函数。
比如数组的sort()方法,接受一个比较函数作为可选参数。
在默认情况下,sort()将数组中每个对象转换成字符串然后进行比较。
var numbers = [1,6,3,7,2,10];
numbers.sort(function(num1,num2){
return num1 - num2;
});
console.log(numbers); //[1, 2, 3, 6, 7, 10]
numbers.sort();
console.log(numbers); //[1, 10, 2, 3, 6, 7]
2.3 参数
函数参数实际上被保存在一个被称为arguments类似于数组的对象中。
var reflect = function(){
return arguments[1];
};
console.log(reflect("first","second")); //second
console.log(reflect.length); //"0"
应尽量避免使用argument。不过,在某些情况下使用arguments比名称参数有效。例如,创建一个函数,可以接受任意数量的参数,并返回它们的和。
function sum(){
var i = 0,
result = 0,
len = arguments.length;
while (i < len){
result += arguments[i];
i++;
}
return result;
}
console.log(sum(3,5,1)); //9
console.log(sum(1,2,3,4)); //10
console.log(sum()); //0
//由于result的初始值为0,改函数就算没有参数也能正常工作
2.4 重载
大多数面向对象语言支持函数重载,它能让一个函数具有多个签名。
函数签名由函数的名字、参数的个数及其类型组成。
JavaScript并没有签名,但可以模仿函数重载。用arguments对象获取传入的参数个数并决定怎么处理。
function sayMessage(message){
if (arguments.length === 0){
message = "Default message";
}
console.log(message);
}
sayMessage("Hello"); //Hello
sayMessage(); //Default message
2.5 对象方法
对象的属性的值是函数,则该属性被称为方法。
2.5.1 this对象
JavaScript所有函数作用域内都有一个this对象代表调用该函数的对象。在全局作用域中,代表全局对象。
function sayNameForAll(){
console.log(this.name);
}
var person1 = {
name: "liang",
sayName: sayNameForAll
};
var person2= {
name: "zhu",
sayName: sayNameForAll
};
person1.sayName(); //liang
person2.sayName(); //zhu
person2.sayName(); //zhu
2.5.2 改变this
call() 方法
call() 的第一个参数指定了函数执行时this的值,其后的所有参数(可选)都是需要被传入函数的参数。
function sayNameForAll(){
console.log(this.name);
}
function sayName(a){
console.log(a + ": "+this.name);
}
var person1= {
name: "liang"
};
var person2= {
name: "zhu"
}
sayNameForAll.call(person1); //liang
sayName.call(person1,"name"); //name: liang
apply() 方法
apply() 方法的工作方式和call()完全一样,但它只接受两个参数:this的值、一个数组(或者类似数组的对象,内含需要被传入函数的参数)。
function sayNameForAll(a){
console.log(a + ": " + this.name);
}
var person1 = {
name: "liang"
};
var person2 = {
name: "zhu"
};
sayNameForAll.apply(person1,["person"]); //person: liang
var array = [1,2,3,4];
sayNameForAll.apply(person2,array); //1: zhu
sayNameForAll.apply(person2,array[2]); //
error
bind() 方法
bind() 的第一个参数是要传给新函数的this的值。其他所有参数代表需要被永久设置在新函数中的命名参数。可以在之后继续设置任何非永久参数。
function sayName(a){
console.log(a + ": " + this.name);
}
var person1 = {
name: "liang"
};
var person2= {
name: "zhu"
};
//绑定this,并传入参数
var sayPerson1 = sayName.bind(person1,"person");
sayPerson1(); //person: liang
//仅绑定this
var sayPerson2 = sayName.bind(person2);
sayPerson2(); //undefined: zhu
sayPerson2("person"); //person: zhu