基本类型
-
Undefined
-
Null
-
Boolean
-
Number
-
String
引用类型
-
-
Array
-
Date
-
RegExp
-
Function
-
基本包装类型
-
Boolean
-
Number
-
String
-
-
单体内置对象
-
Global
-
Math
-
类型判断
-
typeof
-
instanceof
-
Object.prototype.toString.call()
差别
-
基本类型在内存中占据固定大小的空间, 因此保存在栈内存中
-
基本类型变量的赋值,复制的就是值得副本
-
引用类型的值是对象,保存在堆内存
-
包含引用类型值得变量实际上包含的不是对象的本身,二十一个指向对象的指针
-
引用类型进行赋值的时候, 复制的是引用指针, 两个变量指向同一对象
小结
-
类型检测方式
-
基础类型和引用类型复制, 以及存储方式
-
方法中 数据传递
JavaScript执行流程
预解析
-
全局预解析(变量和函数提前声明, 同名的函数比变量函数优先级高)
-
函数内部预解析(所有的变量,函数和形参都会参与预解析)
-
函数
-
形参
-
普通变量
-
执行
-
先解析全局作用域,然后执行全局作用域中的代码
-
在执行全局代码中遇到的函数, 遇到函数就进行函数的预解析,在执行函数内代码
JavaScript面向对象
封装, 继承, 多态
创建对象
简单方式
var person = new Object();
person.name = "Jack";
person.age = 18;
person.sayName = function(){
console.log(this.name);
}
var person = {
name: "jack",
age: 18,
sayName: function(){
console.log(this.name);
}
}
改进:工厂函数
function createPerson(name, age){
return {
name: name,
age: age,
sayName: function(){
console.log(this.name);
}
}
}
实例化对象
var p1 = createPerson("jack", 18);
var p2 = createPerson("luck", 20);
构造函数
function Person(name, age){
this.name = name;
this.age = age;
this.sayName = function(){
console.log(this.name);
}
}
// 实例化对象
var p = new Person("jack", 18);
p.sayName(); // jack
解析构造函数的执行
创建Person实例, 则必须使用 new
操作符
-
创建一个新对象
-
将构造函数的作用域赋值给新对象(this指的是这个新对象)
-
执行构造函数中的代码
-
返回新对象
构造函数和实例对象之间的关系
使用构造函数在于代码的简洁性,更重要的就是识别对象的具体类型。
在每一个实例对象中的_proto_
中同时有一个constructor
属性,该属性指向创建该实例的构造函数:
console.log(p1.constructor === Person);// true
console.log(p2.constructor === Person);//true
console.log(p1.constructor === p2.constructor); // true
对象的constructor
属性最初用来标识对象类型的, 但是检测类型还是使用instanceof
操作符可靠一点
console.log(p1 instanceof Person); // true
console.log(p2 instanceof Person); // true
总结
-
构造函数是根据具体的事物抽象出来的抽象模板
-
实例对象是根据抽象的构造函数模板得到的具体实例对象
-
每一个实例对象都具有一个
constructor
属性, 指向该实例的构造函数-
注意:
constructor
是实例的属性的说法不严谨
-
-
可以通过实例的
constructor
属性进行判断实例和构造函数之间的关系-
注意: 这种方法不严谨, 推荐使用
instanceof
。
-
构造函数的问题
使用构造函数方便创建对象, 但是有时候存在浪费内存
function Person(name, age) {
this.name = name;
this.age = age;
this.type = "human";
this.sayHello = function() {
console.log("hello" + this.name);
}
}
var p1 = new Person("jack", 18);
var p2 = new Person("luck", 18);
对于p1和p2两个对象而言,type
和sayHello
都是一模一样的内容,造成了内存浪费
console.log(p1.sayHello === p2.sayHello); // false
对于这种问题,将共享的函数定义到构造函数外部
sayHello = function() { console.log('hello'+this.name) }; function Person (name, age) { this.name = name; this.age = age; this.type = 'human'; this.sayHello = sayHello; } var p1 = new Person('lpz', 18); var p2 = new Person('Jack', 16); console.log(p1.sayHello === p2.sayHello) // => true
避免全局变量命名空间冲突问题, 进行改写
var fns = { sayHello: function() { console.log('hello'+this.name); }, sayAge: function() { console.log(this.age); }, }; function Person(name, age) { this.name = name; this.age = age; this.type = "human"; this.sayHello = fns.sayHello; this.sayAge = fns.sayAge; } var p1 = new Person("jack", 18); var p2 = new Person("luck", 18); console.log(p1.sayHello === p2.sayHello); // true console.log(p1.sayAge === p2.sayAge); //true