基本类型:string、number、boolean、null、undefined
引用类型:object、function、array
typeof : 主要用来判断数据类型,返回值有string、boolean、number、undefined、object、function
instanceof: 判断该对象是谁的实例,返回值为true或false。
var arr = [11, 22, 33];
console.log(typeof arr); //object
console.log(arr instanceof Array); //true
undefined 和 null 的区别:
null表示空对象,undefined表示已在作用域中声明但未赋值的变量
null 和 undefined 的值相等,但类型不等
console.log(null == undefined); // true 值相同
console.log(null === undefined); // false 类型不同
console.log(typeof undefined); // undefined
console.log(typeof null); // object
词法作用域:
词法作用域就是定义在词法阶段的作用域。
换句话说,词法作用域是由你在写代码时将变量和块作用域写在哪里来决定的。
function fn1() {
var x = 10;
function fn2() { // 注意:fn2函数并没有定义局部变量
//fn1内部的所有局部变量,对fn2都是可见的。但是反过来就不行
//这就是Javascript语言特有的"链式作用域"结构,子对象会一级一级地向上寻找所有父对象的变量。
//所以,父对象的所有变量,对子对象都是可见的,反之则不成立。
console.log(x);
}
fn2(); //fn2函数在fn1函数内部执行
}
f1(); // 10
闭包:是指有权访问另一个函数作用域中的变量的函数
function fn1() {
var x = 10;
function fn2() { //fn2函数,就是闭包
console.log(x);
}
//既然fn2可以读取fn1中的局部变量,那么只要把fn2作为返回值,我们不就可以在fn1外部读取它的内部变量了吗!
return fn2;
}
var result = fn1();
result(); // 10
闭包用途:
闭包缺点:会导致函数的变量一直保存在内存中,过多的闭包可能会导致内存泄漏
最后:引用闭包的两个思考题(阮一峰),如果你能理解下面两段代码的运行结果,应该就算理解闭包的运行机制了。
//代码片段一:
var name = "The Window";
var object = {
name : "My Object",
getNameFunc : function(){
return function(){
return this.name;
};
}
};
alert(object.getNameFunc()()); // The Window
//代码片段二:
var name = "The Window";
var object = {
name : "My Object",
getNameFunc : function(){
var that = this;
return function(){
return that.name;
};
}
};
alert(object.getNameFunc()()); // My Object
原型:对象中固有的__proto__属性,该属性指向对象的prototype原型属性。
原型链:当我们访问一个对象的属性时,如果这个对象内部不存在这个属性,那么就会去它的原型对象里找这个属性,而这个原型对象又会有自己的原型,于是就这样一直找下去,也就是原型链的概念。所以原型链为对象成员查找机制提供一个方向。
特点:JavaScript对象是通过引用来传递的,我们创建的每个新对象实体中并没有一份属于自己的原型副本。当我们修改原型时,与之相关的对象也会继承这一改变。
this 表示当前对象的一个引用。
1. 在方法中,this 表示该方法所属的对象
a、如果该方法属于某个对象,this指向该对象
b、如果该方法是全局方法,this指向window ,在严格模式下,this 是未定义的(undefined)。
c、如果是构造函数调用,this指向这个用new新创建的对象。
2. 在事件中,this 表示接收事件的元素
3. apply() 、 call() 和 bind() 调用模式,这三个方法都可以显示的指定调用函数的 this 指向。
apply() 接收的参数是数组
call() 接收参数列表
bind() 方法不会立即执行,而是返回一个改变了上下文 this 后的函数。
作用域:确定当前执行的代码对某些变量的访问权限。(全局作用域、函数作用域、块级作用域)。
作用域链:就是从当前作用域开始一层一层向上寻找某个变量,直到找到全局作用域还是没找到,就宣布放弃。
变量提升(预解析):在当前作用域下, JS 代码执行之前,浏览器会把用var 和 function 声明的变量和函数进行提前声明。
1. extends (ES6)
注意: 1.在 ES6 中类没有变量提升,所以必须先定义类,才能通过类实例化对象。
2.类里面的共有属性和方法一定要加this使用。
//父类
class Father {
// 类里面的 构造函数
constructor(firstName, secondName) {
this.firstName = firstName;
this.secondName = secondName;
}
// 类里面的 普通函数
say() {
console.log("父类的方法");
}
}
//子类
class Son extends Father {
// super 关键字用于访问和调用对象父类上的函数。可以调用父类的构造函数,也可以调用父类的普通函数
// 注意: 子类在构造函数中使用super, 必须放到 this 前面 (必须先调用父类的构造方法,在使用子类构造方法)
constructor(x,y) {
// 调用父类的构造函数
super(firstName, secondName);
// 调用普通函数(可以,但无意义)
//super.say();
}
}
let s = new Son("张", "无忌");
console.log(s.firstName); // 张
s.say(); // 父类的方法
2. 组合继承:构造函数 + 原型对象
核心原理:
使用call(), 将父类型的this 指向 子类型(缺点:不能继承父类型原型上的方法)
解决方法:让子类的 prototype 原型对象 = new 父类() (父类实例化之后另外开辟内存空间,就不会影响原来父类原型对象)
// 父 构造函数
function Father(firstName, secondName) {
this.firstName = firstName;
this.secondName = secondName;
this.have = function () {
console.log("父亲有三栋别墅!!!");
};
}
Father.prototype.rank = function () {
console.log("最高军衔!");
};
// 子 构造函数
function Son(firstName) {
Father.call(this, "李");
}
Son.prototype = new Father(); //这一步必须写在,创建子类对象之前
let s = new Son();
s.have(); // 父亲有三栋别墅!!!
s.rank(); // 最高军衔!
相比JSON,XML还是有一些不足:
XML标签冗余高,数据体积大,传输速度慢
XML解析较难,json解析难度几乎为0
只是拷贝一层,更深层次对象级别的只拷贝引用(地址),所以被拷贝的对象和拷贝出来的对象都是共用一个地址(会相互影响)
拷贝出来的对象和原对象之间没有任何数据是共享的,所有的东西都是自己独占的一份。
1. jQuery的$.extend():
我们可以通过$.extend()方法来完成深复制。值得庆幸的是,我们在jQuery中可以通过添加一个参数来实现递归extend
2. 使用JSON对象实现深拷贝
使用JSON全局对象的parse和stringify方法来实现深复制也算是一个简单讨巧的方法。
function jsonClone(obj) {
return JSON.parse(JSON.stringify(obj));
//JSON.parse() 方法用来解析JSON字符串,构造由字符串描述的JavaScript值或对象。
// JSON.stringify() 方法将一个 JavaScript 对象或值转换为 JSON 字符串
}
var clone = jsonClone({ a:1 });
3. 使用递归自己封装一个函数
function deepClone(obj) {
if (!obj || typeof obj !== "object") return;
let newObj = Array.isArray(obj) ? [] : {};
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
newObj[key] =
typeof obj[key] === "object" ? deepClone(obj[key]) : obj[key];
}
}
return newObj;
}
定义:触发事件后在n秒内函数只能执行一次,如果在n秒内又触发了事件,则会重新计算函数执行时间。
使用场景:搜索框搜索输入。只需用户最后一次输入完,再发送请求 手机号、邮箱验证输入检测 onchange oninput事件 窗口大小Resize。只需窗口调整完成后,计算窗口大小。防止重复渲染。
const debounce = (fn, wait, immediate) => {
let timer = null;
return function (...args) {
if (timer) clearTimeout(timer);
if (immediate && !timer) {
fn.call(this, args);
}
timer = setTimeout(() => {
fn.call(this, args);
}, wait);
};
};
const betterFn = debounce(() => console.log("fn 防抖执行了"), 1000, true);
document.addEventListener("scroll", betterFn);
定义:当持续触发事件时,保证隔间时间触发一次事件。
使用场景:
function throttle(fn,wait){
let pre = 0;
return function(...args){
let now = Date.now();
if( now - pre >= wait){
fn.apply(this,args);
pre = now;
}
}
}
function handle(){
console.log(Math.random());
}
window.addEventListener("mousemove",throttle(handle,1000));