1.原始类型和引用类型
- JavaScript没有类,但是有类型。分为原始类型和引用类型。
5个原始类型:字符串,数字,布尔,空类型,未定义。
除了空类型,都可以用typeof来鉴别。空类型必须直接和null进行比较才能鉴别 - 引用类型使JavaScript最接近类的东西,而对象则是引用类型的实例。可以用new操作符或字面形式创建新对象。可以用点号或者中括号访问属性和方法。
- JavaScript提供3种原始封装类型 String、Number、Boolean
2.函数
- JavaScript中函数和其他对象最大的区别在于函数有一个特殊的内部属性[[call]],包含了函数的执行命令。typeof操作符会在对象内查找这个内部属性,如果找到,它返回"function"
- 操作函数的this的三种方法
call()
方法,第一个参数指定函数执行时的this值,其后参数是需要被传入函数的参数。
例如
function sayNameForAll(label){
console.log(label+":"+this.name);
}
var person1={
name:"Nicholas"
};
var person2={
name:"Greg"
};
var name = "Happy";
sayNameForAll.call(this,"global"); //输出 global:Happy
sayNameForAll.call(person1,"person1");//输出 person1:Nicholas
sayNameForAll.call(person2,"person2");//输出 person2:Greg
apply()
方法
和call()区别在于第二个参数可以是一个数组,包含了函数的多个参数。函数可以用arguments数组对象来获得参数。
例如这样调用
sayNameForAll.apply(person1,["person1"]);
bind()
方法(ES5新加)
参数和call类似,但是所有的参数会永久设置在新函数。
如
var sayNameForPerson1 = sayNameForAll.bind(person1);
sayNameForPerson1("person1");//输出 person1:Nicholas
3.理解对象
- 可以用点号或者中括号访问对象的属性。可以随时用赋值的方法添加新属性,也可以使用delete操作符删除一个属性。
- 如果是自有属性,可以用hasOwnProperty()判断,这个方法存在于所有的对象中。所有对象的属性默认是可枚举的,即他们会出现在for-in循环中或者被Object.keys()获取。
- 属性有
数据属性
和访问器属性
。数据属性保存值,可以读写他们,当数据属性保存了一个函数的值的时候,这个属性被认为是对象的一个方法。访问器属性不保留值,通过getter和setter来进行指定操作。
定义访问器属性例如
var person ={
_name:"Happy",
get name(){
//your process
return this._name;
},
set name(value){
//your process
this._name=value;
}
};
- 数据属性和访问器属性都具有[[Enumerable]]和[[Configurable]]特征。
- 数据属性还具有[[Writable]]和[[Value]]特征,而访问器属性则具有[[Get]]和[[Set]]特征。
- [[Enumerable]]和[[Configurable]]默认为true,可以通过Object.defineProperty()或Object.defineProperties()改变这样特征,用Object.getOwnPropertyDescriptor()获取它们。
- 静止拓展:Object.preventExtensions(person1)使一个对象禁止拓展
用Object.isExtensible() - 对象封印Object.seal(),用Object.isSealed()判断一个对象是否被封印。
- 对象冻结Object.isFrozen()和Object.isFrozen()
4.构造函数和原型对象
- 可以随时定义自己的构造函数来创建多个具有相同属性的对象。可以用instanceof 操作符或者直接访问constructor属性来鉴别对象是由哪个构造函数创建的。
- 每一个函数都有prototype属性,它定义了该构造函数创建的所有对象共享的属性。
- 原型对象被保存在对象实例内部的[[Prototype]]属性中。这个属性是一个引用而不是一个副本。当你试图访问一个对象的某个属性的时候,JavaScript首先在自有属性中查找这个名字,如若没有找到,再查找原型属性。
5.继承
- Object.prototype方法
hasOwnProperty
propertyIsEnumerable
isPrototypeOf
valueOf
toString
- 对象继承
对象字面形式会隐式指定Object.prototype为其[[Prototype]],也可以使用Object.create()方式显式指定。
Object.create()方法接受两个参数,第一个为需要被设置为新对对象的[[Prototype]]的对象,第二个可选参数是一个属性描述对象,其格式如Object.defineProperties()中使用的一样。
例如
var book={title:"The Principles"};
等价于
var book = Object.create(Object.prototype,{
title:{
configurable:true,
enumerable:true,
value:"The Principles",
writable:true
}
});
- 为了正确继承自有属性,可以使用构造函数窃取。只需以call()或者apply()调用父类的构造函数,就可以在子类里完成各种初始化。结合构造函数窃取和原型对象链是JavaScript中最常见的继承手段。由于和基于类的继承相似,这个组合经常被称为
伪类继承
- 可以通过直接访问父类原型对象的方式访问父类的方法,需要以call()或者apply()执行父类方法并传入一个子类的对象。
6.对象模式
- 私有成员和特权成员
-模块模式的实现
使用立调函数表达IIFE
来返回一个对象。(被定义后立即调用并产生结果的函数表达式)
var person = (function(){
var age=25; //private data variables 外部无法访问
return{ //public methods and properties
name:"Happy",
getAge:function(){
return age;
},
growOlder:function(){
age++;
}
};
}());
- 混入
- 作用域安全的构造函数
function Person(name){
this.name = name;
}
Person.prototype.sayName = function(){
//process
};
var person1 = Person("Happy"); //note: missing "new"
console.log(person1 instanceof Person); //false
console.log(typeof person1); //"udefined"
console.log(name); // "Happy"
这里由于Person的构造函数不是用new操作符调用的,于是创建了一个全局变量name.首字母大写的构造函数通常在提醒你记得在前面加上new操作符。但是很多内建构造函数例如Array,Object,Error和RegExp不需要new也可以工作,这是因为它们被设计为作用域安全的构造函数,一个作用域安全的构造函数有没有new都可以正常工作。
模板例如
function Person(name){
if (this instanceof Person){
//call with "new"
}else {
//call without "new"
}
}
例如一个作用域安全的Person版本如下
function Person(name){
if (this instanceof Person){
this.name=name;
}else {
return new Person(name);
}
}