98、比较typeof()和instanceof() 通过Object.prototype.toString.call()可以判断所有变量的类型
相同点:JavaScript中typeof 和 instanceof 常用来判断一个变量是否为空,或者是什么类型的
typeof:返回值是一个字符串,用来说明变量的数据类型
(1) typeof 一般只能返回如下几个结果:number,boolean,string,function,object,undefined
(2) 对于 Array,Null,Object 等特殊对象使用 typeof 一律返回 object,这正是 typeof 的局限性
instanceof:判断一个变量是否属于某个对象的实例
(1) 一般用于Array Object null的判断
var a = new Array();
alert(a instanceof Array); // true
alert(a instanceof Object) // true
这是因为Array是Object的子类,所以要进一步判断是Array的话还要进行下面的操作
var a = [1,2];
if(Object.prototype.toString.call(a) == '[object Array]'){
console.log('1');
}
var b = {};
if(Object.prototype.toString.call(b) == '[object Object]'){
console.log('2');
}
99、实现数组的混序:利用array中的sort函数,然后再里面定义一个回调函数,利用Math.random()产生一个随机数,当大于某个数的时候返回1,否则返回-1
function mixArr(arr){
var len = arguments.length;
if( !len){
return '请输入参数';
}else if( len!=1 ){
return '输入的参数为一个';
}else if(!Array.isArray(arr)){
return '输入的参数必须为数组';
}
arr.sort(function() {
var rand = (Math.random() > 0.5) ? 1 : -1;
return rand;
});
return arr;
}
var arr = [5,1,8,3];
arr = mixArr(arr);
console.log(arr);
function randomNum(min,max){
return Math.round(Math.random()*(max-min)+min)
}
function mixArr(arr){
var len = arguments.length;
if( !len){
return '请输入参数';
}else if( len!=1 ){
return '输入的参数为一个';
}else if(!Array.isArray(arr)){
return '输入的参数必须为数组';
}
len = arr.length;
for(var i =0;i<len;i++){
var index = randomNum(0,i);
var temp = arr[index];
arr[index] = arr[i];
arr[i] = temp;
}
return arr;
}
var arr = [1,2,34,8,5];
console.log(mixArr(arr))
100、有一个长度为100的数组,值为其所在位置的索引
//方法一
// var a = new Array(100);
// a = a.join(",").split(",").map(function(item, index) {
// return index;
// });
// console.log(a);
//方法2
var a = [];
for(var i=0;i<100;i++){
a.push(i);
}
console.log(a);
102、字符串转驼峰写法:利用split(‘-’)将字符串转为数组,然后对从第二个元素开始,用arr[i].charAt(0).toUpperCase()+arr[i].slice(1)先将每个元素的第一个元素转为大写,然后在将后面的元素进行拼接
function changeToHump(str){
if( !arguments.length ){
return '请输入字符串变量';
}else if(typeof(str) !== 'string'){
return '变量是字符串';
}else if(!str.length){
return '字符串变量不能为空';
}
var arr = str.split('-');
var len = arr.length;
if(len > 1){
for(var i=1;i<len;i++){
arr[i] = arr[i].charAt(0).toUpperCase() + arr[i].slice(1);
}
str = arr.join('');
}
return str;
}
var str = 'aa-bb';
str = changeToHump(str);
console.log(str);
103、js面试代码题
104、输出日期的格式为‘2018-5-31’
var d = new Date();
var year = d.getFullYear();
var month = d.getMonth() + 1; //月数是从0-11的,所以需要加上1
month = month<10 ? '0'+month : month;
var day = d.getDate();
day = day<10 ? '0'+day : day;
var date = year + '-' + month + '-' + day;
console.log(date);
105、写一个函数对特殊字符进行转义
function escapeHtml(str) {
return str.replace(/[<>"&]/g, function(match) {
switch (match) {
case '<': return '<'; break;
case '>': return '>'; break;
case '&': return '&';break;
case '\"': return '"';break;
}
});
}
var str='ss<>s"&s';
str = escapeHtml(str);
console.log(str);
105、用js实现随机选取10–100之间的10个数字,存入一个数组,并排序
// 用js实现随机选取10–100之间的10个数字,存入一个数组,并排序
//start--开始的数字,end--结束的数字,num---要取得的数字的长度
function productRandNumAndSort(start,end,num){
var diff = end-start;
var arr = [];
var len = num;
var randNum;
while(len--){
randNum = Math.round((Math.random()*diff) + start);
arr.push(randNum);
}
arr = quickSort(arr);
return arr;
}
function quickSort(arr){
if(!Array.isArray(arr)){
return '输入参数必须为数组';
}
var len = arr.length;
if(len<2){
return arr;
}
var midIndex = Math.floor(len/2);
var midEle = arr.splice(midIndex,1);
var left = [];
var right = [];
for(var i=0;i<len-1;i++){
if(midEle>arr[i]){
left.push(arr[i]);
}else{
right.push(arr[i]);
}
}
return quickSort(left).concat(midEle,quickSort(right));
}
var new1 = productRandNumAndSort(10,100,10);
console.log(new1);
106、请实现,鼠标点击页面中的任意标签,console该标签的名称(注意兼容性)
<script type="text/javascript">
window.onload = function(){
var obj = document.getElementsByTagName('body')[0];
obj.onclick = function(event){
//在IE中获取到事件需要使用window.event
var eve = event || window.event;
//在IE中需要使用eve.srcElement获取到事件源对象
var targetObj = eve.target || eve.srcElement;
console.log(targetObj.nodeName.toLowerCase());
}
}
</script>
106、对String对象的方法扩展,使其能删除前后的空格
// 对 string 对象进行扩展,使其具有删除前后空格的方法
String.prototype.trim = function(){
var reg = /(^\s*)|(\s*$)/g;
return this.replace(reg,'');
}
var str=' dfd ';
str = str.trim();
console.log(str);
107、对cookie的封装
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>alert标签名</title>
</head>
<body>
<script>
setCookie('age','1');
var age = getCookie('age');
console.log(age);
delCookie('age');
age = getCookie('age');
console.log(age);
//设置cookie
function setCookie(name, value, days) {
days = days || 30;
var exp = new Date();
exp.setTime(exp.getTime() + days * 24 * 60 * 60 * 1000);//toUTCString()将根据世界时,将日期对象转换为字符串
document.cookie = encodeURIComponent(name) + "=" + encodeURIComponent(value) + ";expires=" + exp.toUTCString();
}
//获取cookie
function getCookie(name) {
var arr, reg = new RegExp("(^| )" + name + "=([^;]*)(;|$)");
if (arr = document.cookie.match(reg)){
//getCookie('name')
//结果: ["name=jiang;", "", "jiang", ";", index: 0, input: "name=jiang; name=jiang", groups: undefined]
console.log(arr);
return decodeURIComponent(arr[2]);
}
else return null;
}
//删除cookie
function delCookie(name) {
var exp = new Date();
exp.setTime(exp.getTime() - 1);
var value = getCookie(name);
if (value != null){
document.cookie = encodeURIComponent(name) + "=" + encodeURIComponent(value) + ";expires=" + exp.toUTCString();
}
}
</script>
</body>
</html>
107、事件绑定和普通事件的区别
事件绑定和普通绑定有什么区别
1)普通事件是DOM0级事件,同一对象只支持单个事件,比如对同一对象添加多个onclick事件,那么只会响应最后一个onclick事件
2)事件绑定是DOM2级事件,同一对象可以添加多个事件,比如对同一对象使用多个addEventListener来监听click事件,执行顺序由前向后
3) IE事件处理程序,使用attachEvent()会在全局作用域执行,函数里面的this=window;对同一对象可以使用attachEvent()来添加多个事件处理器,执行顺序由后向前
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>alert标签名</title>
</head>
<body>
<div id='hello'>dfdfdfd</div>
<script>
//使用普通事件
// var btn = document.getElementById("hello");
// btn.onclick = function(){
// alert(1); //不执行
// };
// btn.onclick = function(){
// alert(2); //弹出
// };
//绑定事件
var btn = document.getElementById("hello");
btn.addEventListener("click",function(){
alert(1); //弹出
},false);
btn.addEventListener("click",function(){
alert(2); //弹出
},false);
</script>
</body>
</html>
108、说出下面代码的问题,并提供解决的方法
for(var i=0;i<5;i++){//5 5 5 5 5
setTimeout(function(){console.log(i)},i*1000);
}
// 如果想要输出(0,1,2,3,4),改为立即执行函数
for(var i =0;i<5;i++){
(function(){
setTimeout(function(){
console.log(i);
},i*100)
})(i)
}
//或者在里面调用一个函数
for(var j=0;j<5;j++){
showData(j);
}
function showData(data){
setTimeout(function(){
console.log(data);
},1000);
}
109、输出结果
var undefined;
console.log( undefined == null);//true
console.log( 1 == true ); //true
console.log(2 == true ); //false
console.log( 0 == false );//true
console.log(0 == '' );//true
console.log(NaN == NaN );//false
console.log([] == false);//true
console.log([] == ![] );//true
110、输出ul li中的下标:立即执行函数+闭包 或者使用Li的属性index
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>alert标签名</title>
</head>
<body>
<ul id='div1'>
<li>这是第一条</li>
<li>这是第二条</li>
<li>这是第三条</li>
</ul>
<script>
var obj = document.getElementById('div1').children;
var len = obj.length;
var tempObj;
//方法一:使用立即执行函数,和闭包
// for(var i=0;i<len;i++){
// tempObj = obj[i];
// tempObj.onclick = (function(data){
// return function(){
// console.log(data);
// }
// })(i);
// }
//方法二:利用列表元素有属性index
for(var i=0;i<len;i++){
tempObj = obj[i];
tempObj.index = i;
tempObj.onclick = function(){
console.log(this.index);
};
}
</script>
</body>
</html>
111、字符串反转
//利用新字符串和charAt()
// function reverseStr(str){
// if(typeof(str) !=='string'){
// return
// }
// var len = str.length;
// var newStr = '';
// if(len<2){
// newStr = str;
// }else{
// for(var i=len-1;i>=0;i--){
// newStr += str.charAt(i);
// }
// }
// return newStr;
// }
//方法二:先用split()转成数组,在用数组的reverse()反转,在用array的join()转成字符串
function reverseStr(str){
if(typeof(str) !=='string'){
return
}
var len = str.length;
if(len<2){
return str;
}
str = str.split('').reverse().join('');
return str;
}
var str = 'abcd';
str = reverseStr(str)
console.log(str);
112、将数字改成RMB的形式,如123456,应该是123,456
function transfer(num){
if(typeof(num)!=='number'){
return
}
num = num + '';
var len = num.length;
if(len<=3){
return num;
}
//字符串反转
num = num.split('').reverse().join('');
count = 0;
var newStr = '';
for(var i=0;i<len;i++){
newStr += num.charAt(i);
count += 1;
if( count%3 ==0 && i!== len-1){
newStr += ',';
}
}
// 在将字符串反转回来
newStr = newStr.split('').reverse().join('');
return newStr;
}
var num = 1234567;
num = transfer(num);
console.log(num);
//方法一:利用正则的正向肯定预查
//数字千分位的特点是,第一个逗号后面数字的个数是3的倍数,正则:/(\d{3})+$/;
// 第一个逗号前最多可以有1至3个数字,正则:/\d{1,3}/。加起来就是/\d{1,3}(\d{3})+$/,
// 分隔符要从前往后加,就要将前面的数字“87”替换成“87,”,为什么是87不是874?因为874后面只剩下5位数字,
// 在632后加一个分隔符后,将只剩下97,不符合千分位要求,所以第一个分隔符后面的数字位数必须是3的倍数。
// 要匹配数字87,又要保证87后面数字位数是3的倍数,并且要将匹配的87替换成“87,”,就要用到(?=exp)
str = '87463297';
// console.log( str.replace(/\d{1,3}(?=(\d{3})+$)/g,function(s){
// return s+','
// }));
//方法二:先将字符串转成数组,利用reverse反转数组后每3个数字后添加一个分隔符“,”,到字符串末尾除外,之后转回字符串
// 利用字符串和数组方法
console.info( str.split("").reverse().join("").replace(/(\d{3})+?/g,function(s){
return s+",";
}).replace(/,$/,"").split("").reverse().join("") )
// 换成美元的形式,保留两位小数位数
// 1233.0988 =》 $+1,233.10 -2134 => $-2,134.00
let num = 123.09898;
let flag = '+';
if( num<0 ){
flag = '-';
}
let str1 = Math.abs(num).toFixed(2).toString();
let index = str1.indexOf('.');
let str = str1.slice(0,index); //整数部分
let result;
result = str.split("").reverse().join("").replace(/(\d{3})+?/g,function(s){//+匹配1-多个,后面的?非贪婪匹配,即只匹配一个
return s+",";
}).replace(/,$/,"").split("").reverse().join("");
result = '$' + flag + result + str1.slice(index);
console.log(result);
112、随机产生5个不同的数字
function productVariNum(num){
var arr =[];
for(var i =0;i<num;i++){
arr[i] = Math.floor(Math.random()*10) +1;
for(var j=0;j<i;j++){
if(arr[i] == arr[j]){
i--; break;
}
}
}
return arr;
}
var arr = productVariNum(5);
console.log(arr);
function productVariNum(num){
var arr =[];
var temp;
for(var i =0;i<num;i++){
temp = Math.floor(Math.random()*10) +1;
if(arr.indexOf(temp) === -1){
arr.push(temp);
}else{
i--;
}
}
return arr;
}
var arr = productVariNum(5);
console.log(arr);
113、阻止冒泡
document.getElementById('#name').onclick = function(e){
var obj = e||window.event;
obj.preventDefault();
obj.stopPropagation();
//todo
}
114、统计数组中单词个数
//方法1:使用for in遍历实现
// function count(arr){
// if(!arguments.length){
// return
// }else if(!Array.isArray(arr)){
// return
// }
// var obj = {};
// if(!arr.length){
// return
// }
// for(var key in arr){
// if(obj[arr[key]]){
// obj[arr[key]]++;
// }else{
// obj[arr[key]] = 1;
// }
// }
// return obj;
// }
// arr = [];
// var obj = count(arr);
// console.log(obj);
var arr = ["apple","orange","apple","orange","pear","orange"];
//方法2:使用reduce(callback(必需-返回值,必需-当前元素,可选-当前元素的索引),给返回值的初始值)函数遍历数组的每一个元素
//返回值的类型是自己设定 ,不改变原数组
function getWordCnt(arr){
//以下应掏空
return arr.reduce(function(prev,next,index,arr){
prev[next] = (prev[next] + 1) || 1; //这句是重点,刚开始都是undefined的时候undefined+1会是NaN
return prev;
},{});
}
console.log(getWordCnt(arr));
//方法3:array.map(function(currentValue,index,arr), thisValue),不改变原数组
function countWord(arr){
var obj = {};
arr.map(function(item){
obj[item] = ( obj[item] + 1 ) || 1;
});
return obj;
}
console.log(getWordCnt(arr));
115、给定字符串 str,检查其是否包含连续重复的字母(a-zA-Z),包含返回 true,否则返回 false
//用了一个新的对象来作为判断的辅助
// function containsRepeatingLetter(str){
// var flag = false;
// if(!arguments.length){
// return
// }else if(typeof(str) !=='string'){
// return
// }
// var len = str.length;
// var obj = {};
// for(var i=0;i<len;i++){
// if( !obj[str.charAt(i)] ){
// obj[str.charAt(i)] = 1;
// }else{
// return flag=true;
// }
// }
// return flag;
// }
//方法2:使用正则
function containsRepeatingLetter(str) {
//以下应掏空
return /([a-zA-Z])\1/.test(str); // \1指代第一个括号的匹配项
}
var str = 'bdaa';
console.log(containsRepeatingLetter(str));
116、函数中的对象属性arguments和形参的关系,他们是相互关联的,其中一个改变了,另一个也改变
function f(a, b, c){
console.log(a);
console.log(arguments.length);
var a = 200;
console.log(arguments[0]);
arguments[0] = "haorooms";
console.log(a);
console.log(c);
c = 2016;
console.log(arguments[2]);
}
f(1, 2)
输出结果:
1
2
200
haorooms
undefined
undefined
116、实现console.log(add(1,2))和console.log(add(1)(2))结果都是3
function add(){
var sum = arguments[0];
var len = arguments.length;
if(!len){
return '';
}else if(len == 1){
var autoAdd = function(a1){
sum += a1;
return autoAdd;
}
autoAdd.toString = function(){
return sum + '';
}
autoAdd.toValue = function(){
return sum - 0;
}
return autoAdd;
}else{
var anotherSum = 0;
for(var i=0;i<len;i++){
anotherSum += arguments[i];
}
return anotherSum;
}
}
console.log(add(1));
这种方法利用打印和相加会分别调用函数的toString()和valueOf(),这里可以兼容大部分的输入形式。
下面考虑一种不兼容的书写形式,也就是最简单的实现形式:
//仅仅考虑两个参数的情况
function add(){
var len = arguments.length;
if(!len){
return;
}else if(len ==1){
var sum = arguments[0];
return function(a1){
return sum+a1;
}
}else if(len ==2){
return arguments[0] + arguments[1];
}
}
console.log(add(1,2));
console.log(add(1)(2));
117、对js中的柯里化函数currying的理解
定义
函数柯里化currying又称部分求值,它首先接受一些参数,接受这些参数之后不回立即求值,而是继返回一个函数,刚才传入的参数在形成的闭包中被保存起来,待到真正求值的时候,之前传入的所有参数都会一次性用于求值
currying的只有一个参数为函数(定义功能,即用所有参数完成的事情),返回值是一个函数其作用有两个-------1)当不满足计算条件的时候将参数保存起来然后调用arguments.callee;2)否则通过fn.apply(this,缓存数据的变量)计算结果
例子:计算月花销,计算的条件是函数没有传参的时候,否则将参数保存起来
// 功能函数
function add(){
let sum = 0;
let len = arguments.length;
for(let i = 0;i<len;i++){
sum += arguments[i];
}
return sum;
}
// fn---是功能函数
function currying(fn){
var args = [];
return function(){
if(arguments.length=== 0){
return fn.apply(this,args);
}else{
[].push.apply(args,arguments);
arguments.callee;
}
}
}
let ss = currying(add);
ss(1);
ss(2);
console.log(ss());
把接受多个参数的函数,变换成一个接受单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数,返回结果是一个新函数的技术
简单的理解就是:逐渐传参,逐渐减小函数的使用范围,逐渐求解;
可以预先设定形参的个数(这种场景不太具由普遍性)
有参数的时候,返回一个函数;没有参数的时候,计算结果,达到延迟计算的目的
function curryIt(fn) {
if(typeof fn !== 'function') throw new Error("curryIt():fn must be function");
var len = fn.length; //获取函数形参数量个数
var slice = Array.prototype.slice; //或者写成[].slice
var arg = slice.call(arguments,1); //将函数的形参转化为数组,因为arguments是伪数组,不能调用Array的API
return function() {
arg = arg.concat(slice.call(arguments));
if(arg.length < len) { //当等于函数需要的形参数量时候调用
//输入参数与预设参数的个数不一样的时候,调用函数本身
return arguments.callee;
}else{
//输入参数与预设参数一致的时候,计算结果
return fn.apply(null,arg); //null这个对象是用于确定this的值的,这里为null,则fn中的this就指向全局对象window
}
}
}
var fn = function(a, b, c) {
return a + b + c
};
console.log(curryIt(fn)(1)(2)(3)); //6
118、实现Cal(2).add(1).reduce()2.multiple(4).divide(3)
// Cal(2).加(1).减(2).乘(4).除(3),链式操作
// 在类中定义公共属性result
// 在prototype上定义方法,方法返回this对象)
function Cal(num1){
this.result = num1;
}
Cal.prototype.add = function(num2){
this.result = this.result + num2;
console.log('result:'+ this.result);
return this;
}
Cal.prototype.reduce = function(num3){
this.result = this.result - num3;
console.log('result:'+ this.result);
return this;
}
Cal.prototype.multiple = function(num4){
this.result = this.result * num4;
console.log('result:'+ this.result);
return this;
}
Cal.prototype.divide = function(num5){
this.result = this.result/num5;
console.log('result:'+ this.result);
return this;
}
console.log(new Cal(2).add(1).reduce(2).multiple(4).divide(3));
118、对回文的理解,从前读到后面和从后面读到前面的结果一样
下面如:'abba'和'abdba'如果认为是回文的话,可以用下面这种形式去判断
function isHuiwen(str){
if(typeof(str) !== 'string'){
return false
}
if(str.length<2){
return false
}
if(str.split('').reverse().join('') === str){
return true;
}else{
return false;
}
}
var str = ''
console.log(isHuiwen(str));
str = 'abba';
console.log(isHuiwen(str));
str = 'abdba';
console.log(isHuiwen(str));
但是如果 认为'abdba不是回文,那么就用下面这种形式:对元素从头到尾遍历一次,使用lastIndexOf()确定right的索引值
//输入:cabbeaf
//4
String.prototype.roundWord = function() {
var i = 0,
str = this,
count = 0, //回文计数
left, right = str.length - 1,
flag = false;
if (str.length <= 0) throw new Error("roundWord(): arguments str/this must be string");
while (i < str.length) {
charOne = str.charAt(i); //searchvalue要检索的字符串,fromindex开始检索的位置
// left = str.indexOf(charOne, i); //stringObject.indexOf(searchvalue,fromindex)
left = i;
if (!flag) {
right = str.lastIndexOf(charOne); //lastIndexOf()找不到元素,则返回-1
} else {
right = str.lastIndexOf(charOne, right);
}
if (left !== right && left < right) { //头尾有相同字符,通过对字符出现的索引进行比较
// if (++count >= max) max = count;//left < right,证明有找到匹配的元素,否则就为-
count++;
flag = true; //开始有回文
}
i++;
}
return count*2;
};
var str = "cababeacf123";
console.log(str.roundWord()); //6
str = "cabbeaf";
console.log(str.roundWord()); //4
119、求输出结果
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>alert标签名</title>
</head>
<body>
<div id='hello'>dfdfdfd</div>
<script>
var out = 25,
inner = {
out: 20,
func: function () {
var out = 30;
return this.out;
}
};
console.log((inner.func, inner.func)());
console.log(inner.func());
console.log((inner.func)());
console.log((inner.func = inner.func)());
</script>
</body>
</html>
结果:
25
20
20
25
120、arr =[1,2,3,4,5,6,7,8],从数组每次取出3个数,如:123 456 781 234依次循环下去
可以使用队列:先进先出,就是每次执行的时候,先将数组前三个元素弹出保存在一个变量上,然后再将这三个元素push进数组里面
var arr = [1,2,3,4,5,6,7,8];
var temp;
var TempVar = '';
var num = 3;
var count = 0;
function loop(){
TempVar = '';
for(var i=0;i<num;i++){
temp = arr.shift();
TempVar += temp
arr.push(temp);
}
count++;
console.log('第'+count+'次输出: '+ TempVar);
setTimeout(loop,1000);
}
loop();
121、题目描述:输入:[2,3,4,[55,77,[6,43,2]],33]
输出:[2, 3, 4, 55, 77, 6, 43, 2, 33]
//正则,分割字符串
//将数组转成字符串,利用字符串的正则表达式和replace()将[]去掉,然后再转成数组,在将里面的元素转成数字
var arr=[2,3,4,[55,77,[6,43,2]],33];
var arrs = arr.toString();
var res = arrs.replace(/[]/g,""); //去掉所有的[] 字符串
var arr2 = res.split(",")
console.log(arr2); //数组
arr2 = arr2.map(function(item){
return item = parseInt(item);
});
console.log(arr2);
//递归 + 闭包
var arr=[2,3,4,[55,77,[6,43,2]],33];
function toArr(arr){
let result = [];
inner(arr);
function inner(arr){
let len = arr.length;
for(let i=0;i<len;i++){
if( {}.toString.call(arr[i]) === '[object Array]' ){
inner(arr[i]);
}else {
result.push(arr[i]);
}
}
}
return result;
}
console.log(toArr(arr));
122、规避javascript多人开发函数重名问题
1)使用命名空间:命名空间可以被认为是唯一标识符下代码的逻辑分组;防止与全局命名空间下的其他对象或变量产生冲突、有助于组织代码、有更强的可维护性和可读性。
由于javascript中只有函数作用域,那么把自定义的函数写到一个函数体内,这样函数内的变量、对象、函数就像在一个命名空间内一样和外部隔离(在立即执行函数里面,定义一个函数,并且定义他的原型,将其实例化给window的一个自定义属性)
(function(){
var _NS=function(){
}
_NS.prototype.alert=function(){
console.log('test');
}
window.NS=new _NS();
})();
调用的时候直接调用NS.alert()这样就不会和window.alert()函数重名了
2)尽量少在全局环境下定义变量
3)加上前缀
4)模块化开发
123、this的典型应用场景
1)作为对象方法调用,这时候要小心,如果在一个函数的里面有定义了一个函数并且内部有this对象,这时候通常会将this保存在that里面
var test = {
a:0,
b:0
get:function(){
return this.a;
}
}
var point = {
x : 0,
y : 0,
moveTo : function(x, y) {
var that = this; //that指向point对象
// 内部函数
var moveX = function(x) {
that.x = x;
};
// 内部函数
var moveY = function(y) {
that.y = y;
}
moveX(x);
moveY(y);
}
};
point.moveTo(1, 1);
point.x; //==>1
point.y; //==>1
2)作为函数调用
function makeNoSense(x) {
this.x = x;
}
3)作为构造函数调用
function Point(x, y){
this.x = x;
this.y = y;
}
4)在call和apply中使用
124、网页中实现一个计算当年还剩多少时间的倒数计时程序,要求网页上实时动态显示"××年还剩××天××时××分××秒"
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>TEst</title>
</head>
<body>
<span id="target"></span>
<script type="text/javascript">
// 为了简化。每月默认30天
function getTimeString() {
var start = new Date();
//new Date(1,0,1)这三个参数是年月天
var end = new Date(start.getFullYear() + 1, 0, 1); //月数从0开始
var elapse = Math.floor((end - start) / 1000);
var seconds = elapse % 60 ;
var minutes = Math.floor(elapse / 60) % 60;
var hours = Math.floor(elapse / (60 * 60)) % 24;
var days = Math.floor(elapse / (60 * 60 * 24)) % 30;
var months = Math.floor(elapse / (60 * 60 * 24 * 30)) % 12;
var years = Math.floor(elapse / (60 * 60 * 24 * 30 * 12));
return start.getFullYear() + '年还剩' + years + '年' + months + '月' + days + '日'
+ hours + '小时' + minutes + '分' + seconds + '秒';
}
//textContent和innerText是浏览器兼容性问题
function domText(elem, text) {
if (text == undefined) {
if (elem.textContent) {
return elem.textContent;
} else if (elem.innerText) {
return elem.innerText;
}
} else {
if (elem.textContent) {
elem.textContent = text;
} else if (elem.innerText) {
elem.innerText = text;
} else {
elem.innerHTML = text;
}
}
}
var target = document.getElementById('target');
setInterval(function () {
domText(target, getTimeString());
}, 1000)
</script>
</body>
</html>
126、兴趣爱好:主要是回答和你从事的岗位相关的答案,比如前端岗位,则关注一些公众号
127、实现对一个数组的混序,也就是洗牌
//里面定义一些公用的方法
//取一个包括min max的值
function getRandomInt(min, max) {
//Math.random()返回值0-1,包括0不包括1
//加1表示取到上限值
return Math.floor(Math.random() * (max - min + 1) + min)
}
//实现洗牌函数
function shuffle(arr) {
let len = arr.length
for (let i = 0; i < len; i++) {
//获取随机的index
let j = getRandomInt(0, i)
//进行元素间的交换
let t = arr[i]
arr[i] = arr[j]
arr[j] = t
}
return arr
}
128、vue中的混入对象mixins
vue中的混入对象mixins的定义
是一种分发 Vue 组件中可复用功能的非常灵活的方式。混入对象可以包含任意组件选项。当组件使用混入对象时,所有混入对象的选项将被混入该组件本身的选项
mixins:Array(Object)
选项合并:当组件和混入对象含有同名选项时,这些选项将以恰当的方式混合
1)同名钩子函数将混合为一个数组,因此都将被调用(组合)
2)混入对象的钩子将在组件自身钩子之前调用(调用顺序)
3)数据对象data在内部会进行浅合并 (一层属性深度),在和组件的数据发生冲突时以组件数据优先(冲突)
4)两个对象键名冲突时,取组件对象的键值对
129、vue中的vuex插件
vuex插件用于组件之间共享一些数据,具体可以参考网址:点击打开链接
地址:https://blog.csdn.net/tangxiujiang/article/details/80645416
130、javascript中的深拷贝和浅拷贝
编程实现使用JavaScript实现一个深拷贝方法
用递归实现深拷贝----Object.prototype.toString.call()函数实现深度拷贝
function getType(obj){
//tostring会返回对应不同的标签的构造函数
var toString = Object.prototype.toString;
var map = {
'[object Boolean]' : 'boolean',
'[object Number]' : 'number',
'[object String]' : 'string',
'[object Function]' : 'function',
'[object Array]' : 'array',
'[object Date]' : 'date',
'[object RegExp]' : 'regExp',
'[object Undefined]': 'undefined',
'[object Null]' : 'null',
'[object Object]' : 'object'
};
if(obj instanceof Element) {
return 'element';
}
return map[toString.call(obj)];
}
function deepClone(data){
var type = getType(data);
var obj;
if(type === 'array'){
obj = [];
for(var i = 0, len = data.length; i < len; i++){
obj.push(deepClone(data[i]));
}
} else if(type === 'object'){
obj = {};
for(var key in data){
obj[key] = deepClone(data[key]);
}
} else {
//不再具有下一层次
//函数不需要再进行遍历
obj = data;
}
return obj;
}
下面的方法可以实现深浅拷贝,用一个参数来表示
const isArray = data => Object.prototype.toString.call(data)==='[object Array]';
const isObject = data => Object.prototype.toString.call(data)==='[object Object]';
const isNullOrUndefined = data => Object.prototype.toString.call(data)==='[object Undefined]' || !!Object.prototype.toString.call(data)==='[object Null]'
function underscoreToHump(data, isDeep=true) {
let ret; //store compute result
let deep = isDeep;
if(isNullOrUndefined(data)){
throw Error('param is error');
}
if( isArray(data) ){
ret = [];
}else if( isObject(data) ){
ret = {};
}
for(let key in data){
let val = data[key];
let arrayFlag;
if(deep && ( arrayFlag=isArray(val) || !!isObject(val) )){
if(arrayFlag){
arrayFlag=false;
ret[key] = [];
}else{
ret[key] = {};
}
ret[key] = underscoreToHump(val, deep);
}else{
ret[key] = data[key];
}
}
return ret;
}
const testData = {
a_v: 123,
a_y: [1, 2, 3, 4],
a_d: {
s: 2,
s_3: 3
},
a_f: [{
a_g: 5
}],
a_a_d: 1
}
const result = underscoreToHump(testData,false)
result.a_y.push(1);
console.log(result)
console.log(testData)
JavaScript有两种数据类型:基础数据类型、引用数据类型
基础数据类型:按值访问,可以直接操作保存在变量中的实际值
引用类型:如Array,Object不能直接操作对象的堆内存空间;引用类型的值都是按引用访问的
深拷贝和浅拷贝的区别
浅拷贝(shallow copy):对于基础类型的复制是按值复制;对于引用类型是按照地址复制,新旧对象共享一块内存;
深拷贝(deep copy):复制并创建一个一摸一样的对象,不共享内存,修改新对象,旧对象保持不变。
1、数组
浅拷贝:相当于使两个数组指针指向相同的地址,任一个数组元素发生改变,影响另一个
深拷贝:两数组指针指向不同的地址,数组元素发生改变时不会相互影响
浅拷贝实现:赋值运算符
var a = [1, 2, 3]
b = a
console.log("a: ",a)
console.log("b: ",b)
b[0] = 99;
console.log("---- after changed array b ----- ")
console.log("a: ",a)
console.log("b: ",b)
深拷贝实现:concat() slice() map() reduce() forEach()
存在的问题:只能处理一层的深度拷贝
//1、slice()方法
//一维数组
// var a = [1, 2, 3, 4, 5, 6]
// b = a.slice(0)
// console.log("a: ",a)
// console.log("b: ",b)
// b[0] = 99;
// console.log("---- after changed deepClone array b ----- ")
// console.log("a: ",a)
// console.log("b: ",b)
//运行结果
// a: [ 1, 2, 3, 4, 5, 6 ]
// b: [ 1, 2, 3, 4, 5, 6 ]
// ---- after changed deepClone array b -----
// a: [ 1, 2, 3, 4, 5, 6 ]
// b: [ 99, 2, 3, 4, 5, 6 ]
//二维数组
// var a = [[1, 2, 3], 4, [5, 6]]
// b = a.slice(0)
// console.log("a: ",a)
// console.log("b: ",b)
// b[0][0] = 99;
// console.log("---- after changed deepClone array b ----- ")
// console.log("a: ",a)
// console.log("b: ",b)
//输出结果
// a: [ [ 1, 2, 3 ], 4, [ 5, 6 ] ]
// b: [ [ 1, 2, 3 ], 4, [ 5, 6 ] ]
// ---- after changed deepClone array b -----
// a: [ [ 99, 2, 3 ], 4, [ 5, 6 ] ]
// b: [ [ 99, 2, 3 ], 4, [ 5, 6 ] ]
//2、concat()方法
//一维数组
// var a = [1, 2, 3, 4, 5, 6]
// b = a.concat([])
// console.log("a: ",a)
// console.log("b: ",b)
// b[0] = 99;
// console.log("---- after changed deepClone array b ----- ")
// console.log("a: ",a)
// console.log("b: ",b)
//运行结果
// a: [ 1, 2, 3, 4, 5, 6 ]
// b: [ 1, 2, 3, 4, 5, 6 ]
// ---- after changed deepClone array b -----
// a: [ 1, 2, 3, 4, 5, 6 ]
// b: [ 99, 2, 3, 4, 5, 6 ]
//二维数组
// var a = [[1, 2, 3], 4, [5, 6]]
// b = a.concat([])
// console.log("a: ",a)
// console.log("b: ",b)
// b[0][0] = 99;
// console.log("---- after changed deepClone array b ----- ")
// console.log("a: ",a)
// console.log("b: ",b)
// 运行结果
// a: [ [ 1, 2, 3 ], 4, [ 5, 6 ] ]
// b: [ [ 1, 2, 3 ], 4, [ 5, 6 ] ]
// ---- after changed deepClone array b -----
// a: [ [ 99, 2, 3 ], 4, [ 5, 6 ] ]
// b: [ [ 99, 2, 3 ], 4, [ 5, 6 ] ]
//3、map()方法
//一维数组
// var a = [1, 2, 3, 4, 5, 6]
// b = a.map(function(item){
// return item;
// })
// console.log("a: ",a)
// console.log("b: ",b)
// b[0] = 99;
// console.log("---- after changed deepClone array b ----- ")
// console.log("a: ",a)
// console.log("b: ",b)
//运行结果
// a: [ 1, 2, 3, 4, 5, 6 ]
// b: [ 1, 2, 3, 4, 5, 6 ]
// ---- after changed deepClone array b -----
// a: [ 1, 2, 3, 4, 5, 6 ]
// b: [ 99, 2, 3, 4, 5, 6 ]
//二维数组
// var a = [[1, 2, 3], 4, [5, 6]]
// b = a.map(function(item){
// return item;
// })
// console.log("a: ",a)
// console.log("b: ",b)
// b[0][0] = 99;
// console.log("---- after changed deepClone array b ----- ")
// console.log("a: ",a)
// console.log("b: ",b)
// 运行结果
// a: [ [ 1, 2, 3 ], 4, [ 5, 6 ] ]
// b: [ [ 1, 2, 3 ], 4, [ 5, 6 ] ]
// ---- after changed deepClone array b -----
// a: [ [ 99, 2, 3 ], 4, [ 5, 6 ] ]
// b: [ [ 99, 2, 3 ], 4, [ 5, 6 ] ]
//3、forEach()方法
//一维数组
// var a = [1, 2, 3, 4, 5, 6],b=[]
// a.forEach(function(item){
// b.push(item);
// })
// console.log("a: ",a)
// console.log("b: ",b)
// b[0] = 99;
// console.log("---- after changed deepClone array b ----- ")
// console.log("a: ",a)
// console.log("b: ",b)
//运行结果
// a: [ 1, 2, 3, 4, 5, 6 ]
// b: [ 1, 2, 3, 4, 5, 6 ]
// ---- after changed deepClone array b -----
// a: [ 1, 2, 3, 4, 5, 6 ]
// b: [ 99, 2, 3, 4, 5, 6 ]
//二维数组
var a = [[1, 2, 3], 4, [5, 6]],b=[]
a.forEach(function(item){
b.push(item);
})
console.log("a: ",a)
console.log("b: ",b)
b[0][0] = 99;
console.log("---- after changed deepClone array b ----- ")
console.log("a: ",a)
console.log("b: ",b)
// 运行结果
// a: [ [ 1, 2, 3 ], 4, [ 5, 6 ] ]
// b: [ [ 1, 2, 3 ], 4, [ 5, 6 ] ]
// ---- after changed deepClone array b -----
// a: [ [ 99, 2, 3 ], 4, [ 5, 6 ] ]
// b: [ [ 99, 2, 3 ], 4, [ 5, 6 ] ]
深拷贝实现:jQuery的extend函数,
// jQuery.extend([deep], target, object1, object2, object3...),
// [deep]:默认false;值为true时深度合并对象,false的时候能进行一层深度拷贝
// target:其他对象复制到该对象
// object:被合并的对象
1、一维数组
var a = [1, 2, 3]
b = $.extend(false, [], a) //设置成true 和 false的结果一样
// b = $.extend(true, [], a)
console.log("a: ",a) //[1,2,3]
console.log("b: ",b) //[1,2,3]
b[0] = 99;
console.log("---- after changed deepClone array b ----- ")
console.log("a: ",a) //[1,2,3]
console.log("b: ",b) //[99,2,3]
2、多维数组
将[deep]设为false
var a = [[1, 2, 3], 4, [5, 6]]
b = $.extend(false,[], a)
console.log("a: ",a)
console.log("b: ",b)
b[0][0] = 99;
console.log("---- after changed deepClone array b ----- ")
console.log("a: ",a)
console.log("b: ",b)
结果:这里将[deep]设为false,然后,改变前后的a b 的值都一样,具体是因为什么,暂且不知道,希望大神指教
将[deep]设为true:可以看出a和b的值不一样,但是修改后的b影响修改后的b,两个的输出值一样
var a = [[1, 2, 3], 4, [5, 6]]
b = $.extend(true,[], a)
console.log("a: ",a)
console.log("b: ",b)
b[0][0] = 99;
console.log("---- after changed deepClone array b ----- ")
console.log("a: ",a)
console.log("b: ",b)
结果:
总结:为了实现真正的Array的深拷贝,应该使用jQuery.extend(true,[],arr1,arr2,arr3...)
2、对象Object
浅拷贝:只拷贝对象的第一层属性,对于属性中包含的属性不会复制;由于JavaScript对象均以地址的方式存贮,所以浅复制导致多个对象的属性均指向同一块地址。
深拷贝:对对象的每一层属性进行递归复制,深层次的属性也不会指向同一块地址
浅拷贝:自定义函数
function shallowCopy(obj1, obj2) {
for( var key in obj1){
if (obj1.hasOwnProperty(key)) {
obj2[key] = obj1[key]
}
}
}
function showKeys(obj) {
for( var key in obj){
if (obj.hasOwnProperty(key)) {
console.log(key, ":", obj[key]);
}
}
}
var a = {
sing:true,
dance:{today:false, tommorrw:true}
}
b = {}
shallowCopy(a, b)
showKeys(a)
showKeys(b)
b.sing = false
b.dance.today = true
console.log("------------- after changed object b -------------- ")
showKeys(a)
showKeys(b)
输出结果:由于对象的浅拷贝只复制第一层属性,因此obj b第一层属性的改变不会影响复制源,而第二层属性仍指向同一块地址,因此obj b的dance属性的today属性作改变之后,同一块地址处的obj a的dance属性的today属性同时变化了
sing : true
dance : { today: false, tommorrw: true }
sing : true
dance : { today: false, tommorrw: true }
------------- after changed object b --------------
sing : true
dance : { today: true, tommorrw: true }
sing : false
dance : { today: true, tommorrw: true }
深拷贝:使用JQuery的extend(),[deep]设为true表示深复制,互不影响,false浅拷贝对于引用类型有影响
function showKeys(obj) {
for( var key in obj){
if (obj.hasOwnProperty(key)) {
console.log(key, ":", obj[key]);
}
}
}
var a = {
sing:true,
dance:{today:false, tommorrw:true}
}
b = $.extend(true, {}, a)
showKeys(a)
showKeys(b)
b.sing = false
b.dance.today = true
console.log("------------- after changed object b -------------- ")
showKeys(a)
showKeys(b)
递归拷贝:
function deepClone(initalObj, finalObj) {
var obj = finalObj || {};
for (var i in initalObj) {
var prop = initalObj[i]; // 避免相互引用对象导致死循环,如initalObj.a = initalObj的情况
if(prop === obj) {
continue;
}
if (typeof prop === 'object') {
obj[i] = (prop.constructor === Array) ? [] : {};
arguments.callee(prop, obj[i]);
} else {
obj[i] = prop;
}
}
return obj;
}
var str = {};
var obj = { a: {a: "hello", b: 21} };
deepClone(obj, str);
console.log(str.a);
131、css预处理器:stylus
stylus:是css的一个预处理工具,对css的一个延伸和强化;是一种富有表现力的、动态的、强壮的css
1、stylus相对于SASS更简洁:冒号可以省略;用空格分隔属性名和多个属性值就可以生成css;可以拼接字符串;支持缩进语法;
body
border 10px soli+'d' darken(red,10%)
等同于:
body {
border: 1px solid #e60000;
}
2、动态性:Stylus由Javascript编译,其结构语句也和Javascript相差不多;Stylus较之LESS则要优越不少,不仅仅是可定义变量,如Javascript般的条件语句和循环语句也为Stylus带来各种可能,加上丰富的内置函数,可以轻松判断和操作各种变量。而利用这样的动态性,就可以写出非常强壮的CSS以满足不同环境和条件下的需要。定义函数、定义mixins、定义常量
131、平时怎么学习的
1)做项目的时候会用到一些之前没有接触过的技术,这时候就会去看别人写的博客或者去stackoverflow查看
2)平时会买点书籍来补充自己的基础知识
3)去淘宝上买些视频或者慕课网上看些教学视频,然后动手去实现一些小DEMO
4)在github上看些开源项目,动手去实现里面的功能
131、d3和echarts的原理、区别
他们都是用于数据可视化中,实现图表的绘制
优缺点
D3:
1)太底层,学习成本大
2)兼容到IE9以上以及所有的主流浏览器
3)D3通过svg来绘制图形,可以自定义事件
Svg的优点
1)不依赖分辨率
2)基于xml绘制图形,可以操作dom、支持事件处理器
3)复杂度高,会减慢页面的渲染速度
Echarts:
1) 封装好的方法可以直接调用
2)兼容到ie6以及以上的所有主流浏览器
3)echarts通过canvas来绘制图形
Canvas:
1)依赖分辨率
2)基于js绘制图形、不支持事件处理器
3)能以png或者jpg的格式保存图片
应用场景
1)前端将数据通过图表的形式展示给用户,一般使用echarts----Echarts里面的方法封装比较好,用的时候直接调用就能实现效果
对于echarts的使用比较简单,引入echarts.js,然后就可以通过 echarts.init 方法初始化一个 echarts 实例并通过 setOption 方法设置图表实例的配置项以及数据,万能接口,所有参数和数据的修改都可以通过setOption完成,ECharts 会合并新的参数和数据,然后刷新图表。如果开启动画的话,ECharts 找到两组数据之间的差异然后通过合适的动画去表现数据的变化
2)对事件监听的话,一般使用D3---使用svg绘制图形,支持事件处理器。需要自己添加画布,绘制图形,绘制的每一个图形都为一个对象,可以添加相应的事件操作,操作dom
131、Servlet的生命周期
Servlet的生命周期指的是 Servlet从被Web服务器加载到它被销毁的整个生命过程
1)初始化阶段,调用init()方法
2)响应客户请求阶段,调用service()方法
3)终止阶段,调用destory()方法
Servlet的工作原理
1)首先客户发送个请求,Servlet容器会创建特定于这个请求的ServletRequest对象和ServletResponse对象
2)然后调用Servlet的service()方法,Service()方法从ServletRequest对象获得客户请求信息,处理该请求,然后通过ServletResponse对象向客户返回响应信息
131、平衡二叉树的原理(AVL算法)
特点:它是一 棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树
131、服务端渲染和客户端渲染的区别
服务端渲染的定义---SSR
一些没有复杂逻辑的、简单的页面,由后端将html和数据拼接好,然后将其返回给浏览器,浏览器拿到这个html文件之后就可以直接渲染展示了
客户端渲染的定义----CSR
随着前端页面的复杂性提高,前端就不仅仅是普通的页面展示了,而可能添加了更多功能性的组件,复杂性更大,另外,彼时ajax的兴起,使得业界就开始推崇前后端分离的开发模式,即后端不提供完整的html页面,而是提供一些api使得前端可以获取到json数据,然后前端拿到json数据之后再在前端进行html页面的拼接,然后展示在浏览器上,这就是所谓的客户端渲染了,这样前端就可以专注UI的开发,后端专注于逻辑的开发。
两者本质的区别---html文件由谁拼接完成
如果html文件的拼接是由服务器端完成的,然后返回给客户端,就是服务器端渲染
如果html文件的拼接是由前端完成的,则就是客户端渲染
服务器端渲染的优缺点是怎样的?
优点:
- 前端耗时少。因为后端拼接完了html,浏览器只需要直接渲染出来。
- 有利于SEO。因为在后端有完整的html页面,所以爬虫更容易爬取获得信息,更有利于seo。
- 无需占用客户端资源。即解析模板的工作完全交由后端来做,客户端只要解析标准的html页面即可,这样对于客户端的资源占用更少,尤其是移动端,也可以更省电。
- 后端生成静态化文件。即生成缓存片段,这样就可以减少数据库查询浪费的时间了,且对于数据变化不大的页面非常高效 。
缺点:
- 不利于前后端分离,开发效率低。使用服务器端渲染,则无法进行分工合作,则对于前端复杂度高的项目,不利于项目高效开发。另外,如果是服务器端渲染,则前端一般就是写一个静态html文件,然后后端再修改为模板,这样是非常低效的,并且还常常需要前后端共同完成修改的动作; 或者是前端直接完成html模板,然后交由后端。另外,如果后端改了模板,前端还需要根据改动的模板再调节css,这样使得前后端联调的时间增加。
- 占用服务器端资源。即服务器端完成html模板的解析,如果请求较多,会对服务器造成一定的访问压力。而如果使用前端渲染,就是把这些解析的压力分摊了前端,而这里确实完全交给了一个服务器
客户端渲染的优缺点是怎样的?
优点:
- 前后端分离。前端专注于前端UI,后端专注于api开发,且前端有更多的选择性,而不需要遵循后端特定的模板。
- 体验更好。比如,我们将网站做成SPA或者部分内容做成SPA,这样,尤其是移动端,可以使体验更接近于原生app。
缺点:
- 前端响应较慢。如果是客户端渲染,前端还要进行拼接字符串的过程,需要耗费额外的时间,不如服务器端渲染速度快。
- 不利于SEO。目前比如百度、谷歌的爬虫对于SPA都是不认的,只是记录了一个页面,所以SEO很差。因为服务器端可能没有保存完整的html,而是前端通过js进行dom的拼接,那么爬虫无法爬取信息。 除非搜索引擎的seo可以增加对于JavaScript的爬取能力,这才能保证seo。
使用服务器端渲染还是客户端渲染?
不谈业务场景而盲目选择使用何种渲染方式都是耍流氓。比如企业级网站,主要功能是展示而没有复杂的交互,并且需要良好的SEO,则这时我们就需要使用服务器端渲染;而类似后台管理页面,交互性比较强,不需要seo的考虑,那么就可以使用客户端渲染。
另外,具体使用何种渲染方法并不是绝对的,比如现在一些网站采用了首屏服务器端渲染,即对于用户最开始打开的那个页面采用的是服务器端渲染,这样就保证了渲染速度,而其他的页面采用客户端渲染,这样就完成了前后端分离。
究竟如何理解前后端分离?
实际上,时至今日,前后端分离一定是必然趋势,如今的网页功能越来越复杂,交互越来越多,将页面的渲染交给前端会比较好,使后台专注逻辑,前端专注UI。而我们目前接触到的前端工程化、编译(转译)、各种MVC/MVVM框架、依赖工具、npm、bable、webpack都给前端的工作性能和效率带来很大的提升
132、git的操作--主要是分支和合并(解决合并冲突)
http://www.ruanyifeng.com/blog/2015/12/git-cheat-sheet.html 详情
在当前目录新建代码库:git init
下载一个项目和他的整个历史:git clone [url]
配置:git config
增加:git add
删除:git rm git mv
提交:git commit
分支:git branch
切换:git checkout
合并:git merge
:git push
标签:git tag
查看:git show
显示变更文件:git status
显示提交历史:git log 6
132、 a^n 用小于 O(n) 的算法实现 -----用分治法和递归
每次重复相同操作,用递归
// 实现a^n,要求复杂度小于O(n)
// 用分治法和递归实现,时间复杂度为O(log(n))
function power(a,n){
if(n===0){
return 1;
}else if(n===1){
return a;
}else if( parseInt(n%2) === 0 ){
return power( a,n/2 ) * power( a,n/2 );
}else if( parseInt(n%2) !== 0 ){
return power( a, parseInt(n/2) ) * power( a, parseInt(n/2) ) * a ;
}s
}
console.log( power(3,2) );
132、多端适配如何做?页面兼容平板、手机、PC等
1)flex布局:给flex容器设置:display:flex
容器属性
flex-direction:决定主轴的方向(项目的排列方向),row | row-reverse | column | column-reverse
flex-wrap:如果一条轴线排不下了,该如何换行,nowrap | wrap | wrap-reverse
flex-flow: flex-direction flex-wrap的简写
justify-content:项目在主轴上的排列方式
align-items:项目在交叉轴上的对齐方式
项目属性
order:项目排列顺序,数值越小越靠前
flex-growth:项目放大比例,默认为0,即存在剩余空间也不放大
flex-shrink:项目缩放比率,默认为1,空间不足,进行缩小
flex-basie:在分配剩余空间之前,给项目分配的空间
flex:flex-growth flex-shrink flex-basie的缩写
2)媒介查询,@media screen and (max-width:900px) and (min-width:100px)----判断终端设备宽度在多少像素内,然后就执行与之对应的CSS样式