# ES5
javascript最早是由网景公司推出的,极其简单,被很多开发者接受,逐渐流行起来,后来IE为了抢占市场微软,将IE浏览器内置在windows系统中,所以IE的市场占有率相当的高。IE脚本语言是Jscript(vbscript)
网景公司为了推广js,与sun公司合作,为了让js更流行,借助当时极其流行的语法java,将js更名为javascript,所以java与javascript关系就像雷锋和雷峰塔。网景公司做了一件好事,将js的语言规范提交给ECMA组织,所以我们学习ECMAScript规范就是在学习javascript规范,所以ECMAScript是js规范的未来。微软很有个性,自己非要研制一套规范,研制的非常不好用,后来自己内部工程师都不干了,非要重新研制新的浏览器,所以微软决定放弃xp系统(放弃IE6,7)。重新研制了IE9浏览器,完全遵守ECMAScript语言规范,所以IE9是微软的第一代高级浏览器(是所有高级浏览器中,最差的一款)。
在国内,我们还要维护IE6,7,8,原因是国内一些企业决定维护xp系统,所以IE6,7就无法淘汰,所以就苦了国内的工程师了,还要维护IE6,7,8
好消息是移动端基本都是webkit内核,因此我们可以放心的使用html5,css3,ES5规范等等 在pc端,由于高级浏览器都实现了html5,css3,ES5规范等等,所以我们可以直接用高级浏览器测试它们ES规范版本 ES1, ES2, ES3, ES4, ES3.1, ES5, ES6, ES2016, ES2017, ES2018
# JSON的拓展
# parse
该方法用于将json字符串解析为js对象
使用方式:
JSON.parse(str, fn)
str: 要处理的字符串
fn: 要处理的函数
返回值就是本次处理的结果
有两个参数
第一个参数: 属性名
第二个参数: 属性值
从外部向内部遍历
// 定义json字符串
var str = '{"a": 1, "b": "2", "c": {"d": 3}}';
// 将str转为js对象
var result = JSON.parse(str, function(key, value) {
// 我们想让所有的字符串作为数字保留
// console.log(arguments);
// 判断value的类型
if (typeof value === "string") {
return +value;
}
return value;
});
# stringify
该方法是用于js对象解析为json字符串的
使用方式:
JSON.stringify(obj, fn)
obj: 要处理的对象
fn: 要处理的函数
返回值就是本次处理的结果
有两个参数
第一个参数: 属性名
第二个参数: 属性值
从内部向外部遍历
// 定义对象
var obj = {
a: 1,
b: "2",
c: {
d: 3
}
}
// 将Obj转为json字符串
var result = JSON.stringify(obj, function(key, value) {
// 我们想要将字符串作为数字保留
// console.log(arguments);
if (typeof value === "string") {
return +value;
}
return value;
});
# 数组的拓展
# 判断数组
第一种方式判断对象的类型
Object.prototype.toString.call(obj)
第二种方式是否是实例化对象
obj instanceof Array
第三种方式判断构造函数是否是Array
obj.constructor === Array
第四种方式数字的静态方法
Array.isArray(obj)
// instanceof
console.log(arr instanceof Array);
// 构造函数是Object的时候,判断也是true
console.log(arr instanceof Object);
console.log(obj instanceof Array);
// constructor
console.log(arr.constructor === Array);
console.log(arr.constructor === Object); // false
console.log(obj.constructor === Array);
// toString
console.log(Object.prototype.toString.call(arr) === "[object Array]");
console.log(Object.prototype.toString.call(obj) === "[object Array]");
// 数组的静态方法
console.log(Array.isArray(arr));
console.log(Array.isArray(obj));
# 获取成员的索引
ES5为数组拓展了两个方法:indexOf、 lastIndexOf 分别用于获取成员的索引
参数就要查找的成员
如果查找到成员返回该成员的索引
如果没有找到该成员返回-1
在查找成员的时候不会做类型转换, 是真正的全等查找
// 兼容IE
if (!Array.prototype.indexOf) {
// 拓展方法
Array.prototype.indexOf = function(item) {
// 遍历数组, 就是遍历this
for (var i = 0; i < this.length; i++) {
// i 表示索引值, this[i] 表示成员值
if (this[i] === item) {
// 找到成员返回索引
return i;
}
}
// 循环完毕,没有找到 返回-1
return -1;
}
}
# lastIndexOf
// 兼容lastIndexOf
if (!Array.prototype.lastIndexOf) {
// 拓展方法
Array.prototype.lastIndexOf = function(item) {
// 遍历数组
for (var i = this.length - 1; i >= 0; i--) {
// i 表示索引值, this[i] 表示成员值
if (this[i] === item) {
// 找到成员返回索引
return i;
}
}
// 循环完毕,没有找到 返回-1
return -1;
}
}
# forEach
是数组迭代器方法,该方法用于替代for循环, 并没有将for循环移除, 只是将循环封装在了数组迭代器forEach方法的内部
使用方式:
数组.forEach(fn)
fn: 要执行的函数
有三个参数
第一个参数: 成员值
第二个参数: 索引值
第三个参数: 原数组
作用域是window
返回值对forEach执行的结果没有影响
forEach方法的返回值始终undefined
jQuery中也有一个类似的方法, each, jquery中的each方法与forEach方法的区别就是
jquery中的each方法中函数中的第一个参数是索引值,第二个参数是成员值
// 兼容IE
if (!Array.prototype.forEach) {
// 拓展方法
Array.prototype.forEach = function(fn) {
// 要遍历数组, 就是在遍历this
for (var i = 0; i < this.length; i++) {
// 执行函数并传递参数
// 有三个参数: 成员值: this[i]、 索引值: i, 原数组: this
fn(this[i], i, this);
}
}
}
# map
该方法用于遍历数组并映射结果, 与forEach方法类似, 只是map方法的返回值是有意义的
使用方式:
数组.map(fn)
fn: 要执行的函数
有三个参数: 成员值, 索引值, 原数组
返回值就是执行结果的数组成员
map方法的返回值是一个新的数组, 数组中的成员都是每一次函数执行结果组成的成员
// 兼容IE
if (!Array.prototype.map) {
// 拓展方法
Array.prototype.map = function(fn) {
// 创建结果容器
var result = [];
// 遍历数组
for (var i = 0; i < this.length; i++) {
// 执行函数并传递参数
// 传递三个参数: 成员值 this[i] 、 索引值 i、 原数组 this
// 将函数的执行结果放入数组容器中
result.push(fn(this[i], i, this));
}
// 返回新的数组
return result;
}
}
# fill
该方法用于填充数组
通过Array(len) 或者new Array(len) 得到的只有数组的长度没有成员,所以我们不能使用数组迭代器方法(forEach,map)进行遍历, 就要填充数组
参数就是要填充的成员, 即使是函数也不会执行
// 兼容IE
if (!Array.prototype.fill) {
// 拓展该方法
Array.prototype.fill = function(item) {
// 遍历数组, 就是遍历this
for (var i = 0; i < this.length; i++) {
// 填充数组成员
this[i] = item;
}
// 返回填充后的数组
return this;
}
}
# 断言方法
# some
判断数组中是否有成员满足条件
使用方式与forEach方法类似
参数就是要执行的函数
函数中有三个参数: 成员值, 索引值, 原数组
返回值就是判断的依据
some方法的返回值:
true: 至少有一个成员满足条件
false: 都不满足条件
some方法对true敏感, 一旦遇到满足条件的成员就立即停止遍历
/**
* 实现some方法
* @arr 要遍历的数组
* @fn 要执行的函数
* return bool 是否有成员满足条件
**/
function some(arr, fn) {
// 遍历数组
for (var i = 0; i < arr.length; i++) {
// 执行函数并判断结果
// 传递三个参数: 成员值 arr[i]、 索引值 i 、 原数组 arr
if (fn(arr[i], i, arr)) {
// 如果执行结果为真, 返回true
return true;
}
}
// 遍历完成没有找到
return false;
}
# every
判断数组中是否都满足条件
与forEach方法类似
参数就是要执行的函数
有三个参数: 成员值、 索引值、 原数组
返回值就是判断的依据
every方法的返回值:
true: 都满足条件
false: 至少有一个成员不满足条件
every方法对false敏感, 一旦遇到一个不满足条件的成员立即停止遍历
/**
* 实现every方法
* @arr 要遍历的数组
* @fn 要执行的函数
* return bool 是否都满足条件
**/
function every(arr, fn) {
// 遍历数组
for (var i = 0; i < arr.length; i++) {
// 执行函数并判断结果
// 传递三个参数: 成员值 arr[i]、 索引值 i 、 原数组 arr
if (!fn(arr[i], i, arr)) {
// 遇到不满足条件的停止遍历并返回false
return false;
}
}
// 都满足条件返回true
return true;
}
# filter
实现对数组的过滤
使用方式和forEach方法类似
参数就是要执行的函数
有三个参数: 成员值、索引值、 原数组
返回值就是过滤的条件
filter方法的返回值就是满足过滤条件的成员组成的新数组
/**
* 实现filter方法
* @arr 要遍历的数组
* @fn 要执行的函数
* return [] 满足过滤条件的成员组成的新数组
**/
function filter(arr, fn) {
// 创建一个结果容器
var result = [];
// 遍历数组
for (var i = 0; i < arr.length; i++) {
// 执行函数并判断结果
// 传递三个参数: 成员值 arr[i]、 索引值 i、 原数组 arr
if (fn(arr[i], i, arr)) {
// 将满足过滤条件的成员放入结果容器中
result.push(arr[i]);
}
}
// 返回result
return result;
}
# reduce
# reduceRight
这两个是累加的方法,reduce是从前向后累加, 而reduceRight是从后向前累加
对所有成员逐一处理,并将结果返回
参数就是要执行的函数
有四个参数: 上一次的累积结果,当前成员值, 当前索引值, 原数组
返回值就是当次累积的结果, 将会在下一次遍历的时候作为第一个参数传递
reduce是从第二个成员开始遍历, 第一个成员会在第一次遍历的时候做为第一个参数传递
reduceRight是从倒数第二个成员开始遍历,倒数第一个成员在第一次遍历的时候作为第一个参数
/**
* 实现reduceRight方法
* @arr 要计算的数组
* @fn 要执行的函数
* return 累积结果
*/
function reduceRight(arr, fn) {
// 定义累计结果
// 倒数第一个成员是当次累积的结果
var result = arr[arr.length - 1];
// 遍历数组
for (var i = arr.length - 2; i >= 0; i--) {
// 执行函数传递参数
// 四个参数: 上一次的累计结果, 当前成员值, 当前索引值, 原数组
result = fn(result, arr[i], i, arr)
}
// 返回累积结果
return result;
}
# 实现addNum方法
addNum(num1, num2) 接受两个参数, 分别是两个整数, 求两个整数之间所有整数之和
比如:
addNum(1, 100)
一种是包含两个参数, 两一种是不包含两个参数
我们统一包含两个参数
// 定义函数
function addNum(num1, num2) {
// 确定最大值和最小值
var max = Math.max(num1, num2);
var min = Math.min(num1, num2);
// console.log(max);
// console.log(min);
// (5, 10) 5, 6, 7, 8, 9, 10 10 - 5 + 1
// (5, 10) 6, 7, 8, 9 10 - 5 - 1
// 创建数组
return Array(max - min + 1)
// 为了遍历数组,需要填充数组
.fill(1)
// 要构建一个从最小值到最大值之间的一个数组
.map(function(value, index, arr) {
// index递加, 用min + index 即可得到一个从最小值到最大值之间的数组
return min + index;
})
// 求累加结果
.reduce(function(pre, value, index, arr) {
return pre + value;
})
}
# 函数绑定
ES5对函数拓展了bind方法
作用:为函数绑定作用域(当函数执行的时候,改变函数的作用域,并传递参数)
call与apply的区别
他们都是改变函数作用域的方法,都是在调用该方法的时候,执行函数并改变作用域的,第一个参数都是改变的作用域
call 从第二个参数开始,表示传递给函数的参数
apply 第二个参数是数组,每一个成员表示传递给函数的参数
bind跟call类似
第一个参数表示改变的作用域对象
从第二个参数开始,表示传递的参数
区别:
call | apply 调用即执行
bind调用不执行,但是得到一个新的方法,可以执行
# 日期拓展
toJSON 将日期转化成json格式,(标准化格式)
var date = new Date();
console.log(date)
console.log(date.toJSON())
# Property getters and setters
ES5 lets you define object methods with a syntax that looks like getting or setting a property.
// Create an object:
var person = {
firstName: "John",
lastName : "Doe",
get fullName() {
return this.firstName + " " + this.lastName;
}
};
// Display data from the object using a getter:
document.getElementById("demo").innerHTML = person.fullName;
# Reserved words as property names
var obj = {name: "John", new: "yes"}
# Object.create()
// Create an Object:
const person = {
firstName: "John",
lastName: "Doe"
};
// Create new Object
const man = Object.create(person);
man.firstName = "Peter";
# Object.keys()
// Create an Object
const person = {
firstName: "John",
lastName: "Doe",
age: 50,
eyeColor: "blue"
};
// Get the Keys
const keys = Object.keys(person);
# Object management
// Adding or changing an object property
Object.defineProperty(object, property, descriptor)
// Adding or changing object properties
Object.defineProperties(object, descriptors)
// Accessing a Property
Object.getOwnPropertyDescriptor(object, property)
// Accessing Properties
Object.getOwnPropertyDescriptors(object)
// Returns all properties as an array
Object.getOwnPropertyNames(object)
// Accessing the prototype
Object.getPrototypeOf(object)
# Object protection
// Prevents adding properties to an object
Object.preventExtensions(object)
// Returns true if properties can be added to an object
Object.isExtensible(object)
// Prevents changes of object properties (not values)
Object.seal(object)
// Returns true if object is sealed
Object.isSealed(object)
// Prevents any changes to an object
Object.freeze(object)
// Returns true if object is frozen
Object.isFrozen(object)
# Object defineProperty()
// Create an Object:
const person = {
firstName: "John",
lastName : "Doe",
language : "NO",
};
// Change a Property:
Object.defineProperty(person, "language", {
value: "EN",
writable : true,
enumerable : true,
configurable : true
});
// Enumerate Properties
let txt = "";
for (let x in person) {
txt += person[x] + "<br>";
}
// Display Properties
document.getElementById("demo").innerHTML = txt;
# Function bind()
const person = {
firstName:"John",
lastName: "Doe",
fullName: function () {
return this.firstName + " " + this.lastName;
}
}
const member = {
firstName:"Hege",
lastName: "Nilsen",
}
let fullName = person.fullName.bind(member);