初级前端知识点整合-JS部分(持续更新中。。请留意哈)

1.冒泡排序:
只需要比较n-1趟,所以循环次数为数组长度-1。第二层循环,因为比较过后得到的最大元素已经放置再末尾所以不参与比较,故arr.length-1-i

function BubbleSort(arr){
    for(var i=0;i

2.快速排序:
利用二分法和递归实现快速排序。

function quickSort(arr){
    if(arr.length == 0){
        return [];
    }
    //利用Math.floor()方法向下取整找到中间位置
    var cIndex = Math.floor(arr.length / 2);
    //再用splice()方法将数组中间位置的元素取出来
    var c = arr.splice(cIndex,1);
    var l = [],r = [];
    for(var i = 0;i

3.JS基本规范:
不要在同一行声明多个变量,正确写法如下:

var a = 1,
    b = 2,
    c = 3;

建议使用对象字面量的写法替代new Array这种写法:
var arr = [1,2,3,4];
尽量不要使用全局变量;
For循环和IF语句必须使用大括号;
Switch语句必须带有Default分支;
for-in 循环中的变量应该使用Var关键字限定作用域,避免作用域污染

4.JS的基本数据类型
undefined、Null、String、Boolean、Number

5.Js中数组的一些操作
<1>map():遍历数组,返回回调返回值组成的新数组

var arr = [1,2,3,4];
var arr = arr.map(function(item){
    return item * item;
})
console.log(arr);  //[1,4,9,16]

var users = [
 {name:"老王",age: 70},
 {name:"大王",age: 50},
 {name:"小王",age: 30}
];

var ages = users.map(function(user){
    return user.age;
})
console.log(ages);   //[70,50,30]

<2>forEach():遍历数组,但无法break,可以用try catch语句中的throw new Error()来停止

var users = [
 {name:"老王",age: 70},
 {name:"大王",age: 50},
 {name:"小王",age: 30}
];
var names = [];
users.forEach(function (item){
    names.push(item.name);
});
console.log(names);    //["老王", "大王", "小王"]

<3>filter():过滤

var arr = [1,2,3,4,5];
var newArr = arr.filter(function(item){
    return item>3;
});
console.log(newArr); //[4,5]

<4>some():有一项返回true,则整体都为true

var arr = [1,2,3,4,5];
var result = arr.some(function(item){
    return item>4;
});
console.log(result);   //true

<5>every():有一项返回false,则整体返回false

var arr = [1,2,3,4,5];
var result = arr.every(function(item){
    return item>6;
});
console.log(result);   //false

<6>join():通过指定连接符生成字符串

var arr = [1,2,3,4,5];
var result = arr.join("-=-");
console.log(result);   //1-=-2-=-3-=-4-=-5

<7>push()/pop():末尾推入和弹出,改变原数组, 返回推入/弹出项,会修改原数组

var arr = [1,2,3,4];
var result1 = arr.push(5);
console.log(result1)  //5
console.log(arr);     //[1,2,3,4,5]

var result2 = arr.pop();
console.log(result2);  //5
console.log(arr);      //[1,2,3,4]

<8>shift()/unshift():
shift()移除数组第一项,返回该值;
unshift()添加一个元素进数组第一项,返回新数组长度

var arr = [1,2,3,4];
var result1 = arr.shift();
console.log(result1);   //1
console.log(arr);       //[2,3,4]

var result2 = arr.unshift(1);
console.log(result2);   //4
console.log(arr);       //[1,2,3,4]

<9>sort(fn)/reverse():排序数组和反转数组,会修改原数组

var arr = [1,6,3,5,4,2];
arr.sort(function(a,b){
    return a-b;        //a-b由小到大排序,b-a由大到小排序
});
console.log(arr);   //[1,2,3,4,5,6]

arr.reverse();
console.log(otherResult);  //[6,5,4,3,2,1]

<10>concat():连接数组,不影响原数组浅拷贝。如果参数不是数组,直接当成数组元素添加到数组中,并返回一个新的数组实例。

var arr1 = [1,2,3];
var arr2 = ["Sami","Nick","Michael"];
var result = arr1.concat(arr2);
console.log(arr1);       //[1,2,3]
console.log(arr2);       //["Sami","Nick","Michael"]
console.log(result);     //[1,2,3,"Sami","Nick","Michael"]

<11>slice(start,end):返回截断后的新数组,不改变原数组。第一个参数起始位置,第二个结束位置。截取的数组不包含结束位置上的元素。

var arr = [1,2,3,4,5];
var result = arr.slice(0,2);   
console.log(result);     //[1,2]
console.log(arr);        //[1,2,3,4,5]

<12>splice(start,number,value...):返回删除元素组成的数组,value 为插入项,改变原数组

var arr = [1,2,3,4,5];
var result = arr.splice(1,2);
console.log(arr);    //[1,4,5];
console.log(result); //[2,3];

<13>indexOf(value,fromIndex)、lastIndexOf(value,fromIndex):
查找数组项,返回对应的下标。indexOf从前往后查找,lastIndexOf从后往前查找。

var arr = [1,2,7,4,5,6,7];
var index = arr.indexOf(7);
console.log(index);   //2
var index = arr.indexOf(7,3);
console.log(index);   //6

var index = arr.lastIndexOf(7);
console.log(index);   //6
var index = arr.lastIndexOf(7,3);
console.log(index);   //2

6.事件侦听器通用对象:

var EventUtil = {
    addEvent:function(element,type,handler){
        if(element.addEventListener){
            element.addEventListener(type,handler,false);
        }else if(element.attachEvent){
            element.attachEvent("on" + type,handler);
        }else{
            element["on" + type] = handler;
        }
    },
    removeEvent:function(element,type,handler){
        if(element.removeEventListener){
            element.removeEventListener(type,handler,false);
        }else if(element.detachEvent){
            element.detachEvent("on" + type,handler);
        }else{
            element["on" + type] = null;
        }
    },
    getEvent:function(){
        return event ? event: window.event;
    },
    getTarget:function(event){
        return event.target || event.srcElement;
    },
    preventDefault:function(event){
        if(event.preventDefault){
            event.preventDefault();
        }else{
            event.returnValue = false;
        }
    },
    stopPropagation:function(event){
        if(event.stopPropagation){
            event.stopPropagation();
        }else{
            event.cancelBubble=true;
        }
    }
}

//调用方法
var btn = document.getElementById("myBtn");
var handler = function(){
    event = EventUtil.getEvent();
    EventUtil.preventDefault();
    alert("Clicked");
};
EventUtil.addEvent(btn,click,handler);

7.JS的内置对象:
数据封装对象:Object、Array、Boolean、Number、String;
其他对象:Math、Date、Function、Error、RegExp、Arguments

8.闭包:指有权访问另一个函数作用域中变量的函数。

function parentFunc(){
    var a = 1;
    function childFunc(){
        console.log(a);
    }
    return childFunc();
}

闭包的特征:
<1>函数内再嵌套函数;
<2>内部函数可以调用外部函数的参数和变量;
<3>参数和变量不会被垃圾回收机制回收。

闭包的好处:能够实现封装和缓存。使用闭包主要是为了封装对象的私有属性和私有方法,闭包可以避免全局变量的污染。
闭包的缺点:闭包会常驻内存,会增大内存使用量,使用不当很容易造成内存泄漏。

闭包经典问题:

function parentFunc(){
    var arr = [];
    for(var i = 0;i<5;i++){
        arr[i] = function (){
            return i;
        }
    }
    return arr;
}
console.log(parentFunc()[0]());  //5
console.log(parentFunc()[1]());  //5

这里就展现出了几个关键信息,首先分析一下代码:循环中创建了一个匿名函数并将其赋值给arr数组中对应索引的元素,匿名函数作用是返回i值。此时,arr数组中存放的是匿名函数,而匿名函数还没有执行。当调用parentFunc()函数时返回arr数组,再单独执行数组中的元素保存的匿名函数,此时循环已经执行完,所以i值为5。接下来再去调用其它数组元素中的匿名函数也样会获得数值5。
要解决这个闭包所产生的问题,有两种办法:
<1>立即执行匿名函数

function parentFunc(){
    var arr = [];
    for(var i = 0;i<5;i++){
        arr[i] = (function (){
            return i;
        })();
    }
    return arr;
}
console.log(parentFunc());  //[0,1,2,3,4]

<2>使用let关键字声明变量:使用let声明变量会形成块级作用域

function parentFunc(){
    var arr = [];
    for(let i = 0;i<5;i++){
        arr[i] = function (){
            return i;
        };
    }
    return arr;
}
console.log(parentFunc()[0]());  //0

9.JS作用域:分为全局作用域和函数作用域
全局作用域,代码在程序中的任何地方都能访问,window对象的内置属性都拥有全局作用域;
函数作用域,在固定的代码片段才能访问。

10.作用域链:作用域链的作用是保证执行环境里有权访问的变量和函数是有序的,作用域链的变量只能向上访问,变量访问到window对象即被终止,作用域链向下访问变量是不被允许的。

11.原型和原型链:
每个构造函数都会在其内部初始化一个属性-prototype(原型)。当我们访问一个对象的属性时,如果这个对象的内部不存在这个属性,就会去其构造函数的prototype中,也就是对象的__proto__属性中查找这个属性,这个prototype又会有自己的prototype,于是就会像链条一样一直找下去形成原型链。
(因为所有的对象都是由Object对象继承而来,因此最终查找到Object的prototype结束)

12.组件化:利用组件化思想将多个页面都需要用的功能组件封装起来,提高代码复用性,降低耦合性,增强可维护性和可读性。

13.模块化:主要用途是封装对象
模块化的优点:避免全局变量变量污染,命名冲突;提高代码复用率;提高了可维护性。
最常用的模块化封装对象的方法是:构造函数模式+原型模式。
构造函数内写属性,原型中放方法和重写构造函数指针。

function Person(name,age){
    this.name = name;
    this.age = age;
}
Person.prototype = {
    constructor: Person,
    sayName: function(){
        alert(this.name);
    }
}

var person1 = new Person("老王", 70);
var person2 = new Person("小王", 20);

alert(person1.name === person2.name);    //false,构造函数内属性不公用
alert(person1.sayName === person2.sayName);  //true,原型中的方法共用

组合使用构造函数模式和原型模式封装对象的好处在于,每个新建的实例都拥有自己的属性,然后共同享有原型中的方法,不用每次创建新实例都重新创建同样的方法。

14.继承:实现继承的常用方法是原型链+借用构造函数。
原型链实现对原型属性和方法的继承,借用构造函数实现对实例属性的继承。

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

function SubType(age,name){
    //继承属性
    SuperType.call(this,name);
    this.age = age;
}

//继承方法
SubType.prototype = new SuperType()
/*
 *最优写法,因为仅仅只是继承方法而不继承属性,不用new多一次父类
 *SubType.prototype = Object.create(SuperType.prototype);
 */
SubType.prototype.constructor = SubType;

SubType.prototype.sayAge = function(){
    alert(this.age);
}

var p1 = new SubType("老王", 70);
var p2 = new SubType("小王", 20);
p1.sayName(); //老王
p2.sayName(); //小王
p1.sayAge();  //70
p2.sayAge();  //20

因为SuperType.prototype.constructor重写了SubType.prototype.constructor,导致子类的实例中的constructor属性指向了父类,所以在继承了父类方法后,要重写一下子类原型对象中的构造器。

15.Ajax:ajax的核心是XMLHttpRequest(XHR)
<1>如何创建一个ajax

//get方法
var xhr = new XMLHttpRequest();
xhr.open("get","example.php",true);  //发送的请求类型、请求的URL、是否异步发送请求
xhr.send(null);

xhr.onreadystatechange= function(){
    if(xhr.readyState === 4){
        if(xhr.status === 200){
            success(xhr.responseText);
        }else{
            console.log(xhr.status);
        }
    }
}

//post方法
var data = new FormData(document.forms[0]);
xhr.open("post","example.php",true);
xhr.send(data);

<2>同步和异步的区别:
同步:用户请求,等待,响应,刷新页面展示内容再操作;
异步:用户请求的同时可继续对页面操作,响应完成不刷新页面展示新内容。
<3>
Ajax优点:
异步请求响应快,用户体验好;页面无刷新、数据局部更新;按需取数据,减少了冗余请求和服务器的负担;
Ajax缺点:
异步回调问题、this指向问题、路由跳转back问题;对搜索引擎的支持比较弱,对于一些手机还不是很好的支持
<4>post一般用于修改服务器上的资源,对发送的数据没有限制;而get一般用于请求获取数据。

16.事件代理:
事件代理又称之为事件委托,是绑定事件的常用技巧。即把原本需要绑定的事件委托给父元素,让父元素担当事件监听的职务。
事件代理的原理是DOM元素的事件冒泡。
使用事件代理的好处是可以提高性能,节省内存占用,减少事件注册。可以实现当新增子对象时无需再对其绑定。

var list = document.getElementById("myLinks");
//EventUtil事件监听器通用对象可以去前面看
EventUtil.addEvent(list,"click",function(event){
    event = EventUtil.getEvent(event);
    var target = EventUtil.getTarget(event);
    
    switch(target.id){
        case "doSomething":
            document.title = "I changed";
            break;
        case "goSomeWhere":
            location.href = "http://www.baidu.com";
            break;
        case "sayHi":
            alert("HI");
            break;
    }
});

17.this对象:
·this总是指向函数的直接调用者(而非间接调用者);
·如果有new关键字,this指向new出来的新对象
·在事件中,this指向触发这个事件的对象,但IE中的attachEvent中的this指向window对象。

18.事件模型:
·冒泡型事件:当你使用事件冒泡时,子元素先触发,父元素后触发;
·捕获型事件:当你使用事件捕获时,父元素先触发,子元素后触发;
·DOM事件流:同时支持两种事件模型,冒泡型事件和捕获型事件;
·阻止冒泡:阻止事件冒泡。在w3c中使用stopPropagation()方法,在IE中使用cancelBubble = true;
·阻止捕获:阻止事件的默认行为。在w3c中使用preventDefault()方法,在IE中使用returnValue = false。

19.XML和JSON的区别:
·JSON相对XML,数据体积更小,传递速度更快些;
·JSON与JS的交互更方便,更容易解析处理,更好的数据交互;
·JSON对数据的描述性比XML较差;
·JSON的传输速度远远快于XML。

20.JS定义对象的方法:
·对象字面量: var obj = {name:'obj'};
·new内置构造函数: var obj = new Object({name:'obj'})
·new自定义构造函数:

function Person(name){
    this.name = name;
}
var obj = new Person('obj')

·Object.create: var obj = Object.create(object.prototype);

var o1 = {name: 'o1'};
var o2 = Object.create(o1);
console.log(o2.__proto__ === o1);   //true
console.log(o2);  //Object{}
//也就是说Object.create()创建的实例本身是没有什么方法的,全部都在原型对象上,所以直接打印实例是没有内容的。

21.Promise:
·promise用来进行延迟和异步计算
·promise的四种状态:pending(初始状态)、fulfilled(成功的操作)、rejected(失败的操作)、settled(promise已被fulfilled或者rejected)
·Promise的构造函数:

var promise = new Promise(function(resolve,reject){
    if(...){
        resolve(result);
    }else{
        reject(errMessage);
    }
});

·Promise的then方法:

promise.then(onFulfilled,onRejected);

这两个参数分别对应resolve和reject传过来的结果。
·引用廖雪峰老师的两个例子给大家理解一下promise(稍作修改):

new Promise(function(resolve,reject){
    console.log("promise start...");
    var timeout = Math.random()*2;   //0-2
    console.log("set timeout to:" + timeout + "seconds");
    setTimeout(function(){
        if(timeout < 1){
            console.log("call resolve()...");
            resolve("200 ok");
        }else{
            console.log("call reject()...");
            reject("timeout in" + timeout + "seconds");
        }
    },timeout * 1000);
}).then(function(resolve){
    console.log("Done:" + resolve);
}).catch(function(reject){
    console.log("Failed:" + reject)
});

可见Promise最大的好处是在异步执行的流程中,把执行代码和处理结果的代码清晰地分离了。

Promise还可以做更多的事情,比如,有若干个异步任务,需要先做任务1,如果成功后再做任务2,任何任务失败则不再继续并执行错误处理函数。
要串行执行这样的异步任务,不用Promise需要写一层一层的嵌套代码。有了Promise,我们只需要简单地写:

job1.then(job2).then(job3).catch(handleError);
function multi(input){
    return new Promise(function(resolve,reject){
        console.log('计算 ' + input + ' x ' + input + '...');
        setTimeout(resolve,500, input * input);
    });
}
function add(input){
    return new Promise(function(resolve,reject){
        console.log('计算 ' + input + ' + ' + input + '...');
        setTimeout(resolve,500,input + input);
    });
}
var p = new Promise(function(resolve,reject){
    console.log("start ....");
    resolve(33);
});
p.then(multi)
 .then(add)
 .then(multi)
 .then(add)
 .then(function(result){
    console.log("结果:" + result);
 });

22.eval()的作用:
把对应的字符串解析成可执行的JS代码并运行;
应该避免使用eval(),不安全且非常耗性能。

23.Null和Undefined的区别:
undefined表示声明的变量未赋值,而null表示声明变量的值为空值;
两者相比较时要使用===,因为==无法区分。

24.["1", "2", "3"].map(parseInt) 答案是多少?
[1,NaN.NaN]。因为parseInt的参数时(val,radix),radix表示基数(多少进制),而map的参数是(function(currentValue,index,arr),thisIndex)。所以map传了三个参数给parseInt,radix对应index不合法导致解析失败。

25.JSON与字符串的转换:
·字符串转换为JSON

var obj = eval('(' + str + ')');
var obj = str.parseJSON();
var obj = JSON.parse(str);  //最常用

·JSON转换为字符串

var str = obj.toJSONString();
var str = JSON.stringify(obj);

26.attribute和property的区别:
attribute是DOM元素再文档中作为html标签拥有的属性;
property是DOM元素再JS中作为对象所拥有的属性;

27.如何判断一个对象是否为数组:

function isArray(obj){
    if(typeof obj === 'object'){
        return Object.prototype.toString.call(obj) === '[Object Array]';
    }
    return false;
}

28.event loop(事件循环):
·JS是一门单线程的非阻塞的脚本语言,单线程意味着JS在执行代码的任何时候,都只有一个主线程来处理所有任务。

·事件循环流程图:
初级前端知识点整合-JS部分(持续更新中。。请留意哈)_第1张图片

同步和异步任务分别进入不同的执行场所,同步任务进入主线程,异步任务进入Event table并注册函数;
当指定的事件完成时,Event table会将这个函数移入事件队列Event queue中;
主线程的任务执行完毕为空,会去Event queue读取对应的函数,进入主线程中执行;
上诉的过程不断重复,也就是我们说的事件循环Event loop。

·举个例子说明他们的执行顺序:

console.log("1");
setTimeout(function(){
    console.log("2");
},0);
console.log("3");        //输出结果为:1,3,2

因为setTimeout是异步任务,其他两个console同步任务按顺序执行,所以setTimeout最后输出。

·微任务和宏任务,结合例子说明:

 console.log('1');
 setTimeout(() => {
     console.log('2')
 }, 1000);
 new Promise((resolve, reject) => {
     setTimeout(() => {
         console.log('3');
     }, 0);
     console.log('4');
     resolve();
     console.log('5');
 }).then(() => {
     console.log('6');
 });
 console.log('7');     //执行结果为1,4,5,7,6,3,2

先来说明下什么是微任务和宏任务,他们都是异步的任务,且都属于队列,区别在于微任务先于宏任务执行。(有一点歧义,之后再说)

宏任务包含有:setTimeout、setInterval、setImmediate、I/O、UI rendering、DOM事件;
微任务包含有:process.nextTick()、promise.then、MutationObserver;
补充一点 new promise会同步执行。

在执行到new Promise的时候会立马新建一个promise对象并立即执行。所以会输出 1,4,5,7,而then则会在Event Table中注册成回调函数并放在微任务队列中,而两个setTimeout(输出3)和setTimeout(输出2,1s后完成)会被先后注册成回调函数并放在宏任务队列中。

·复杂测试题理解程度(分清宏任务和微任务,画出队列执行顺序理解):

console.log(1)
process.nextTick(() => {
  console.log(8)
  setTimeout(() => {
    console.log(9)
  })
})
setTimeout(() => {
  console.log(2)
  new Promise(() => {
    console.log(11)
  })
})
let promise = new Promise((resolve,reject) => {
  setTimeout(() => {
    console.log(10)
  })
  resolve()
  console.log(4)
})
fn()
console.log(3)
promise.then(() => {
  console.log(12)
})
function fn(){
  console.log(6)
}                  //输出结果:1,4,6,3,8,12,2,11,10,9

按顺序执行,同步任务先执行,再到微任务和宏任务,其内部包含的亦是如此。(不同评论留言)

这些内容来自:https://juejin.im/post/5d2603...

29.附加多一题promise+event loop的题目:贼有意思

new Promise((resolve,reject)=>{
    console.log("promise1")
    resolve()
}).then(()=>{
    console.log("then11")
    new Promise((resolve,reject)=>{
        console.log("promise2")
        resolve()
    }).then(()=>{
        console.log("then21")
    }).then(()=>{
        console.log("then23")
    })
}).then(()=>{
    console.log("then12")
})
new Promise((resolve,reject)=>{
    console.log("promise3")
    resolve()
}).then(()=>{
    console.log("then31")
})            

//输出结果:[promise1,promise3,then11,promise2,then31,then21,then12,then23]

不明白的来评论问我!链式调用插队问题。

30.上瘾了,加多一题async await + event loop + promise

async function async1() {
    console.log("async1 start");
    await  async2();
    console.log("async1 end");
}

async  function async2() {
    console.log( 'async2');
}

console.log("script start");

setTimeout(function () {
    console.log("settimeout");
},0);

async1();

new Promise(function (resolve) {
    console.log("promise1");
    resolve();
}).then(function () {
    console.log("promise2");
});
console.log('script end'); 

async/await仅仅影响的是函数内的执行,而不会影响到函数体外的执行顺序。也就是说async1()并不会阻塞后续程序的执行,await async2()相当于一个Promise,console.log("async1 end");相当于前方Promise的then之后执行的函数。

最终输出结果:[script start,async1 start,async2,promise1,script end,async1 end,promise2,settimeout]

31.Math.random()函数:生成[0,1)的随机数
·结合Math.floor()方法获得整数,向下取整
·Math.ceil()方法向上取整
·Math.round()方法四舍五入

<1>生成[0,10)之间的整数:

Math.floor(Math.random()*10);

<2>生成[0,10]之间的整数(也就是[0,11)):

Math.floor(Math.random()*(10+1));

<3>生成[1,10]之间的整数:

Math.floor(Math.random()*(10+1)+1);

32.类型判断:
三种方式,分别为:typeof instanceof、Object.prototype.toString.call();

<1>typeof:判断属于哪一种基本类型。

typeof 'str'        //string
typeof true         //boolean
typeof 10           //number
typeof null         //object  所以无法判定是否为null
typeof undefined    //undefined
typeof Symbol()     //symbol

typeof []           //object
typeof {}           //object
typeof (()=>{})     //function

<2>instanceof:可以对对象类型进行判定,其原理就是测试构造函数的protoype是否出现被检测对象的原型链上。

[] instanceof Array //true
{} instanceof Object    //true
(()=>{}) instanceof Function //true

但是,instanceof并不是最好的,也有bug,如下:

let arr = [];
let obj = {};
arr instanceof Array    //true
arr instanceof Object   //true
obj instanceof Object   //true
obj instanceof Array    //false

因为instanceof的是通过原型链实现的:

arr.__proto__ === Array.prototype;
Array.prototype.__proto__ === Object.prototype;
arr.__proto__ ===Object.prototype;

所以arr即使继承自Array,也继承自Object,因此instanceof检测arr是否属于Array和Object都是true。

<3>Object.prototype.toString.call():

Obejct.prototype.toString.call({})      //[object Object]
Object.prototype.toString.call([])      //[object Array]
Object.prototype.toString.call(()=>{})  //[object Function]
Object.prototype.toString.call('str')   //[object String]
Object.prototype.toString.call(1)       //[object Number]
Object.prototype.toString.call(Symbol())//[object Symbol]
Object.prototype.toString.call(null)    //[object Null]
Object.prototype.toString.call(undefined)   //[object Undefined]

Object.prototype.toString.call(new Date())  //[object Date]
//以此类推,new Set()、new Map()等等都一样

·Array.isArray()也可以判定是否为数组,但是IE6-8不兼容所以可以写一个兼容方法

33.空值判断:
<1>先来个反面例子

if([]){
    console.log("true");
}else{
    console.log("false");
}
//返回true
if({}){
    console.log("true");
}else{
    console.log("false");
}
//返回true

因为在这里if只是判断这个对象存不存在,[]、{}对象明显是存在的,所以返回true,而并不能判断数组和对象是否为空。
<2>空数组判断:
Array.length>0 即可
<3>空对象判断:
·Object.getOwnPropertyNames(),返回值是对象中属性名组成的数组

var obj = {};
Object.getOwnPropertyNames(obj).length === 0;   //true

·JSON对象转换为字符串,然后与字符串"{}"比较。因为JSON对象最外层为{}。

var obj = {};
var a = JSON.stringify(obj);
console.log(a === "{}");   //true

·for..in..循环判断:

var obj = {};
function isNullObj(obj){
    for(let key in obj){
        return false;
    }
    return true;
};
console.log(isNullObj(obj));     //true   

·Object.Keys().ES6的新方法,返回值是属性名组成的数组。

var obj = {};
console.log(Object.Keys(obj).length === 0);   //true

34.字符串常用函数:
<1>substr()方法把字符串分割成数组,不改变原字符串。
substr(start,number)的参数分别是其实位置和截取的数量。用法也一样,当start为负值的时候,开始位置为length+start,依然向后截取

var str = "你好啊小伙子";
var result1 = str.substr(1,2);
var result2 = str.substr(-2,2);
console.log(result1 + "\n" + result2); //"好啊"  "伙子"

<2>split(separator,howmany),将字符串分割成数组,不改变原字符串:

var str = "你好啊,小伙子";
var res1 = str.split(",");
var res2 = str.split("");
var res3 = str.split("",3);
console.log(res1);      //["你好啊", "小伙子"]
console.log(res2);      //["你", "好", "啊", ",", "小", "伙", "子"]
console.log(res3);      //["你", "好", "啊"]

35.对象常用方法:
<1>Object.prototype.hasOwnProperty(),仅再目标属性为对象自身属性时返回true,若该属性是从原型链继承而来或根本不存在时返回false。

var obj = {age:18};
//记得传参加引号
obj.hasOwnProperty('age');    //true
obj.hasOwnProperty('toString');    //false,继承Object而来

<2>Object.create(obj,desc)(ES6),该方法用于创建一个新对象,并为其设置原型。

var parent = {
    hi: 'Hello'
}; 
var o = Object.create(parent, {
    prop: {
        value: 1 
    } 
});
console.log(o.prop);      //1

这个函数迟点再补充详细的探讨。

36.访问元素的样式的方法:dom.style、window.getComputedStyle(dom,null)、dom.currentStyle;
<1>dom.style属性

var myDiv = document.createElement("div");
myDiv.style.backgroundColor = "red";
console.log(myDiv.style.backgroundColor);   //red

dom.style仅可以进行DOM元素内联样式的读写操作。对于嵌入样式和外部样式无法进行读取操作。

<2>window.getComputedStyle(dom,null)方法:
第一个参数是DOM元素,第二个参数不是必须的,当不查询伪类元素的时候可以忽略或者传入 null。

var myDiv = document.getElementById("myDiv");
var computedStyle = window.getComputedStyle(myDiv,null);
console.log(computedStyle.width);
console.log(computedStyle.color);

window.getComputedStyle()方法可以对行内样式、嵌入样式、外部样式进行操作,不可以进行写操作。

我们可以通过使用getComputedStyle读取样式,通过element.style修改样式。

<3>dom.currentStyle:仅支持IE,且同样仅支持读操作,不可进行写入

var myDiv = document.getElementById("myDiv");
var currStyle = myDiv.currentStyle;
console.log(currStyle.width);
console.log(currStyle.color);

37.计算元素大小:
<1>dom.offsetWidth/offsetHeight/offsetLeft/offsetTop
·dom.offsetWidth:DOM元素整体的实际宽度,包含边框、滚动条等边线。(content+padding+border);
·dom.offsetLeft:DOM元素左边框至包含元素的左内边框的距离。
初级前端知识点整合-JS部分(持续更新中。。请留意哈)_第2张图片

<2>dom.clientWidth/clientHeight
·dom.clientWidth:DOM元素内容的可视区的宽度,不包含边框、滚动条等边线。(content+padding)溢出可视区部分也不计入宽度。
初级前端知识点整合-JS部分(持续更新中。。请留意哈)_第3张图片

<4>深入理解区分:
·元素内无内容或者内容不超过可视区域,滚动不出现或不可用的情况:
scorllWidth = clientWidth, offsetWidth为元素实际宽度
初级前端知识点整合-JS部分(持续更新中。。请留意哈)_第4张图片

·元素内容超过可视区域,滚动条出现的情况:
scrollWidth > clientWidth;
scrollWidth为实际内容的宽度、clientWidth为内容可视区域的宽度、offsetWidth为元素的实际宽度;
初级前端知识点整合-JS部分(持续更新中。。请留意哈)_第5张图片

<5>dom.getBoundingClientRect():用来确定元素大小
返回值是一个DOMRect对象,用于获取某个元素相对于视窗的位置集合。集合中有top, right, bottom, left等属性。

var myDiv = document.getElementById("myDiv");
var rect = myDiv.getBoundingClientRect();
console.log(rect.top);    //div上边到视窗上边的距离
console.log(rect.right);  //div右边到视窗左边的距离
console.log(rect.bottom); //div下边到视窗上边的距离
console.log(rect.left);   //div左边到视窗左边的距离

初级前端知识点整合-JS部分(持续更新中。。请留意哈)_第6张图片

38.DOM操作:增、删、查、替换、创建、复制、移动、插入等
<1>创建节点:document.createElement(nodeName)

var myDiv = document.createElement("div");   //创建标签节点
var text = document.createTextNode("文本节点!"); //创建文本节点

<2>添加节点:dom.appendChild(nodeObj)

var newNode = document.createElement("p");
myDiv.appendChild(newNode);

<3>删除节点:dom.removeChild(childNodeObj)

myDiv.removeChild(newNode);

<4>替换节点:dom.replaceChild(newNode,oldNode)

var myDiv = document.getElementById("myDiv");
var oldEle = document.createElement("p");
var newEle=document.createElement("div");

myDiv.replaceChild(newEle,oldEle);

<5>插入节点:dom.insertBefore(newItem,existingItem)

myDiv.insertBefore(newEle,oldEle);

<6>复制节点:dom.cloneNode(boolean)

var cEle = myDiv.cloneNode(true);//深度复制,复制节点下面所有的子节点
cEle = myDiv.cloneNode(false);//只复制当前节点,不复制子节点

<7>查找节点:document.getElementById/getElementsByClassName/getElementsByTagName()

document.getElementById("id");// 通过id查找,返回唯一的节点
document.getElementsByClassName("class");// 通过class查找,返回值为nodeList类型
document.getElementsByTagName("div");// 通过标签名查找,返回值为nodeList类型

39.DOM事件级别:
·DOM0级:element.onclick = function(){};
·DOM2级:element.addEventListener('click',function(){},false);
false代表冒泡截断触发,true代表捕获截断触发;
·DOM3级:element.addEventListener('keyup',function(){},false);
DOM3级就是增加了一些鼠标、键盘事件。

40.描述一下捕获流程:
window最先触发事件->document->html(document.documentElement)->body->....各层级元素->目标元素(例如button等)

41.事件对象Event最常见的应用:
·event.preventDefault():阻止默认行为(捕获)
·event.stopPropagation():阻止事件冒泡
·event.stopImmediatePropagation():阻止同个元素的默认后续同类型事件的触发。比如一个DOM元素定义了两个click,在第一个click事件中调用了此方法,那么后面的click事件就不会触发。
·event.currentTarget:实际注册事件的元素。一般和事件委托结合使用,因为使用事件委托时currentTarget不是目标元素(比如你点击的按钮)。
·event.target:目标元素。例如你点击触发事件的按钮。

42.自定义事件:
使用的方法:new Event()创建事件对象、dom.dispatchEvent()触发自定义事件。

var eventObj = new Event("custome");
dom.addEventListener("custome",function(){
    console.log("custome");
},false);
dom.dispatchEvent(eventObj);

还可以使用new CustomEvent()创建事件对象,这个方法可以传参数:

var custom = new CustomEvent('test_event',{
    detail:{
        e_name : " this is a test "
    }
});
// 某个dom元素监听自定义事件
let div = document.createElement("DIV");
div.addEventListener("test_event",function(e){console.log(e.detail.e_name)},false)
// 触发自定义事件(dispatchEvent 除非事件的参数是必填项,且必须为事件对象)
div.dispatchEvent(custom);// this is a test

43.DOM事件流:
DOM事件流规定包括三个阶段:事件捕获阶段、出于目标阶段和事件冒泡阶段。先触发事件捕获,然后是实际的目标接收到事件,最后一个阶段是冒泡阶段。

44.prototype属性和__proto__属性
·prototype属性是构造函数才拥有的,指向构造函数的原型对象。例如Array.prototype就指向它的原型对象
·__proto__属性是实例拥有的,指向它的构造函数的原型对象。例如new Array().__proto__ === Array.prototype;

这里还有个小问题,虽然__proto__是实例特有的,但是构造函数也是一个实例,所以他也拥有__proto__属性。例如Array.__proto__ === Function.prototype,因为此时Array是一个构造函数是通过Function继承而来的。

45.

你可能感兴趣的:(前端,javascript)