JavaScript核心知识

290 阅读15分钟

数据类型

五种基础类型:字符串值、数值、布尔值、数组、对象

typeof运算符:返回变量或者表达式的类型。

Undefined:没有值的变量 var person

空值:空的字符串变量既有值也有类型 var car = ""

Null:nothing,数据类型是对象,可以设置值为null清空对象

Undefined与Null的区别:值相同,类型不相同

原始数据:一种没有额外属性和方法的简单数据值。有string、number、boolean、undefined、null

复杂数据:function、object

this关键字

JavaScript this关键词指的是它所属的对象

它拥有不同的值,具体取决于它的使用位置

  • 在方法中,this指得是所有者对象
  • 单独的情况下,this指的是全局对象
  • 在函数中,this指的是全局对象
  • 在函数中,严格模式下,this的undefined
  • 在事件中,this指的是接收事件的元素

显式函数绑定

call()和apply()方法是预定义的JavaScript方法,可以用于将另一个对象作为参数调用对象方法

var person1 = {
  fullName: function() {
    return this.firstName + " " + this.lastName;
  }
}
var person2 = {
  firstName:"Bill",
  lastName: "Gates",
}
person1.fullName.call(person2);  // 会返回 "Bill Gates"

字符串方法

  • 返回字符串长度
    • length
  • 检索字符串中的字符串
    • indexOf(string,number):返回字符串中指定文本首次出现的索引(位置),第二个参数表示开始检索的位置。索引从0开始,-1表示未找到
    • lastIndexOf(string,number):返回字符串指定文本末尾出现的所有(位置),第二个参数表示开始检索的位置。索引从0开始,-1表示未找到
    • search():搜索特定值的字符串,并返回匹配的位置
  • 提取部分字符串
    • slice(start,end):提取字符串的某个部分并在新字符串中返回被提取的部分,可接受负索引
    • substring(start,end):类似slice,无法接受负索引
    • substr(start,length):类似slice,第二个参数是提取部分的长度
  • 替换字符串内容
    • replace(resString,repString),大小写敏感,默认只替换首个匹配,替换所有并且大小写不敏感,使用正则表达式replace(/resString/gi,repString)
  • 转换成大小写
    • toUpperCase():将字符串转换成大写
    • toLowerCase():将字符串转换成小写
  • 拼接字符串
    • concat(string1,string2,...,stringN):连接两个或者多个字符串
  • 去掉空白符
    • trim():删除字符串两端的空白符,IE8或者更低版本不支持trim()方法
  • 提取字符串字符
    • charAt(index):返回字符串中指定下标(位置)的字符
    • charCodeAt(index):返回字符串中指定索引的字符Unicode编码
  • 字符串转数组
    • split(“分隔符”):将字符串转换成数组

数字方法

  • 格式化为字符串
    • toString()
  • 四舍五入并使用指数计数法返回字符串值
    • toExponential()
  • 指定位数小数的数字
    • toFixed(number)
  • 指定长度的数字返回字符串值
    • toPrecision()
  • 将变量转换成数值
    • Number():将JavaScript变量转换成数值
    • parseInt():解析一段字符串并返回整形数值,允许空格。只返回首个数字
    • parseFloat():解析一段字符串并返回双精度数字,允许空格。只返回首个数字

Array对象属性和方法

  • 属性
    • length:数组长度
  • 技巧
    • 访问最后一个数组元素array[array.length-1]
    • 遍历数组元素Array.forEach()
    • 添加数组元素
      • push():向数组添加新元素
    • 判断是否为数组
      • Array.isArray(array),ECMAScript5方法
  • 对象方法
    • concat():连接两个或者更多的数组,并返回结果
    • join(separator):把数组的所有元素放入一个字符串
    • pop():删除并返回数组最后一个元素
    • push():将数组的末尾添加一个或者更多元素,并放回新的长度
    • reverse():颠倒数组中元素的顺序
    • shift():删除并返回数组的第一个元素
    • slice(start,end):从某个已有的数组返回选定的元素
    • sort():对数组的元素进行排序
    • splice(index,howmany,item1,......,itemX):删除元素,并想数组添加新元素
    • toString():将数组转换成字符串
    • unshift():想数组的开头添加一个或更多元素,并返回新的长度

数组迭代

  • Array.forEach():为每个数组元素调用一次函数(回调函数)
  • Array.map()
    • 对每个数组元素执行函数来创建新的数组
    • 不会对没有值得数组元素执行函数
    • 不会更改原始数组
  • Array.filter():创建一个包含通过测试的数组元素的新数组
  • Array.reduce()
    • 在每个数组元素上运行函数,以生成(减少它)单个值。
    • 在数组中从左到右。
    • 不会减少原始数组
  • Array.every():检查所有数组是否通过测试
  • Array.some():检查某些数组值是否通过了测试
  • Array.indexOf(item,start):在数组中搜索元素值并且返回其位置,从0开始
  • Array.lastIndexOf():与indexOf相似,从数组结尾开始搜索
  • Array.find():返回通过测试函数的第一个数组元素的值
  • Array.findIndex():返回通过测试函数的第一个数组元素的索引

Date日期格式化

四种JavaScript日期输入格式:

  • ISO日期: 2018-02-12(国际标准)        YYYY-MM-DD
  • 短日期:   02/19/2018或者2018/02/19   MM/DD/YYYY(常用)或者YYYY/MM/DD
  • 长日期:   Feb 19 2018或者19 Feb 2018 (常用MMM DD YYYY)
  • 完整日期:Monday February 25 2015

JavaScript日期输出格式:Mon Feb 19 2018 06:00:00 GMT+0800 (中国标准时间)

日期获取方法

  • getDate():以数值返回天(1-31)
  • getDay():以数值获取周名(0-6)
  • getFullYear():获取四位的年(YYYY)
  • getHours():获取小时(0-23)
  • getMilliseconds():获取毫秒数(0-999)
  • getMinutes():获取分(0-59)
  • getMonth():获取月(0-11)
  • getSecond():获取秒(0-59)
  • getTime():获取时间(返回自1970年1月1日以来的毫秒数)

日期设置时间

  • setDate():以数值(1-31)设置日
  • setFullYear():设置年(可选月和日)
  • setHours():设置小时
  • setMilliseconds():设置毫秒
  • setMinutes():设置分
  • setMonth():设置月
  • setSeconds():设置秒
  • setTime():设置时间

Math对象

  • Math.PI
  • Math.round(x):返回值是x四舍五入为最接近的整数
  • Math.pow(x,y):返回值是x的y次幂
  • Math.sqrt(x):返回x的平方根
  • Math.abs(x):返回x的绝对(正)值
  • Math.ceil():返回x上舍入最接近的整数
  • Math.floor():返回x下舍入最接近的整数
  • Math.sin(x):返回角x(以弧度计)的正弦(结余-1和1之间的值)
  • Math.cos(x):返回角x(以弧度计)的余弦(结余-1和1之间的值)
  • Math.min() 和 Math.max() 可用于查找参数列表中的最低或最高值
  • Math.random():返回介于0(包括)与1(不包括)之间的随机数

随机整数

函数始终返回介于 min(包括)和 max(不包括)之间的随机数:

function getRndInteger(min, max) {
    return Math.floor(Math.random() * (max - min) ) + min;
}

函数始终返回介于 min 和 max(都包括)之间的随机数:

function getRndInteger(min, max) {
    return Math.floor(Math.random() * (max - min + 1) ) + min;
}

正则表达式

  • 修饰符
    • i:执行大小写不敏感的匹配
    • g:执行全局匹配
    • m:执行多行匹配
  • 方括号
    • 【abc】:查找方括号之间的任何字符
    • 【^abc】:查找任何不在方括号之间的字符
    • 【0-9】:查找任何从0到9的数字
    • 【a-z】:查找任何小写a到小写z的字符
    • 【A-Z】:查找任何大写A到大写Z的字符
    • 【A-z】:查找任何大写A到小写z的字符
    • 【adgk】:查找给定集合内的字符
    • 【^adgk】:查找给定集合外的任何字符
    • (red|blue|green):查找任何指定的选项
  • 元字符
    •  . :查找单个字符,除了换行和行结束符
    • \w :查找单词字符
    • \W:查找非单词字符
    • \d:查找数字
    • \D:查找非数字字符
    • \s:查找空白字符
    • \S:查找非空白字符
    • \b:匹配单词边界
    • \B:匹配非单词边界
    • \n:查找换行符
  • 量词
    • n+:匹配任何包含至少一个n的字符串
    • n*:匹配任何包含零个或多个n的字符串
    • n?:匹配任何包含零个或者一个n的字符串
    • n{ X }:匹配包含X个n的序列的字符串
    • n{ X , Y }:匹配包含X至Y个n的序列的字符串
    • n{ X , }:匹配包含至少X个n的序列的字符串
    • n$:匹配任何结尾为n的字符串
    • ^n:匹配任何开头为n的字符串
    • ?=n:匹配任何其后紧接指定字符串n的字符串
    • ?!n:匹配任何其后没有紧接指定指定字符串n的字符串
  • 支持正则表达式的String对象的方法
    • search:检索与正则表达式相匹配的值
    • match:找到一个或多个正则表达式的匹配
    • replace:替换与正则表达式匹配的字符串
    • split:把字符串分割为字符串数组

作用域

  • 局部作用域
    • 函数内声明的变量,只能在函数中访问它们
    • 有效期:在函数完成时删除
  • 全局作用域
    • 函数之外声明的变量,网页的所有脚本和函数都能访问它们
    • 自动全局,为未声明的变量赋值,此变量会自动成为全局变量
    • 有效期:关闭网页时被删除

提升

提升是JavaScript将声明移至顶部的默认行为,在JavaScript中,可以在使用变量之后对其进行声明;JavaScript初始化不会被提升。

let或construction声明的变量和常量不会被提升

严格模式

声明严格模式:通过在脚本或函数的开头添加 "use strict"; 来声明严格模式

准则:

  • 无法使用未声明的变量(对象和函数也属于变量)
  • 不允许删除变量或者函数
  • 不允许重复参数名
  • 不允许声明八进制数值文本
  • 不允许转义字符
  • 。。。太多啦,参考www.w3school.com.cn/js/js_stric…

JavaScript代码约定

  • 变量名:驼峰命名法
  • 空格:运算符(= + - * /)周围以及逗号之后添加空格
  • 代码缩进:四个空格
  • 语句规则:以分号结束单条语句
  • 复杂语句通用规则:
    • 第一行结尾处写开括号
    • 开括号前使用一个空格
    • 新行上写闭括号,不带前导空格
    • 不要以分号结束复杂语句
  • 对象规则
    • 把开括号与对象名放在同一行
    • 在每个属性与其值之间使用冒号加一个空格
    • 不要在最后一个属性值后台写逗号
    • 在新行上写闭括号,不带前导空格
    • 始终以分号结束对象定义

对象构造器

function Person(first, last, age, eyecolor) {
    this.firstName = first;
    this.lastName = last;
    this.age = age;
    this.eyeColor = eyecolor;
}
var myFather = new Person("Bill", "Gates", 62, "blue");

无法直接为已有的对象构造器添加新属性或者方法(下列方法错误)

Person.nationality = "English"; XXX

如需向构造器添加一个新属性,则必须把它添加到构造器函数:

function Person(first, last, age, eyecolor) {
    this.firstName = first;
    this.lastName = last;
    this.age = age;
    this.eyeColor = eyecolor;
    this.nationality = "English";
}


原型继承

所有 JavaScript 对象都从原型继承属性和方法。

日期对象继承自 Date.prototype。数组对象继承自 Array.prototype。Person 对象继承自 Person.prototype。

Object.prototype 位于原型继承链的顶端:

日期对象、数组对象和 Person 对象都继承自 Object.prototype。

JavaScript prototype 属性允许您为对象构造器添加新属性或者方法:

Person.prototype.nationality = "English";

call()

使用call()方法,您可以编写能够在不同对象上使用的方法

var person = {
    fullName: function() {
        return this.firstName + " " + this.lastName;
    }
}
var person1 = {
    firstName:"Bill",
    lastName: "Gates",
}
var person2 = {
    firstName:"Steve",
    lastName: "Jobs",
}
person.fullName.call(person1);  // 将返回 "Bill Gates"

call()方法可以接受参数

var person = {
  fullName: function(city, country) {
    return this.firstName + " " + this.lastName + "," + city + "," + country;
  }
}
var person1 = {
  firstName:"Bill",
  lastName: "Gates"
}
person.fullName.call(person1, "Seattle", "USA");

Apply()

通过apply()方法,可用于不同对象的方法

var person = {
    fullName: function() {
        return this.firstName + " " + this.lastName;
    }
}
var person1 = {
    firstName: "Bill",
    lastName: "Gates",
}
person.fullName.apply(person1);  // 将返回 "Bill Gates"

call()和apply()之间的区别

call()方法分别接受参数

apply()方法接受数组形式的参数

var person = {
  fullName: function(city, country) {
    return this.firstName + " " + this.lastName + "," + city + "," + country;
  }
}
var person1 = {
  firstName:"John",
  lastName: "Doe"
}
person.fullName.apply(person1, ["Oslo", "Norway"]);

高级JavaScript

变量弱类型

可以重复声明变量

随时可以改变变量的数据类型

可以先使用变量,再声明变量(变量提升)。

变量类型

变量存在两种类型的值,即原始值和引用值

原始值:存储在栈(stack)中的简单数据段,它的值直接存储在变量访问的位置

引用值:存储在堆(heap)中的对象,存储在变量的值是一个指针(point),指向存储对象的内存处

Object对象

两个属性:

  • constructor:对创建对象的函数引用
  • prototype:对该对象的对象原型的引用

五个方法:

  • hasOwnProperty(property):判断对象是否有某个特定的属性,必须用字符串指定该属性
  • IsPrototypeOf(object):判断该对象是否为另一个对象的原型
  • PropertyIsEnumerable:判断给定的属性是否可以用for...in语句进行枚举
  • ToString():返回对象的原始字符串表示
  • ValueOf():返回最适合该对象的原始值

原始类型

ECMAScript有5种原始类型(primitive type),即Undefined、Null、Boolean、Number和String。

引用类型

引用类型通常叫做类(class),也就是说,遇到引用值,所处理的就是对象。对象是由 new 运算符加上要实例化的对象的名字创建的

typeof与instanceof运算符

使用typeof运算符用于识别变量以及原始类型的类型,但是使用typeof运算符时采用引用类型存储值会出现一个问题,无论引用是什么类型对象,都返回'object'。

instanceof运算符与typeof运算符相似,用于识别正在处理的对象的类型。与typeof方法不同的是,instanceof方法要求开发者明确地确认对象为某特定类型

arguments对象

在函数中,使用特殊对象 arguments,无需明确指出参数名,就能访问。arguments[index]

可以使用arguments对象检测函数的参数个数。arguments.length

可以arguments对象判断传递给函数的参数个数模拟函数重载。

闭包

闭包,指的是词法表示包括不被计算的变量的函数,也就是说,函数可以使用函数之外定义的变量

var iBaseNum = 10;

function addNum(iNum1, iNum2) {
  function doAdd() {
    return iNum1 + iNum2 + iBaseNum;
  }
  return doAdd();
}

定义类和对象

工厂模式

function showColor() {
  alert(this.color);
}

function createCar(sColor,iDoors,iMpg) {
  var oTempCar = new Object;
  oTempCar.color = sColor;
  oTempCar.doors = iDoors;
  oTempCar.mpg = iMpg;
  oTempCar.showColor = showColor;
  return oTempCar;
}

var oCar1 = createCar("red",4,23);
var oCar2 = createCar("blue",3,25);

oCar1.showColor();		//输出 "red"
oCar2.showColor();		//输出 "blue"

缺陷:不符合对象语义(它看起来不像使用带有构造函数 new 运算符那么正规),函数看起来不像对象的方法

构造方法

function Car(sColor,iDoors,iMpg) {
  this.color = sColor;
  this.doors = iDoors;
  this.mpg = iMpg;
  this.showColor = function() {
    alert(this.color);
  };
}

var oCar1 = new Car("red",4,23);
var oCar2 = new Car("blue",3,25);

缺陷:虽然使用 new 运算符和类名 Car 创建对象,但是构造函数会重复生成函数,为每个对象都创建独立的函数版本。不过,与工厂函数相似,也可以用外部函数重写构造函数,同样地,这么做语义上无任何意义

原型

我们创建的每个函数都会有一个prototype(原型)属性,这个属性是一个指针,指向一个对象,而这个对象的用途是包含可以由特定类型的所有实例共享的方法和属性。简单地说,我们可以通过函数的prototype属性为此函数原型对象创建属性和方法,所有实例化该函数的实例都可以共享原型对象的属性和方法。总而言之,prototype 对象的任何属性和方法都被传递给那个类的所有实例

function Car() {
}

Car.prototype.color = "blue";
Car.prototype.doors = 4;
Car.prototype.mpg = 25;
Car.prototype.showColor = function() {
  alert(this.color);
};

var oCar1 = new Car();
var oCar2 = new Car();

缺陷:这个构造函数没有参数。使用原型方式,不能通过给构造函数传递参数来初始化属性的值;属性指向的是对象,而不是函数。

混合的构造函数/原型方式

function Car(sColor,iDoors,iMpg) {
  this.color = sColor;
  this.doors = iDoors;
  this.mpg = iMpg;
  this.drivers = new Array("Mike","John");
}

Car.prototype.showColor = function() {
  alert(this.color);
};

var oCar1 = new Car("red",4,23);
var oCar2 = new Car("blue",3,25);

oCar1.drivers.push("Bill");

alert(oCar1.drivers);	//输出 "Mike,John,Bill"
alert(oCar2.drivers);	//输出 "Mike,John"

动态原型方法

function Car(sColor,iDoors,iMpg) {
  this.color = sColor;
  this.doors = iDoors;
  this.mpg = iMpg;
  this.drivers = new Array("Mike","John");
  
  if (typeof Car._initialized == "undefined") {
    Car.prototype.showColor = function() {
      alert(this.color);
    };
	
    Car._initialized = true;
  }
}

继承机制

对象冒用:

其原理如下:构造函数使用 this 关键字给所有属性和方法赋值(即采用类声明的构造函数方式)。因为构造函数只是一个函数,所以可使 ClassA 构造函数成为 ClassB 的方法,然后调用它。ClassB 就会收到 ClassA 的构造函数中定义的属性和方法。

function ClassA(sColor) {
    this.color = sColor;
    this.sayColor = function () {
        alert(this.color);
    };
}

function ClassB(sColor, sName) {
    this.newMethod = ClassA;
    this.newMethod(sColor);
    delete this.newMethod;

    this.name = sName;
    this.sayName = function () {
        alert(this.name);
    };
}

所有新属性和新方法都必须在删除了新方法的代码行后定义。否则,可能会覆盖超类的相关属性和方法。

call()方法:

function ClassB(sColor, sName) {
    //this.newMethod = ClassA;
    //this.newMethod(color);
    //delete this.newMethod;
    ClassA.call(this, sColor);

    this.name = sName;
    this.sayName = function () {
        alert(this.name);
    };
}

apply()方法:

function ClassB(sColor, sName) {
    //this.newMethod = ClassA;
    //this.newMethod(color);
    //delete this.newMethod;
    ClassA.apply(this, new Array(sColor));

    this.name = sName;
    this.sayName = function () {
        alert(this.name);
    };
}

原型链:

function ClassA() {
}

ClassA.prototype.color = "blue";
ClassA.prototype.sayColor = function () {
    alert(this.color);
};
function ClassB() {
}

ClassB.prototype = new ClassA();

ClassB.prototype.name = "";
ClassB.prototype.sayName = function () {
    alert(this.name);
};

原型链的弊端是不支持多重继承,因为 prototype 属性被替换成了新对象,添加了新方法的原始对象将被销毁。

混合方式:

创建类的最好方式是用构造函数定义属性,用原型定义方法。这种方式同样适用于继承机制,用对象冒充继承构造函数的属性,用原型链继承 prototype 对象的方法

function ClassA(sColor) {
    this.color = sColor;
}

ClassA.prototype.sayColor = function () {
    alert(this.color);
};

function ClassB(sColor, sName) {
    ClassA.call(this, sColor);
    this.name = sName;
}

ClassB.prototype = new ClassA();

ClassB.prototype.sayName = function () {
    alert(this.name);
};