一、数据类型
1、分类:
1)基本(值)类型String:任意字符串Number:任意数值boolean:true / falseundefined:undefinednull:null2)对象(引用)类型Object:任意对象Array:特别的对象(内部数据有序/ 数据下标)Function:特别的对象(可以执行)2、判断:
1)typeof:判断变量的类型* 可以判断 undefined / 数值 / 字符串 / 布尔值 / function* 不可以判断 null 与 object 、 object 与 arrayvar b1 = { b2: [1,'abc',console.log], b3: function(){ console.log('b3'); return function(){ return 'xfzhang'; } } } console.log(typeof b1.b2) // 'object'
2)instanceof:判断对象的具体类型(返回数据类型的字符串表达)true / falseconsole.log(b1 instanceof Object, b1 instanceof Array);
3)=== (不可以是== 因为==会自动进行类型转换) true / false* undefined 、null3、相关问题:
1) 实例:实例对象类型:类型对象function Person(name,age){ // 构造函数 类型 this.name = name; this.age = age; } var p = new Person(); // 根据类型创建的实例对象
2)undefined 与 null 的区别?* undefined 代表定义了未赋值* null 定义并赋值了,只是值为nullvar a; console.log(a); // undefined a = null; cosnole.log(a); // null 3)什么时候给变量赋值为null? * 初始赋值,表明将要赋值为对象 * 结束前,让对象成为垃圾对象(被垃圾回收器回收) // 起始 var b = null; // 初始赋值为null,表明将要赋值为对象 // 确定对象就赋值 b = ['abc', 12]; // 最后 b = null; // 将b指向的对象成为垃圾对象(被垃圾回收器回收)
4)严格区别变量类型与数据类型?① 数据的类型* 基本类型* 对象类型② 变量的类型(变量内存值的类型)* 基本类型:保存的就是基本类型的数据* 引用类型:保存的是地址值二、数据、变量、内存
1、什么是数据?
① 存储在内存中代表特定信息的东西(本质是二进制0101)② 数据的特点:* 可传递
* 可运算var a = 3; var b = a; var a = 3; var b = a + 2;
③ 一切皆数据④ 内存中所有操作的目标:数据* 算数运算* 逻辑运算* 赋值* 运算函数2、什么是内存?
① 内存条通电后产生的可存储数据的空间(临时的)② 一块小内存的2个数据* 内部存储的数据* 地址值③ 内存分类* 栈:全局变量、局部变量(空间较小)*堆:对象 (空间较大)3、什么是变量?
* 可变化的量,由变量名和变量值组成* 每个变量都对应一块小内存,变量名用来查找对应的内存,变量值就是内存中保存的数据4、内存、数据、变量三者之间的关系
* 内存是用来存储数据的临时空间* 变量是内存的标识,我们通过变量找到对应的内存,进而操作(读 / 写)内存中的数据5、相关问题1
① var a = xxx, a 内存中到底保存的是什么?* xxx是基本数据,保存的就是这个数据* xxx是对象,保存的是对象的地址* xxx是一个变量,保存的是xxx的内存内容(可能是基本数据,也可能是地址值)var a = function(){ }② 关于引用变量赋值问题* n个引用变量指向同一个对象,通过一个变量修改对象内部数据,其他所有变量看到的是修改之后的数据var obj1 = {name:'Tom'}; var obj2 = obj1; // 将obj1内存的内容保存到obj2 obj1.name = 'Jack'; console.log(obj2.name); //'Jack
* 2个引用变量指向同一个对象,让其中一个引用变量指向另一个对象,另一个引用变量仍然指向前一个对象var a = {age:12}; var b = a; a = {name: 'BoB',age:13}; b.age = 14; console.log(b.age,a.name,a.age); // 14 Bob 13 function fn(obj){ obj = {age:15} } fn(a); console.log(a.age); // 13
6、相关问题2
① 在js调用函数时传递变量参数时,是值传递还引用传递?* 理解1:都是值(基本/ 地址值)传递* 理解2:可能是值传递,也可能是引用传递(地址值)② JS引擎如何管理内存?Ⅰ 内存生命周期* 分配小内存空间,得到它的使用权* 存储数据,可以反复进行操作* 释放小内存空间Ⅱ 释放内存* 局部变量:函数执行完自动释放* 全局变量:成为垃圾对象 ---> 垃圾回收器回收
function fn(){
var b = {}
}
fun(); // b是自动释放,b所指向的对象是在后面的某个时刻由垃圾回收器回收
三、对象
1、什么是对象?
* 多个数据的封装体* 用来保存多个数据的容器* 一个对象代表现实中的一个事物
2、为什么要用对象?
* 统一管理多个数据
3、对象的组成
① 属性:属性名(字符串)和属性值(任意)组成* 代表现实事物的状态数据② 方法:一种特别的属性(属性值是函数)* 代表现实事物的行为数据
4、如何访问对象内部数据?
① * . 属性名:编码简单,有时不能用* [ ' 属性名 ' ]:编码麻烦,能通用
var p = {
name: ' Tom ',
age: 12,
setName: function(name){
this.name = name;
},
setAge:function(age){
this.age = age;
}
}
p.setName('Bob');
p['setAge'](23);
console.log(p.name,p['age'])
② 什么时候必须使用[ ' 属性名 ' ]的方式?* 属性名包含特殊字符: - 空格* 属性名不确定
var p = {}
1. 给p对象添加一个属性:content-type:text/json
p.content-type = 'text/json' //不能用
p['content-type'] = 'text/json'
2.属性名不确定
var propNmame = 'myAge';
var value = 18;
p.proName = value; //不能用
p[proName] = value
四、函数
1、什么是函数?
* 实现特定功能的n条语句的封装体* 只有函数是可以执行的,其他类型的数据不能执行
2、为什么要用函数?
* 提高代码复用* 便于阅读交流
3、如何定义函数?
* 函数声明
function fn1(){
console.log('fn1()')
}
* 表达式
var fn2 = function(){
console.log('fn2()')
}
4、如何调用(执行)函数?
* test():直接调用* obj.test():通过对象调用* new test():new调用* test.call / apply(obj):临时让test成为obj的方法进行调用
var obj = {}
function test2(){
this.xxx = 'guigu'
}
obj.test2(); // 错误
test2.call(obj); //js可以让一个函数成为指定任意对象的方法进行调用
console.log(obj.xxx);
五、回调函数
1、什么函数才是回调函数?
* 你定义的* 你没有调* 但最终它执行了(在某个时刻或某个条件下)
2、常见的回调函数?
* dom事件回调函数 ---> this是发生事件的dom元素(例如:button)* 定时器回调函数 ---> this是window* ajax请求回调函数* 声明周期回调函数
六、IIFE
1、理解
* 全称:Immediately-Invoked Function Expression 立即调用函数表达式* 别名:匿名函数自调用(function(){ // 匿名函数自调用var a = 3;console.log(a+3);})()
2、作用
* 隐藏实现* 不会污染外部(全局)命名空间* 用它来编写js模块
(function(){
var a = 1;
function test(){
console.log(++a);
}
window.$ = function(){ // 向外暴露一个全局函数
return {
test:test;
}
}
})();
$().test(); // 1.$是一个函数 2.$执行后返回的是一个对象
七、函数中的this
1、this是什么?
* 任何函数本质上都是通过某个对象来调用的,如果没有直接指定就是window* 所有函数内部都有一个变量this* 它的值是调用函数的当前对象
2、如何确定this的值?
* test( ):window
* p.test( ): p
* new test( ):新创建的对象
* p.call(obj):obj
function Person(color) {
console.log(this)
this.color = color;
this.getColor = function () {
console.log(this)
return this.color;
};
this.setColor = function (color) {
console.log(this)
this.color = color;
};
}
Person("red"); //this是谁? window
var p = new Person("yello"); //this是谁? p
p.getColor(); //this是谁? p
var obj = {};
p.setColor.call(obj, "black"); //this是谁? obj
var test = p.setColor;
test(); //this是谁? window
function fun1() {
function fun2() {
console.log(this);
}
fun2(); //this是谁? window
}
fun1();
八、关于语句分号问题
1、在下面两种情况下不加分号会有问题
* 小括号开头的前一条语句* 中括号开头前一条语句
2、解决方法:在行首加分号
var a = 3;(function(){})()
九、复习
1、形参的本质是变量、实参的本质是数据2、什么时候是垃圾对象?没有一个引用指向的时候
十、函数的prototype
1、函数的prototype属性
* 每个函数都有一个prototype属性,它默认指向一个Objec t空对象(即称为:原型对象)* 原型对象中有一个属性constructor,它指向函数对象
2、给原型对象添加属性(一般都是方法)
* 作用:函数的所有实例对象自动拥有原型中的属性(方法)
十一、显式原型与隐式原型
1、每个函数function都有一个prototype,即显式原型
2、每个实例对象都有一个__proto__,可称为隐式原型
3、对象的隐式原型的值为其对应构造函数的显式原型的值
4、内存结构
* 函数对象是在定义的时候就创建了
5、总结:
* 函数的prototype属性:在定义函数时自动添加的,默认值是一个空Object对象* 对象的__proto__属性:创建对象时自动添加的,默认值为构造函数的prototype属性值* 程序员能直接操作显式原型,但不能直接操作隐式原型(ES6之前)
十二、原型链
1、原型链
* 访问一个对象属性时* 先在自身属性中查找,找到返回* 如果没有,再沿着__proto__这条链向上查找,找到返回* 如果最终没有找到,返回undefined* 别名:隐式原型链* 作用:查找对象的属性(方法)
2、构造函数 / 原型 / 实体对象的关系
*函数对象是Function的实例function Foo(){ } <----> var Foo = new Function()
3、构造函数 / 原型 / 实体对象的关系2
* 函数的显式原型指向的对象默认是空Object实例对象(但Object不满足)console.log(Fn.prototype instanceof Object) // trueconsole.log(Object instanceof Object) // falseconsole.log(Function.prototype instanceof Object) // true* 所有函数都是Function的实例(包含Function)console.log(Function.prototype === Function.__proto) // true* Object的原型对象是原型链的尽头console.log(Object.prototype.__proto) // null
十二、原型链_属性问题
1、读取对象的属性值时:会自动到原型链中查找
2、设置对象的属性值时:不会查找原型链,如果当前对象中没有此属性,直接添加此属性并设置其值
3、方法一般定义在原型中,属性一般通过构造函数定义在对象本身上
十三、探索 instanceof
(判断左边的对象是否为右边类型的实例)
1、Function是通过new自己产生的实例
2、instanceof是如何判断的?
* 表达式:A instanceof B* 如果B函数的显式原型对象在A对象的原型链上,返回true,否则返回false
//案例1
function Foo() { }
var f1 = new Foo();
console.log(f1 instanceof Foo); // true
console.log(f1 instanceof Object); // true
//案例2
console.log(Object instanceof Function) // true
console.log(Object instanceof Object) // true
console.log(Function instanceof Object) // true
console.log(Function instanceof Function) // true
function Foo() {}
console.log(Object instanceof Foo); // false
十四、面试题
/*
测试题1
*/
var A = function() { }
A.prototype.n = 1
var b = new A()
A.prototype = {
n: 2,
m: 3
}
var c = new A()
console.log(b.n, b.m, c.n, c.m) // 1 undefined 2 3
/*
测试题2
*/
var F = function(){};
Object.prototype.a = function(){
console.log('a()')
};
Function.prototype.b = function(){
console.log('b()')
};
var f = new F();
f.a() // true
f.b() // false
F.a() // true
F.b() // true
十五、变量提升与函数提升
1、变量声明提升
* 通过var定义(声明)的变量,在定义语句之前就可以访问到* 值:undefined
2、函数声明提升
* 通过function声明的函数,在之前就可以直接调用* 值:函数定义(对象)
3、问题:变量提升和函数提升是如何产生的?
十六、执行上下文
1、代码分类(位置)
* 全局代码* 函数(局部)代码
2、全局执行上下文
* 在执行全局代码前将window确定为全局执行上下文* 对全局数据进行预处理* var定义的全局变量 ==>undefined,添加为window的属性* function声明的全局函数 ==> 赋值(fun),添加为window的方法* this ==> 赋值(window)
3、函数执行上下文
* 在调用函数,准备执行函数体之前,创建对应的函数执行上下文对象* 对局部数据进行预处理* 形参变量 ==> 赋值(实参)==> 添加为执行上下文的属性* arguments ==> 赋值(实参列表),添加为执行上下文的属性* var 定义的局部变量 ==> undefined,添加为执行上下文的属性* function 声明的函数 ==> 赋值(fun),添加为执行上下文的方法* this ==> 赋值(调用函数的对象)* 开始执行函数体代码
十七、执行上下文栈
1、在全局代码执行前,JS引擎就会创建一个栈来存储管理所有的执行上下文对象2、在全局执行上下文(window)确定后,将其添加到栈中(压栈)3、在函数执行上下文创建后,将其添加到栈中(压栈)4、在当前函数执行完后,栈中只剩下window