var arr = [1, 2, 2];
arr.indexOf(1); //0
arr.indexOf(10); //-1
复制代码
var arr = [1, 2, 2];
arr.lastIndexOf(2); //2
arr.lastIndexOf(10); //-1
复制代码
与字符串的substring()方法同样,截取数组的一部分,返回一个新的数组。html
var arr = [1, 2, 2, 5, 6];
arr.slice(2) // [2, 5, 6]
复制代码
var arr = [1, 2, 2, 5, 6];
arr.slice(1,3) // [2, 2]
复制代码
var arr = [1, 2, 2, 5, 6];
arr.slice();
复制代码
把当前的数组和另外一个数组链接起来,并返回一个新的数组。es6
var arr1 = [1, 2, 3,4,5,6];
var arr2 = ['a','b','c'];
var arr3 = arr1.concat(arr2);
arr3; //[1, 2, 3, 4, 5, 6, "a", "b", "c"]
复制代码
var arr1 = [1, 2, 3];
var arr2 = arr1.concat(66,'abc',true,[10,20],[30,[31,32]],{x:100});
arr2; //[1, 2, 3, 66, "abc", true, 10, 20, 30, [31,32], {x:100}]
复制代码
它会把当前Array的每一个元素都用指定的字符串链接起来,而后返回链接后的字符串。数组
var arr = [1, 2, 3];
arr.join('*') //"1*2*3"
复制代码
var arr = [1, 2, 3];
arr.join() //"1,2,3"
复制代码
var arr = [1, 2, 3];
arr.toString() // "1,2,3"
复制代码
var arr = [1, 2, 3];
arr.valueOf() // [1, 2, 3]
复制代码
arr.map(function(elem, index, arr) {
return elem * index;
});
//[0, 2, 6]
复制代码
arr.map(function(elem, index, arr) {
return elem * index;
});
//[0, 2, 6]
复制代码
与map方法很类似,也是遍历数组的全部成员,执行某种操做。注意:forEach方法通常没有返回值浏览器
var arr = [1, 2, 3];
function log(element, index, array) {
console.log('[' + index + '] = ' + element);
}
arr.forEach(log);
// [0] = 1
// [1] = 2
// [2] = 3
复制代码
var arr = [1, 2, 3, 4, 5];
arr.filter(function (elem, index, arr) {
return index % 2 === 1;
});
//[2, 4]
复制代码
相似“断言”(assert),用来判断数组成员是否符合某种条件。bash
var arr = [1, 2, 3, 4];
arr.some(function (elem, index, arr) {
return elem >= 3;
});
// true
复制代码
var arr = [1, 2, 3, 4];
arr.every(function (elem, index, arr) {
return elem >= 3;
});
// false
复制代码
依次处理数组的每一个成员,最终累计为一个值。闭包
arr = [1, 2, 3]
arr.reduce(function(x, y){
console.log(x, y)
return x + y;
});
// 1 2
// 3 3
// 6
复制代码
rr.reduceRight(function(x, y){
console.log(x, y)
return x + y;
});
// 3 2
// 5 1
// 6
复制代码
向数组的末尾添加若干元素。返回值是改变后的数组长度。app
var arr = [1, 2];
arr.push(3) ;// 3
arr; // [1, 2, 3]
arr.push('b','c'); //5
arr; //[1, 2, 3, "b", "c"]
arr.push([10,20]); //6
arr; //[1, 2, 3, "b", "c", [10,20]]
复制代码
删除数组最后一个元素。返回值是删除的元素。函数
var arr =[1, 2, 3, "b", "c", [10,20]];
arr.pop(); //[10, 20]
arr; // [1, 2, 3, "b", "c"]
复制代码
向数组头部添加若干元素。返回值是改变后的数组长度。ui
var arr = [1, 2];
arr.unshift(3,4 ); //4
arr; // [3, 4, 1, 2]
复制代码
删除数组第一个元素。返回值是删除的元素this
var arr = ['a', 'b', 1, 2];
arr.shift(); //'a'
arr; //['b', 1, 2]
复制代码
数组排序。
var arr = [1, 2, 12, 'a', 'b', 'ab', 'A', 'B']
arr.sort(); //[1, 12, 2, "A", "B", "a", "ab", "b"] 注意:12排在了2的前面
复制代码
var arr = [1, 2, 12, 100]
arr.sort(function(a,b){
return a-b;
});
// [1, 2, 12, 100]
复制代码
颠倒数组中元素的位置
var arr = [1, 2, 12, 'a', 'b', 'ab', 'A', 'B'];
arr.reverse();
//["B", "A", "ab", "b", "a", 12, 2, 1]
复制代码
array.splice(start[, deleteCount[, item1[, item2[, ...]]]])
若是 deleteCount 大于 start 以后的元素的总数,则从 start 后面的元素都将被删除(含第 start 位)。 若是 deleteCount 被省略了,或者它的值大于等于array.length - start(也就是说,若是它大于或者等于start以后的全部元素的数量),那么start以后数组的全部元素都会被删除。 若是 deleteCount 是 0 或者负数,则不移除元素。这种状况下,至少应添加一个新元素
var arr = ['Alibaba', 'Tencent', 'Baidu', 'XiaoMi', '360'];
// 从索引2开始删除3个元素
arr.splice(2, 3); // 返回删除的元素 ['Baidu', 'XiaoMi', '360']
arr; // ['Alibaba', 'Tencent']
复制代码
arr.splice(2, 0, 'Toutiao', 'Meituan', 'Didi'); // 返回[],由于没有删除任何元素
arr; //["Alibaba", "Tencent", "Toutiao", "Meituan", "Didi"]
复制代码
var arr =["Alibaba", "Tencent", "Toutiao", "Meituan", "Didi"]
arr.splice(2,2,'Apple','Google'); //["Toutiao", "Meituan"]
arr; //["Alibaba", "Tencent", "Apple", "Google", "Didi"]
复制代码
参考:developer.mozilla.org/zh-CN/docs/… 函数的调用方式决定了this的值。记住调用方式决定了this的值。this不能在执行期间被赋值,而且在每次函数被调用时this的值也可能会不一样。
不管是否在严格模式下,在全局执行环境中(在任何函数体外部)this 都指向全局对象。
// 在浏览器中, window 对象同时也是全局对象:
console.log(this === window); // true
a = 37;
console.log(window.a); // 37
this.b = "MDN";
console.log(window.b) // "MDN"
console.log(b) // "MDN"
复制代码
function f1(){
return this;
}
//在浏览器中:
f1() === window; //在浏览器中,全局对象是window
//在Node中:
f1() === global;
复制代码
function f2(){
"use strict"; // 这里是严格模式
return this;
}
f2() === undefined; // true
复制代码
call和apply 均可以传递参数,call 是传递多个参数,而apply则传数组传递参数。
// 将一个对象做为call和apply的第一个参数,this会被绑定到这个对象。
var obj = {a: 'Custom'};
// 这个属性是在global对象定义的。
var a = 'Global';
function whatsThis(arg) {
return this.a; // this的值取决于函数的调用方式
}
whatsThis(); // 'Global'
whatsThis.call(obj); // 'Custom'
whatsThis.apply(obj); // 'Custom'
复制代码
ECMAScript 5 引入了 Function.prototype.bind,调用f.bind(someObject)会建立一个与f具备相同函数体和做用域的函数,可是在这个新函数中,this将永久地被绑定到了bind的第一个参数(注意永久绑定到第一个参数上,也就是无论绑定多少次bind,都是指向第一个参数),不管这个函数是如何被调用的。
function f(){
return this.a;
}
var g = f.bind({a:"azerty"});
console.log(g()); // azerty
var h = g.bind({a:'yoo'}); // bind只生效一次!
console.log(h()); // azerty
var o = {a:37, f:f, g:g, h:h};
console.log(o.f(), o.g(), o.h()); // 37, azerty, azerty
复制代码
在箭头函数中,this与封闭词法环境的this保持一致。在全局代码中,它将被设置为全局对象:
var globalObject = this;
var foo = (() => this);
console.log(foo() === globalObject); // true
复制代码
重难点:
// 建立一个含有bar方法的obj对象,
// bar返回一个函数,
// 这个函数返回this,
// 这个返回的函数是以箭头函数建立的,
// 因此它的this被永久绑定到了它外层函数的this。
// bar的值能够在调用中设置,这反过来又设置了返回函数的值。
var obj = {
bar: function() {
var x = (() => this);
return x;
}
};
// 做为obj对象的一个方法来调用bar,把它的this绑定到obj。
// 将返回的函数的引用赋值给fn。
var fn = obj.bar();
// 直接调用fn而不设置this,
// 一般(即不使用箭头函数的状况)默认为全局对象
// 若在严格模式则为undefined
console.log(fn() === obj); // true
// 可是注意,若是你只是引用obj的方法,
// 而没有调用它
var fn2 = obj.bar;
// 那么调用箭头函数后,this指向window,由于它从 bar 继承了this。
console.log(fn2()() == window); // true
复制代码
特别注意的是,当方法是对象里的属性时,若是调用的不是方法 obj.bar()这种形式,而是obj.bar这种形式,后面再去调用的时候,前者的this指向当前对象obj,然后者指向全局对象。根本缘由是因为执行的上下文不同致使的,但愿细细品味。
当函数做为对象里的方法被调用时,它们的 this 是调用该函数的对象。
var o = {
prop: 37,
f: function() {
return this.prop;
}
};
console.log(o.f()); // logs 37
复制代码
请注意,这样的行为,根本不受函数定义方式或位置的影响。
var o = {prop: 37};
function independent() {
return this.prop;
}
o.f = independent;
console.log(o.f()); // logs 37
复制代码
一样,this 的绑定只受最靠近的成员引用的影响。在下面的这个例子中,咱们把一个方法g看成对象o.b的函数调用。在此次执行期间,函数中的this将指向o.b。事实证实,这与他是对象 o 的成员没有多大关系,最靠近的引用才是最重要的。
o.b = {g: independent, prop: 42};
console.log(o.b.g()); // 42
复制代码
即this指向最后一个调用方法的对象
对于在对象原型链上某处定义的方法,一样的概念也适用。若是该方法存在于一个对象的原型链上,那么this指向的是调用这个方法的对象,就像该方法在对象上同样。
var o = {
f: function() {
return this.a + this.b;
}
};
var p = Object.create(o);
p.a = 1;
p.b = 4;
console.log(p.f()); // 5
复制代码
此处p继承自o,可是调用f()方法的是p,则this指向p
再次,相同的概念也适用于当函数在一个 getter 或者 setter 中被调用。用做 getter 或 setter 的函数都会把 this 绑定到设置或获取属性的对象。
function sum() {
return this.a + this.b + this.c;
}
var o = {
a: 1,
b: 2,
c: 3,
get average() {
return (this.a + this.b + this.c) / 3;
}
};
Object.defineProperty(o, 'sum', {
get: sum, enumerable: true, configurable: true});
console.log(o.average, o.sum); // logs 2, 6
复制代码
当一个函数用做构造函数时(使用new关键字),它的this被绑定到正在构造的新对象。
/*
* 构造函数这样工做:
*
* function MyConstructor(){
* // 函数实体写在这里
* // 根据须要在this上建立属性,而后赋值给它们,好比:
* this.fum = "nom";
* // 等等...
*
* // 若是函数具备返回对象的return语句,
* // 则该对象将是 new 表达式的结果。
* // 不然,表达式的结果是当前绑定到 this 的对象。
* //(即一般看到的常见状况)。
* }
*/
function C(){
this.a = 37;
}
var o = new C();
console.log(o.a); // logs 37
function C2(){
this.a = 37;
return {a:38};
}
o = new C2();
console.log(o.a); // logs 38
复制代码
虽然构造器返回的默认值是this所指的那个对象,但它仍能够手动返回其余的对象(若是返回值不是一个对象,则返回this对象)。
对象类型在赋值的过程当中实际上是复制了地址,从而会致使改变了一方其余也都被改变的状况。一般在开发中咱们不但愿出现这样的问题,咱们可使用浅拷贝来解决这个状况。
let a = {
age: 1
}
let b = a
a.age = 2
console.log(b.age) // 2
复制代码
不少人认为这个函数是用来深拷贝的。其实并非,Object.assign 只会拷贝全部的属性值到新的对象中,若是属性值是对象的话,拷贝的是地址,因此并非深拷贝。
let a = {
age: 1
}
let b = Object.assign({}, a)
a.age = 2
console.log(b.age) // 1
复制代码
let a = {
age: 1
}
let b = { ...a }
a.age = 2
console.log(b.age) // 1
复制代码
一般浅拷贝就能解决大部分问题了,可是当咱们遇到以下状况就可能须要使用到深拷贝了
let a = {
age: 1,
jobs: {
first: 'FE'
}
}
let b = { ...a }
a.jobs.first = 'native'
console.log(b.jobs.first) // native
复制代码
浅拷贝只解决了第一层的问题,若是接下去的值中还有对象的话,那么就又回到最开始的话题了,二者享有相同的地址。要解决这个问题,咱们就得使用深拷贝了。
这个问题一般能够经过 JSON.parse(JSON.stringify(object)) 来解决。
let a = {
age: 1,
jobs: {
first: 'FE'
}
}
let b = JSON.parse(JSON.stringify(a))
a.jobs.first = 'native'
console.log(b.jobs.first) // FE
复制代码
可是该方法也是有局限性的:
let obj = {
a: 1,
b: {
c: 2,
d: 3,
},
}
obj.c = obj.b
obj.e = obj.a
obj.b.c = obj.c
obj.b.d = obj.b
obj.b.e = obj.b.c
let newObj = JSON.parse(JSON.stringify(obj))
console.log(newObj)
复制代码
若是你有这么一个循环引用对象,你会发现并不能经过该方法实现深拷贝()
在遇到函数、 undefined 或者 symbol 的时候,该对象也不能正常的序列化
let a = {
age: undefined,
sex: Symbol('male'),
jobs: function() {},
name: 'yck'
}
let b = JSON.parse(JSON.stringify(a))
console.log(b) // {name: "yck"}
复制代码
上述状况中,该方法会忽略掉函数和 undefined 。 深度拷贝的实现方法:
function deepClone(obj) {
function isObject(o) {
return (typeof o === 'object' || typeof o === 'function') && o !== null
}
if (!isObject(obj)) {
throw new Error('非对象')
}
let isArray = Array.isArray(obj)
let newObj = isArray ? [...obj] : { ...obj }
Reflect.ownKeys(newObj).forEach(key => {
newObj[key] = isObject(obj[key]) ? deepClone(obj[key]) : obj[key]
})
return newObj
}
let obj = {
a: [1, 2, 3],
b: {
c: 2,
d: 3
}
}
let newObj = deepClone(obj)
newObj.b.c = 1
console.log(obj.b.c) // 2
复制代码
持续更新中。。。。