全等操做符比较两个值是否相等,两个被比较的值在比较前都不进行隐式转换。若是两个被比较的值具备不一样的类型,这两个值是不全等的。不然,若是两个被比较的值类型相同,值也相同,而且都不是 number 类型时,两个值全等。最后,若是两个值都是 number 类型,当两个都不是 NaN,而且数值相同,或是两个值分别为 +0 和 -0 时,两个值被认为是全等的。javascript
相等操做符比较两个值是否相等,在比较前将两个被比较的值转换为相同类型。在转换后(等式的一边或两边均可能被转换),最终的比较方式等同于全等操做符 === 的比较方式。 相等操做符知足交换律。java
Object.is =function(x,y){
if(x === y){
// +0,-0状况处理
return x !==0 || 1/x ===1/y;
}else{
//NaN
return x !== x && y!==y;
}
}复制代码
typeof只有一个实际应用场景,就是用来检测一个对象是否已经定义或者是否已经赋值。node
instanceof运算符能够用来判断某个构造函数的prototype属性是否存在于另一个要检测对象的原型链上。 nginx
function _instanceOf(left,right){
let prototype =right.prototype;
obj = left.__proto__;
while(true){
if(obj === null) return false;
if(obj === prototype) return true;
obj = obj.__proto__;
}
}
function Person(){
this.name = "first";
}
let person = new Person();
console.log(_instanceOf(person,Person));复制代码
Object.prototype.toString.call() 经常使用于判断浏览器内置对象时。
web
const an = ['Hello','An'];
an.toString(); // "Hello,An"
Object.prototype.toString.call(an); // "[object Array]"
Object.prototype.toString.call('An') // "[object String]"
Object.prototype.toString.call(1) // "[object Number]"
Object.prototype.toString.call(Symbol(1)) // "[object Symbol]"
Object.prototype.toString.call(null) // "[object Null]"
Object.prototype.toString.call(undefined) // "[object Undefined]"
Object.prototype.toString.call(function(){}) // "[object Function]"
Object.prototype.toString.call({name: 'An'}) // "[object Object]"复制代码
功能:用来判断对象是否为数组算法
instanceof 与 isArray 当检测Array实例时,Array.isArray 优于 instanceof ,由于 Array.isArray 能够检测出 iframesjson
var iframe = document.createElement('iframe');
document.body.appendChild(iframe);
xArray = window.frames[window.frames.length-1].Array;
var arr = new xArray(1,2,3); // [1,2,3]
// Correctly checking for Array
Array.isArray(arr); // true
Object.prototype.toString.call(arr); // true
// Considered harmful, because doesn't work though iframes arr instanceof Array; // false 复制代码
在 JS 中,存在着 6 种原始值,分别是:跨域
一、boolean 二、null 三、undefined 四、number 五、string 六、symbol数组
首先原始类型存储的都是值,是没有函数能够调用的。
浏览器
对象类型和原始类型不一样的是,原始类型存储的是值,对象类型存储的是地址(指针)。当你建立了一个对象类型的时候,计算机会在内存中帮咱们开辟一个空间来存放值,可是咱们须要找到这个空间,这个空间会拥有一个地址(指针)。
1)字面量的方式
var box={
name:'苏',
age:22,
run:function(){
return this.name+this.age
}
}复制代码
2)new 方法:
var box = new object();
box.name = '苏';
box.age =22;
//缺点:想建立相似的对象,即属性,方法名相同可是值不相同的对象,就须要写不少代码。复制代码
建立一个新对象。
这个新对象会被执行[[原型]]链接。
属性和方法被加入到 this 引用的对象中。并执行了构造函数中的方法.
若是函数没有返回其余对象,那么this指向这个新对象,不然this指向构造函数中返回的对象。
function new(func){
let target ={};
target.__proto__ = func.prototype;
let res = func.call(target);
if(res &&typeof(res) =="object" || typeof(res) =="function"){
return res;
}
return target;
}复制代码
function createObjet(name ,age){
var obj = new Object();
obj.name = name;
obj.age = age;
obj.run = function (){
return this.name + this.age;
}
return obj;
}
var a = createObjet('lao',22);
//缺点:没有办法判断对象的来源,即没法判断出对象是谁建立出来的实例。存在识别问题。复制代码
function Box(name,age){
this.name = name;
this.age = age;
this.run = function(){
return this.name + this.age;
}
}
var a = new Box('lao',22);复制代码
优势:解决了识别问题,即建立每一个实例对象都是这个Box的实例。
缺点:经过构造函数建立对象的时候,当一个构造函数被实例化屡次后,构造函数中的方法也会被实例化屡次,同一类型的不一样对象之间并不共用同一个函数,形成内存浪费。
var a = new Box('11',22);
var b = new Box('11',22);
a.run() == b.run();//true;
a.run = b.run //false;引用地址不一样复制代码
function Box(){};
Box.prototype={
constructor:Box, //强制转到Box
name:'11',
age:22,
run:function(){
return this.name+this.age;
}
}复制代码
缺点:没有办法传参。可在实例里来添加或覆盖原型属性:
特色:原型里的属性和方法都是共享的。
function Box(name,age){
this.name=name;
this.age=age;
}
Box.prototype.run=function(){
return this.name+this.age;
}复制代码
方式:须要传参的实例属性用构造函数,须要共享的方法用原型模式。
缺点:无论是否调用了原型里的方法,在建立实例对象时,都会对方法进行初始化。
浅拷贝只会将对象的各个属性进行依次复制,并不会进行递归复制,也就是说只会赋值目标对象的第一层属性。 对于目标对象第一层为基本数据类型的数据,就是直接赋值,即「传值」; 而对于目标对象第一层为引用数据类型的数据,就是直接赋存于栈内存中的堆内存地址,即「传址」。
深拷贝不一样于浅拷贝,它不仅拷贝目标对象的第一层属性,而是递归拷贝目标对象的全部属性。 通常来讲,在JavaScript中考虑复合类型的深层复制的时候,每每就是指对于 Date 、Object 与 Array 这三个复合类型的处理。
一、经过 JSON.parse(JSON.stringify(object)) 来解决
会忽略 undefined
会忽略 symbol
不能序列化函数
不能解决循环引用的对象
二、递归实现
function deepCopy(obj1) {
var obj2 = Array.isArray(obj1) ? [] : {};
if (obj1 && typeof obj1 === "object") {
for (var i in obj1) {
if (obj1.hasOwnProperty(i)) {
// 若是子属性为引用数据类型,递归复制
if (obj1[i] && typeof obj1[i] === "object") {
obj2[i] = deepCopy(obj1[i]);
} else {
// 若是是基本数据类型,只是简单的复制
obj2[i] = obj1[i];
}
}
}
}
return obj2;
}
var obj1 = {
a: 1,
b: 2,
c: {
d: 3
}
}
var obj2 = deepCopy(obj1);
obj2.a = 3;
obj2.c.d = 4;
alert(obj1.a); // 1
alert(obj2.a); // 3
alert(obj1.c.d); // 3
alert(obj2.c.d); // 4复制代码
闭包就是指有权访问另外一个函数做用域中的变量的函数。
function func(){
var a=1,b=2;
function closure(){
return a+b;
}
return closure;
}复制代码
一般,函数的做用域及其全部变量都会在函数执行结束后被销毁。可是,在建立了一个闭包之后,这个函数的做用域就会一直保存到闭包不存在为止。 在javascript中,若是一个对象再也不被引用,那么这个对象就会被垃圾回收机制回收;
闭包只能取得包含函数中任何变量的最后一个值,这是由于闭包所保存的是整个变量对象,而不是某个特殊的变量。
obj.getName()()其实是在全局做用域中调用了匿名函数,this指向了window。这里要理解函数名与函数功能(或者称函数值)是分割开的,不要认为函数在哪里,其内部的this就指向哪里。匿名函数的执行环境具备全局性,所以其 this 对象一般指向 window。
var name = "The Window";
var obj = {
name: "My Object",
getName:function(){
return function(){
return this.name;
};
}
};
console.log(obj.getName()());复制代码
一、应用闭包的主要场合是:设计私有的方法和变量。
二、模块模式:为单例建立私有变量和方法。
匿名函数最大的用途是建立闭包,而且还能够构建命名空间,以减小全局变量的使用。从而使用闭包模块化代码,减小全局变量的污染。
三、函数做为返回值
四、函数做为参数传递
闭包的缺点就是常驻内存会增大内存使用量,而且使用不当很容易形成内存泄露。
若是不是由于某些特殊任务而须要闭包,在没有必要的状况下,在其它函数中建立函数是不明智的,由于闭包对脚本性能具备负面影响,包括处理速度和内存消耗。
内存泄漏指因为疏忽或错误形成程序未能释放已经再也不使用的内存。内存泄漏并不是指内存在物理上的消失,而是应用程序分配某段内存后,因为设计错误,致使在释放该段内存以前就失去了对该段内存的控制,从而形成了内存的浪费。
1.console.log()
2.闭包
3.意外的全局变量
柯里化是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,而且返回接受余下的参数并且返回结果的新函数的技术。
function check(reg,txt){
return reg.test(txt);
}
check(/\d+/g,'test'); //false
check*(/[a-z]+/g,'test'); //true
function curryingCheck(reg){
return function(txt){
return reg.test(txt);
}
}
var hasNumber = curryingCheck(/\d+/g);
var hasLetter = curryingCheck(/[a-z]+/g);
hasNumber('test1');//true
hasNumber('testtest');//false
hasLetter('212222')//flase复制代码
function.prototype.bing = function(context){
var _this = this;
var args = Array.prototype.slice.call(arguments,1)
return function(){
return _this.apply(context,args);
}
}复制代码
function add(){
//第一次执行时,定义一个数组专门用来存储全部的参数
var _args = Array.prototype.slice.call(arguments);
//在内部声明一个函数,利用闭包的特性保存_args并收集全部的参数值。
var _adder = function(){
_args.push(...arguments);
return _adder;
};
//利用toString隐式转换的特性,当最后执行隐式转换,并计算最终返回的值
_adder.toString = function(){
return _args.reduce(function(a,b){
return a+b;
});
}
return _adder;
}
add(1)(2)(3);
add(1,2,3)(4);
add(1)(2)(3)(4)(5);复制代码
在新生代空间中,内存空间分为两部分,分别为 From 空间和 To 空间。在这两个空间中,一定有一个空间是使用的,另外一个空间是空闲的。新分配的对象会被放入 From 空间中,当 From 空间被占满时,新生代 GC 就会启动了。算法会检查 From 空间中存活的对象并复制到 To 空间中,若是有失活的对象就会销毁。当复制完成后将 From 空间和 To 空间互换,这样 GC 就结束了。
老生代中的对象通常存活时间较长且数量也多,使用了两个算法,分别是标记清除算法和标记压缩算法。
一、新生代中的对象是否已经经历过一次 Scavenge 算法,若是经历过的话,会将对象重新生代空间移到老生代空间中。 二、To 空间的对象占比大小超过 25 %。在这种状况下,为了避免影响到内存分配,会将对象重新生代空间移到老生代空间中。 老生代中的空间很复杂,有以下几个空间 在老生代中,如下状况会先启动标记清除算法: (1)某一个空间没有分块的时候 (2)空间中被对象超过必定限制 (3)空间不能保证新生代中的对象移动到老生代中 在这个阶段中,会遍历堆中全部的对象,而后标记活的对象,在标记完成后,销毁全部没有被标记的对象。在标记大型对内存时,可能须要几百毫秒才能完成一次标记。这就会致使一些性能上的问题。 清除对象后会形成堆内存出现碎片的状况,当碎片超过必定限制后会启动压缩算法。在压缩过程当中,将活的对象像一端移动,直到全部对象都移动完成而后清理掉不须要的内存。
原则:this 永远指向最后调用它的那个对象。
箭头函数的 this 始终指向函数定义时的 this,而非执行时。箭头函数须要记着这句话:“箭头函数中没有 this 绑定,必须经过查找做用域链来决定其值,若是箭头函数被非箭头函数包含,则 this 绑定的是最近一层非箭头函数的 this,不然,this 为 undefined”。
apply传递数组,call传递参数,而bind改变this指向的时候返回的是一个函数。而apply、call是当即执行。
call模拟实现
Function.prototype.call =function(context){
context = context? Object(context): window;
context.fn = this;//this也就是调用call的函数
let args = [...argments].slice(1);
let r = context.fn(...args);
delete context.fn;
return r;
}复制代码
apply模拟实现
Function.prototype.apply = function(context,args){
context = context? Object(context): window;//不传递context默认为window
context.fn = this;
if(!args){
return context.fn();
}
let r = context.fn(...args);
delete context.fn;
return r;
}复制代码
bind模拟实现
Function.prototype.bind = function(context){
const _this = this;
const argus = Array.prototype.slice.apply(argments,[1]) //拿到除了context以外的预置参数序列
return function(){
_this.apply(context,argus.concat(Array.prototype.slice.call(argments)))
//绑定this同时将调用时传递的序列和预置序列进行合并
}
}复制代码
//方法一
function ArrayFlat(arr){
let a = [];
arr.forEach(item){
if(Array.isArray(item)){
ArrayFlat(item);
}else{
a.push(item);
}
}
return a;
}
//方法二
var a = arr.toString.split(',');
for(var i=0;i<a.length;i++){
a[i] =eval(arr[i]);
}复制代码
let arr =[1,2,3,22,233,22,2,233,'a',3,'b','a'];
Array.prototype.unique = function(){
const newArray = [];
this.forEach(item =>{
if(newArray.indexOf(item)===-1){
newArray.push(item);
}
});
return newArray;
}复制代码
Array.prototype.unique = function(){
return [...new Set(this)];
}复制代码
Array.prototype.unique =function(){
const newArray=[];
let isRepeat;
for(let i=0;i<this.length;i++){
isRepeat =false;
for(let j=i+1;i<this.length;j++){
if(this[i]===this[j]){
isRepeat = true;
break;
}
}
if(!isRepeat){
newArray.push(this[i]);
}
}
return newArray;
}复制代码
function reduce(param,callback ,initVal){
var hasInitVal = initVal !== void 0;
var acc =hasInitVal ? initVal: param[0];
each(hasInitVal? param:Array.prototype.slice.call(param,1),function(v,k,o){
acc = callback(acc,v,k,o);
});
return acc;
}复制代码
// ES5 的写法
Math.max.apply(null, [14, 3, 77, 30]);
// ES6 的写法
Math.max(...[14, 3, 77, 30]);
// reduce
[14,3,77,30].reduce((accumulator, currentValue)=>{
return accumulator = accumulator > currentValue ? accumulator : currentValue
});复制代码
具备 iterator 接口,就能够用for...of循环遍历它的成员(属性值)。for...of循环可使用的范围包括数组、Set 和 Map 结构、某些相似数组的对象、Generator 对象,以及字符串。
function* generator(){
yield 1;
yield 2;
yield 3;
};
for (const g of generator()) {
console.log(g);
}复制代码
遍历对象自身的和继承的可枚举的属性, 不能直接获取属性值。能够中断循环。
只能遍历数组,不能中断,没有返回值(或认为返回值是undefined)。
[].forEach(function(value, index, array) {
// ...
});复制代码
只能遍历数组,不能中断,返回值是修改后的数组。
[].map(function(value, index, array) {
// ...
});复制代码
var ages = [32, 33, 16, 40];
function checkAdult(age) {
return age >= 18;
}
function myFunction() {
document.getElementById("demo").innerHTML = ages.filter(checkAdult);
}复制代码
var scores = [5,8,3,10];
var current = 7;
function higherThanCurrent(score){
return score > current;
}
if(scores.some(higherThanCurrent)){
alert(1);
}复制代码
if(scroes.every(higherThanCurrent)){
console.log(1);
}else{
console.log(2);
}复制代码
var sum = [1, 2, 3, 4].reduce(function (previous, current, index, array) {
return previous + current;
});
console.log(sum); // 10复制代码
一、原型链继承
function Parent(name){
this.name = name;
}
function Child(name){
this.name = name;
}
Parent.prototype.sayName = function(){
console.log('parent name:',this.name);
}
Child.protoType = new Parent('father');
Child.protoType.constructor = Child;
Child.protoType.sayName = function(){
console.log('child name:',this.name);
}
var child = new Child('son');
child.sayName();
//此种继承的缺点:子类没法给父类传递参数,而且Child.protoType 要写在new Parent后面
二、构造函数继承
function Parent(name){
this.name = name;
}
Parent.protoType.sayName = function(){
console.log('parent name:',this.name);
}
Parent.protoType.doSomeThing = function(){
console.log('parent doSomeThing');
}
function Child(name,fatherName){
Parent.call(this,faterName);
this.name = name;
}
Child.protoType.sayNmae = function(){
console.log('child name:',this.name);
}
var child = new Child('son','father');
child.sayName();
child.doSomeThing();
//此方案的缺点:没有原型,每次建立一个Child实例对象的时候都要执行一遍Parent函数
三、组合式继承
function Parent(name){
this.name = name;
}
Parent.protoType.sayName = function(){
console.log('parent name:',this.name);
}
Parent.protoType.doSomeThing = function(){
console.log('parent doSomeThing');
}
function Child(name,fatherName){
Parent.call(this,faterName);
this.name = name;
}
Child.protoType = Parent.protoType;
Child.protoType.constructor = Child;
Child.protoType.sayNmae = function(){
console.log('child name:',this.name);
}
var child = new Child('son');
child.sayName();
child.doSomeThing();
//经过原型链实现对象属性和方法的继承,而经过构造函数来实现实例属性的继承。
四、寄生组合继承
function Parent(name){
this.name = name;
}
Parent.protoType.sayName = function(){
console.log('parent name:',this.name);
}
Parent.protoType.doSomeThing = function(){
console.log('parent doSomeThing');
}
function Child(name,fatherName){
Parent.call(this,faterName);
this.name = name;
}
function create(proto){
function F(){}
F.proto=proto;
return new F();
}
Child.protoType = create(Parent.protoType);
Child.protoType.sayNmae = function(){
console.log('child name:',this.name);
}
Child.protoType.constructor = Child;
//用F(){}去替代父类执行构造函数
五、ES6继承
Class Parent{
constructor(name){
this.name = name;
}
doSomething(){
console.log('parent do sometthing!');
}
sayName(){
console.log('parent name:',this.name);
}
}
class Child extend Parent{
constructor(name,parentName){
super(parentName);
this.name =name;
}
sayName(){
console.log('child name:',this.name);
}
}
//ES6继承 复制代码
同源策略:端口、域名、协议
JSONP优势是简单兼容性好,可用于解决主流浏览器的跨域数据访问的问题。缺点是仅支持get方法具备局限性,不安全可能会遭受XSS攻击。
(1)声明一个回调函数,其函数名(如show)当作参数值,要传递给跨域请求数据的服务器,函数形参为要获取目标数据(服务器返回的data)。
(2)建立一个<script>标签,把那个跨域的API数据接口地址,赋值给script的src,还要在这个地址中向服务器传递该函数名(能够经过问号传参:?callback=show)。
(3)服务器接收到请求后,须要进行特殊的处理:把传递进来的函数名和它须要给你的数据拼接成一个字符串,例如:传递进去的函数名是show,它准备好的数据是show('我不爱你')。
(4)最后服务器把准备的数据经过HTTP协议返回给客户端,客户端再调用执行以前声明的回调函数(show),对返回的数据进行操做。 在开发中可能会遇到多个 JSONP 请求的回调函数名是相同的,这时候就须要本身封装一个 JSONP函数。
服务端设置 Access-Control-Allow-Origin 就能够开启 CORS。 该属性表示哪些域名能够访问资源,若是设置通配符则表示全部网站均可以访问资源。
(1)页面和其打开的新窗口的数据传递
(2)多窗口之间消息传递
(3)页面与嵌套的iframe消息传递
实现原理:同源策略是浏览器须要遵循的标准,而若是是服务器向服务器请求就无需遵循同源策略。 代理服务器,须要作如下几个步骤:
接受客户端请求 。
将请求 转发给服务器。
拿到服务器 响应 数据。
将 响应 转发给客户端。
实现原理相似于Node中间件代理,须要你搭建一个中转nginx服务器,用于转发请求。
防抖(debounce) 所谓防抖,就是指触发事件后在 n 秒内函数只能执行一次,若是在 n 秒内又触发了事件,则会从新计算函数执行时间。
function debounce(func,wait){
let timeout;
return function(){
let context = this;
let args = arguments;
if(timeout) clearTimeout(timeout);
timeout = setTimeout(()=>{
func.apply(context,args)
},wait);
}
}复制代码
节流(throttle) 所谓节流,就是指连续触发事件可是在 n 秒中只执行一次函数。 节流会稀释函数的执行频率。
function throttle(func,wait){
var previous = 0;
return fucntion(){
let now = Date.now();
let context = this;
let args = arguments;
if(now -previous > wait){
func.apply(context,args);
previous = now;
}
}
}复制代码
一、在对象中声明相同的属性名
二、在函数声明中相同的参数名
三、不能用前导0声明8进制直接量
四、不能从新声明、删除或重写eval和arguments这两个标示符
五、用delete删除显示声明的标识符、名称和具名函数
六、代码中使用扩展的保留字,例如 interface,let,yield,package,private等
七、严格模式下是禁止使用with的
宏任务:包括总体代码script,setTimeout,setInterval
微任务:Promise.then(非new Promise),process.nextTick(node中)
事件的执行顺序,是先执行宏任务,而后执行微任务,这个是基础,任务能够有同步任务和异步任务,同步的进入主线程,异步的进入Event Table并注册函数,异步事件完成后,会将回调函数放入Event Queue中(宏任务和微任务是不一样的Event Queue),同步任务执行完成后,会从Event Queue中读取事件放入主线程执行,回调函数中可能还会包含不一样的任务,所以会循环执行上述操做。
1.捕获阶段 (即由根节点流向子节点,检测每一个节点是否注册了监听器)
2.目标阶段 (激发在目标对象自己注册的监听程序)
3.冒泡阶段 (从目标节点到根节点,检测每一个节点是否注册了监听器)。事件流在此阶段触发
w3c方法是e.stopPropation()
IE中方法是window.event.cancelBubble = true
w3c方法是e.preventDefault
IE中方法是window.event.returnValue = false
Load 事件触发表明页面中的 DOM,CSS,JS,图片已经所有加载完毕。
DOMContentLoaded 事件触发表明初始的 HTML 被彻底加载和解析,不须要等待 CSS,JS,图片加载。
先触发DOMContentLoaded事件,后触发load事件。
与setTimeout相比,requestAnimationFrame最大的优点是由系统来决定回调函数的执行时机。具体一点讲,若是屏幕刷新率是60Hz,那么回调函数就每16.7ms被执行一次,若是刷新率是75Hz,那么这个时间间隔就变成了1000/75=13.3ms,换句话说就是,requestAnimationFrame的步伐跟着系统的刷新步伐走。它能保证回调函数在屏幕每一次的刷新间隔中只被执行一次,这样就不会引发丢帧现象,也不会致使动画出现卡顿的问题。
//window.onload函数在页面全部内容加载完成后触发,只能执行最后一个window.onload函数
$(window).load(function(){ //等价于window.onload = function
alert("加载完成");
});
//ready函数在DOM树加载完成后触发,能够同时执行多个ready函数。
$(document).ready(function(){
//$(document)能够简写成$(), $(document).ready函数能够简写成$(function(){})
alert("加载完成");
});复制代码
默认排序顺序是根据字符串UniCode码。
由于排序是按照字符串UniCode码的顺序进行排序的,因此首先应该把数组元素都转化成字符串(若有必要),以便进行比较。
js中substr和substring都是截取字符串中子串,很是相近,能够有一个或两个参数。
语法:substr(start [,length]) 第一个字符的索引是0,start必选 length可选
substring(start [, end]) 第一个字符的索引是0,start必选 end可选
children是Element的属性,childNodes是Node的属性
1 var func =function(){} ,即和 var 变量的特性 同样。 func 变量名提早,可是不会初始化,直到执行到初始化代码。
2 function func(){} 变量名 和方法体 都会提早到 顶部执行。
(1)同源限制
分配给 Worker 线程运行的脚本文件,必须与主线程的脚本文件同源。
(2)DOM 限制
Worker 线程所在的全局对象,与主线程不同,没法读取主线程所在网页的 DOM 对象,也没法使用document
、window
、parent
这些对象。可是,Worker 线程能够navigator
对象和location
对象。
(3)通讯联系
Worker 线程和主线程不在同一个上下文环境,它们不能直接通讯,必须经过消息完成。
(4)脚本限制
Worker 线程不能执行alert()
方法和confirm()
方法,但可使用 XMLHttpRequest 对象发出 AJAX 请求。
(5)文件限制
Worker 线程没法读取本地文件,即不能打开本机的文件系统(file://
),它所加载的脚本,必须来自网络。
Object.create()方法接受两个参数:Object.create(obj,propertiesObject) ;
{}继承自Object;
function newOperator(ctor){
if(typeof ctor !== 'function'){
throw 'newOperator function the first param must be a function';
}
// ES6 new.target 是指向构造函数
newOperator.target = ctor;
// 1.建立一个全新的对象,
// 2.而且执行[[Prototype]]连接
// 4.经过`new`建立的每一个对象将最终被`[[Prototype]]`连接到这个函数的`prototype`对象上。
var newObj = Object.create(ctor.prototype);
// ES5 arguments转成数组 固然也能够用ES6 [...arguments], Aarry.from(arguments);
// 除去ctor构造函数的其他参数
var argsArr = [].slice.call(arguments, 1);
// 3.生成的新对象会绑定到函数调用的`this`。
// 获取到ctor函数返回结果
var ctorReturnResult = ctor.apply(newObj, argsArr);
// 小结4 中这些类型中合并起来只有Object和Function两种类型 typeof null 也是'object'因此要不等于null,排除null
var isObject = typeof ctorReturnResult === 'object' && ctorReturnResult !== null;
var isFunction = typeof ctorReturnResult === 'function';
if(isObject || isFunction){
return ctorReturnResult;
}
// 5.若是函数没有返回对象类型`Object`(包含`Functoin`, `Array`, `Date`, `RegExg`, `Error`),那么`new`表达式中的函数调用会自动返回这个新的对象。
return newObj;
}复制代码
var array = [10,34,57,43,76];
var res = array.forEach(function (item,index,input) {
input[index] = item*10;
})
console.log(res);//--> undefined;
console.log(array);//--> 经过数组索引改变了原数组;复制代码
var array = [10,34,57,43,76];
var res = array.map(function (item,index,input) {
return item*10;
})
console.log(res);
console.log(array);//不变复制代码
浏览器如今支持Fetch API,能够无须其余库就能实现Ajax,Fetch你想获取资源,Fetch会返回Promise,因此在获取资源后,可使用.then方法作你想作的。
第一个参数是设置请求方法(如post、put或del),Fetch会自动设置方法为get。
第二个参数是设置头部。由于通常使用JSON数据格式,因此设置ContentType为application/json。
第三个参数是设置包含JSON内容的主体。由于JSON内容是必须的,因此当设置主体时会调用JSON.stringify。
function query(string) {
// console.log(string) // http://www.baidu.com?a=1&b=2&c=3
let arr=string.split("?") //截取字符,变为伪数组
// console.log(arr) // ["http://www.baidu.com", "a=1&b=2&c=3"]
let arr1=arr[1].split("&"); //截取字符,变为伪数组
// console.log(arr1) // ["a=1", "b=2", "c=3"]
let obj={}
for (let i=0;i<arr1.length;i++){ //便利数组
// console.log(i) //0 1 2
let arr2=arr1[i].split("=") //截取arr1下面的每一个=
// console.log(arr2) ["a", "1"] ["b", "2"] ["c", "3"]
if(arr2[0].indexOf("[")!= -1){
let arr3 =arr2[0].split("[")
if(obj.hasOwnProperty(arr3[0])){
obj[arr3[0]].push(arr2[1]);
}else{
obj[arr3[0]] = [];
obj[arr3[0]].push(arr2[1]);
}
}else{
obj[arr2[0]]=arr2[1] //让obj[arr2数组下的每一个下标为0的]=arr2的数组下的每一个下标为1的
}
}
console.log(obj) //{a: "1", b: "2", c: "3"}
console.log( typeof obj) //object
return obj
}复制代码
var jsonStudents = [
{name:"Dawson", totalScore:"197", Chinese:"100",math:"97"},
{name:"HanMeiMei", totalScore:"196",Chinese:"99", math:"97"},
{name:"LiLei", totalScore:"185", Chinese:"88", math:"97"},
{name:"XiaoMing", totalScore:"196", Chinese:"96",math:"100"},
{name:"Jim", totalScore:"196", Chinese:"98",math:"98"},
{name:"Joy", totalScore:"198", Chinese:"99",math:"99"}];
jsonStudents.sort(function(a,b){
var value1 = a.totalScore,
value2 = b.totalScore;
if(value1 === value2){
return b.Chinese - a.Chinese;
}
return value2 - value1;
});复制代码
LazyMan('Tony');
// Hi I am Tony
LazyMan('Tony').sleep(10).eat('lunch');
// Hi I am Tony
// 等待了10秒...
// I am eating lunch
LazyMan('Tony').eat('lunch').sleep(10).eat('dinner');
// Hi I am Tony
// I am eating lunch
// 等待了10秒...
// I am eating diner
LazyMan('Tony').eat('lunch').eat('dinner').sleepFirst(5).sleep(10).eat('junk food');
// Hi I am Tony
// 等待了5秒...
// I am eating lunch
// I am eating dinner
// 等待了10秒...
// I am eating junk food
class LazyManClass {
constructor(name) {
this.taskList = [];
this.name = name;
console.log(`Hi I am ${this.name}`);
setTimeout(() => {
this.next();
}, 0);
}
eat (name) {
var that = this;
var fn = (function (n) {
return function () {
console.log(`I am eating ${n}`)
that.next();
}
})(name);
this.taskList.push(fn);
return this;
}
sleepFirst (time) {
var that = this;
var fn = (function (t) {
return function () {
setTimeout(() => {
console.log(`等待了${t}秒...`)
that.next();
}, t * 1000);
}
})(time);
this.taskList.unshift(fn);
return this;
}
sleep (time) {
var that = this
var fn = (function (t) {
return function () {
setTimeout(() => {
console.log(`等待了${t}秒...`)
that.next();
}, t * 1000);
}
})(time);
this.taskList.push(fn);
return this;
}
next () {
var fn = this.taskList.shift();
fn && fn();
}
}
function LazyMan(name) {
return new LazyManClass(name);
}
LazyMan('Tony').eat('lunch').eat('dinner').sleepFirst(5).sleep(4).eat('junk food');复制代码