[TOC]
編寫一個方法,求一個字串的長度
function getbytes(str){
var len = str.length;
var bytes = len;
for (var i=0;i<len;i++){
if(str.charCodeAt(i)>255)bytes++
}
return bytes;
}
複製程式碼
如何統計字串“aaaabbbccccddfgh”
var str = 'aaaabbbccccddfgh';
dealStr(str);
function dealStr(str) {
var obj = {};
for(var i=0;i<str.length;i++){
var v = str.charAt(i);
if(obj[v] && obj[v].value === v){
++obj[v].count
}else{
obj[v] = {
count:1,
value:v
}
}
}
return obj;
}
var obj = dealStr(str);
for(key in obj){
console.log(obj[key].value + '=' +obj[key].count)
}
複製程式碼
深拷貝
//deepClone函式
function deepClone(obj){
let objClone = Array.isArray(obj)?[]:{};
if(obj && typeof obj === 'object'){
for(key in obj){
if(obj.hasOwnProperty(key)){
//判斷obj子元素是否為物件,如果是,遞迴複製
if(obj[key] && typeof obj[key] == 'object'){
objClone[key] = deepClone(obj[key]);
}else{
objClone[key] = obj[key];
}
}
}
}
}
複製程式碼
寫一個function,清除字串前後的空格(相容所有瀏覽器)
function trim(str) {
if(str && typeof str == 'string'){
return str.replace(/^\s+|\s+$/g,"");
}
}
複製程式碼
請說出阻止事件冒泡的方法
function stopBubble(e) {
var evt = e||window.event;
evt.stopPropagation ? evt.stopPropagation() : (evt.cancelBubble = true);
}
複製程式碼
以下兩個函式會返回相同的結果嗎?為什麼
function foo1() {
return {
bar:'hello'
}
}
function foo2() {
return
{
bar:'hello'
}
}
//第一個返回一個物件
//第二個返回undefine 因為第二個 return 後面沒內容,分號自動載入 return 後面
複製程式碼
判斷一個數字是否是整數
//es6
Number.isInteger()
//非es6
function isInteger(x) {
return (x^0) === x;
}
複製程式碼
寫一個sum方法,在使用任意語法呼叫時,都可以正常工作
//方法一
function sum(x) {
if(arguments.length === 2){
return arguments[0] + arguments[1];
}else{
return function (y) {
return x+y
}
}
}
//方法二
function sum2(x,y) {
if(y !== undefined){
return x+y;
}else{
return function (y) {
x+y;
}
}
}
複製程式碼
下面的程式碼將輸出什麼內容到控制檯?
var myObject = {
foo:'bar',
func:function(){
var self = this;
console.log("outer func: this.foo = " + this.foo);
console.log("outer func: self.foo =" + self.foo);
(function(){
console.log("inner func: this.foo="+this.foo);
console.log("inner func: self.foo="+self.foo);
}())
}
}
//輸出
outer func: this.foo = bar
outer func:self.foo = bar
inner func: this.foo = undefined
inner func: self.foo = bar
複製程式碼
下面的程式碼將輸出什麼?閉包在這裡能起什麼作用?
for(var i=0;i<5;i++){
(function(){
setTimeout(function(){
console.log(i)
},i*1000)
}())
}
//輸出 5 5 5 5 5
//原因:在迴圈中執行的每個函式將先整個迴圈完成之後執行,因此,將會引用儲存在i中的最後一個值,那就是5
//閉包可以為每次迭代建立一個唯一的作用域,儲存作用域內的迴圈變數,如下程式碼會按預期輸出0、1、2、3、4到控制檯
for(var i=0;i<5;i++){
(function(x){
setTimeout(function(){
console.log(x)
},x*1000)
})(i)
}
複製程式碼
一下程式碼行將輸出什麼到控制檯
console.log("0 || 1 ="+(0 || 1));
console.log("1 || 2 ="+(1 || 2));
console.log("0 && 1 ="+(0 && 1));
console.log("1 && 2 ="+(1 && 2));
//輸出
//0 || 1 = 1;
//1 || 2 = 1;
//0 && 1 = 0;
//1 && 2 = 2
複製程式碼
以下程式碼將輸出什麼?
var a={},b={key:'b'},c={key:'c'};
a[b] = 123;
a[c] = 456;
console.log(a[b]);
//輸出 456
//當設定物件屬性時,JavaScript 會隱式地將[]內的變數轉換成字串,在這種情況下,由於b和c都是物件,
因此它們都將被轉換為[object Object]。結果就是,a[b]和a[c]均相當於a["[object Object]"],
並可以互換使用。因此,設定或引用a[c]和設定或引用a[b]完全相同。
複製程式碼
防抖
防抖是將多次執行操作轉變成一次
/**
* underscore 防抖函式,返回函式連續呼叫時,空閒時間必須大於或等於 wait,func 才會執行
*
* @param {function} func 回撥函式
* @param {number} wait 表示時間視窗的間隔
* @param {boolean} immediate 設定為ture時,是否立即呼叫函式
* @return {function} 返回客戶呼叫函式
*/
_.debounce = function(func, wait, immediate) {
var timeout, args, context, timestamp, result;
var later = function() {
// 現在和上一次時間戳比較
var last = _.now() - timestamp;
// 如果當前間隔時間少於設定時間且大於0就重新設定定時器
if (last < wait && last >= 0) {
timeout = setTimeout(later, wait - last);
} else {
// 否則的話就是時間到了執行回撥函式
timeout = null;
if (!immediate) {
result = func.apply(context, args);
if (!timeout) context = args = null;
}
}
};
return function() {
context = this;
args = arguments;
// 獲得時間戳
timestamp = _.now();
// 如果定時器不存在且立即執行函式
var callNow = immediate && !timeout;
// 如果定時器不存在就建立一個
if (!timeout) timeout = setTimeout(later, wait);
if (callNow) {
// 如果需要立即執行函式的話 通過 apply 執行
result = func.apply(context, args);
context = args = null;
}
return result;
};
};
複製程式碼
節流
節流是將多次執行變成每隔一段時間執行
/**
* underscore 節流函式,返回函式連續呼叫時,func 執行頻率限定為 次 / wait
*
* @param {function} func 回撥函式
* @param {number} wait 表示時間視窗的間隔
* @param {object} options 如果想忽略開始函式的的呼叫,傳入{leading: false}。
* 如果想忽略結尾函式的呼叫,傳入{trailing: false}
* 兩者不能共存,否則函式不能執行
* @return {function} 返回客戶呼叫函式
*/
_.throttle = function(func, wait, options) {
var context, args, result;
var timeout = null;
// 之前的時間戳
var previous = 0;
// 如果 options 沒傳則設為空物件
if (!options) options = {};
// 定時器回撥函式
var later = function() {
// 如果設定了 leading,就將 previous 設為 0
// 用於下面函式的第一個 if 判斷
previous = options.leading === false ? 0 : _.now();
// 置空一是為了防止記憶體洩漏,二是為了下面的定時器判斷
timeout = null;
result = func.apply(context, args);
if (!timeout) context = args = null;
};
return function() {
// 獲得當前時間戳
var now = _.now();
// 首次進入前者肯定為 true
// 如果需要第一次不執行函式
// 就將上次時間戳設為當前的
// 這樣在接下來計算 remaining 的值時會大於0
if (!previous && options.leading === false) previous = now;
// 計算剩餘時間
var remaining = wait - (now - previous);
context = this;
args = arguments;
// 如果當前呼叫已經大於上次呼叫時間 + wait
// 或者使用者手動調了時間
// 如果設定了 trailing,只會進入這個條件
// 如果沒有設定 leading,那麼第一次會進入這個條件
// 還有一點,你可能會覺得開啟了定時器那麼應該不會進入這個 if 條件了
// 其實還是會進入的,因為定時器的延時
// 並不是準確的時間,很可能你設定了2秒
// 但是他需要2.2秒才觸發,這時候就會進入這個條件
if (remaining <= 0 || remaining > wait) {
// 如果存在定時器就清理掉否則會呼叫二次回撥
if (timeout) {
clearTimeout(timeout);
timeout = null;
}
previous = now;
result = func.apply(context, args);
if (!timeout) context = args = null;
} else if (!timeout && options.trailing !== false) {
// 判斷是否設定了定時器和 trailing
// 沒有的話就開啟一個定時器
// 並且不能不能同時設定 leading 和 trailing
timeout = setTimeout(later, remaining);
}
return result;
};
};
複製程式碼