Skip to content

Instantly share code, notes, and snippets.

@YaoKaiLun
Last active January 29, 2019 09:02
Show Gist options
  • Save YaoKaiLun/bbddc33fa9d885e735969f09f74016e1 to your computer and use it in GitHub Desktop.
Save YaoKaiLun/bbddc33fa9d885e735969f09f74016e1 to your computer and use it in GitHub Desktop.
the practice of javascript
/*
* 要求:实现一个div滑动的动画,由快至慢5s结束
* 参考:https://developers.google.com/web/fundamentals/design-and-ux/animations/css-vs-javascript?hl=zh-tw
*/
function Box() {
let startTime = 0
const ACCEL = 30
const TIME = 5
let initSpeed = ACCEL * TIME
let testDom = document.querySelector('#test')
this.startAnimation = function() {
startTime = Date.now()
requestAnimationFrame(frameUpdate)
}
function frameUpdate() {
let currentTime = (Date.now() - startTime) / 1000
if (currentTime >=5) return
let position = parseInt(initSpeed * currentTime - 1/2 * ACCEL * Math.pow(currentTime, 2))
testDom.style.transform = 'translateX(' + position + 'px)'
requestAnimationFrame(frameUpdate)
}
}
let box = new Box()
box.startAnimation()
/*
* 要求:实现 bind 的 polyfill
* 参考:https://github.com/mqyqingfeng/Blog/issues/12
*/
// simple
if(!Function.prototype.bind) {
Function.prototype.bind = function(context) {
let preArgs = [].slice.call(arguments, 1)
let self = this
return function() {
let nextArgs = [].slice.call(arguments)
self.apply(context, preArgs.concat(nextArgs))
}
}
}
/*
* complex
* 上面情况在构造调用前执行 bind 会出现问题,它会永久绑定指定的 this。 而真实情况是,构造函数的优先级高于 bind
*/
if(!Function.prototype.bind) {
Function.prototype.bind = function(context) {
if (typeof this !== 'function') {
throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable');
}
let preArgs = [].slice.call(arguments, 1)
let self = this
function fNOP() {}
let fBound = function() {
let nextArgs = [].slice.call(arguments)
self.apply(this instanceof fNOP ? this : context, preArgs.concat(nextArgs))
}
fNOP.prototype = this.prototype
fBound.prototype = fNOP.prototype
return fBound
}
}
// 防抖,不固定时间
function debounce(callback, time) {
let timer
return function(...args) {
clearTimeout(timer)
let context = this
timer = setTimeout(() => {
callback.apply(context, args)
}, time)
}
}
// 节流,固定时间
function throttle(callback, time) {
let timer
let start = +new Date()
return function(...args) {
clearTimeout(timer)
let context = this
let now = +new Date()
if (now - start >= time) {
callback.apply(context, args)
start = now
} else {
timer = setTimeout(function() {
callback(...args)
}, time)
}
}
}
function clone(item) {
if (!item) { return item; } // null, undefined values check
let types = [ Number, String, Boolean ], result;
// normalizing primitives if someone did new String('aaa'), or new Number('444');
types.forEach(function(type) {
if (item instanceof type) {
result = type(item);
}
});
if (typeof result == "undefined") {
if (Object.prototype.toString.call( item ) === "[object Array]") {
result = [];
item.forEach(function(child, index, array) {
result[index] = clone( child );
});
} else if (typeof item == "object") {
// testing that this is DOM
if (item.nodeType && typeof item.cloneNode == "function") {
result = item.cloneNode( true );
} else if (!item.prototype) { // check that this is a literal
if (item instanceof Date) {
result = new Date(item);
} else {
// it is an object literal
result = {};
for (let i in item) {
result[i] = clone( item[i] );
}
}
} else {
// depending what you would like here,
// just keep the reference, or create new object
if (false && item.constructor) {
// would not advice to do that, reason? Read below
result = new item.constructor();
} else {
result = item;
}
}
} else {
result = item;
}
}
return result;
}
// 测试数据
let copy = clone({
one : {
'one-one' : new String("hello"),
'one-two' : ["one", "two", true, "four"]
},
two : document.createElement("div"),
three : [
{
name : "three-one",
number : new Number("100"),
obj : new function() {
this.name = "Object test";
}
}
]
})
function getStyle(el, styleProp) {
var value, defaultView = el.ownerDocument.defaultView;
if (defaultView && defaultView.getComputedStyle) {
// sanitize property name to css notation (hypen separated words eg. font-Size)
styleProp = styleProp.replace(/([A-Z])/g, "-$1").toLowerCase();
return defaultView.getComputedStyle(el, null).getPropertyValue(styleProp);
} else if (el.currentStyle) { // IE
// sanitize property name to camelCase
styleProp = styleProp.replace(/\-(\w)/g, function(str, letter) {
return letter.toUpperCase();
});
value = el.currentStyle[styleProp];
// convert other units to pixels on IE
if (/^\d+(em|pt|%|ex)?$/i.test(value)) {
return (function(value) {
var oldLeft = el.style.left, oldRsLeft = el.runtimeStyle.left;
el.runtimeStyle.left = el.currentStyle.left;
el.style.left = value || 0;
value = el.style.pixelLeft + "px";
el.style.left = oldLeft;
el.runtimeStyle.left = oldRsLeft;
return value;
})(value);
}
return value;
}
}
// 质数定义为在大于1的自然数中,除了1和它本身以外不再有其他因数。
function isPrimes(num) {
if (num <= 1) return false
for (let i = 2, s = Math.sqrt(num); i <= s; i++) {
if (num % i === 0) return false
}
return true
}
/*
* 实现 promise 的 polyfill
* 参考:https://github.com/forthealllight/blog/issues/4
* 要点:由于调用成功后开发者会自己调用 resolve,因此并不需要轮询之类的,来确定执行成功
* 以下只支持异步 Promise 和单个 then 绑定,不支持链式调用
*/
/*
* 思路:
* 接受一个函数做参数,调用并传回 resolve 和 reject 函数
* 返回一个 then 函数
*/
let p = new Promise(function(resolve, reject) {
if(true) {
resolve('data')
} else {
reject('err')
}
})
// 1.简易版本,支持一个 then
p.then(() => {}, () => {})
// 2.支持多个 then
p.then(() => {}, () => {})
// 3.支持链式调用
p.then(() => {}, () => {}).then(() => {}, () => {})
// 实现:
function Promise2(callback) {
let self = this
this.status = 'pendding'
this.successCallback = null
this.failCallback = null
function resolve(data) {
self.status = 'fulfilled'
self.value = data
if(self.successCallback) {
self.successCallback(data)
}
}
function reject(err) {
self.status = 'rejected'
self.error = err
if(self.failCallback) {
this.failCallback(err)
}
}
callback(resolve, reject)
}
Promise2.prototype.then = function(successCallback, failCallback) {
switch(this.status) {
case 'pendding':
this.successCallback = successCallback
this.failCallback = failCallback
case 'fulfilled':
successCallback(this.value)
break
case 'rejected':
failCallback(this.error)
break
}
}
var events = {
events: {},
on: function (eventName, fn) {
this.events[eventName] = this.events[eventName] || [];
this.events[eventName].push(fn);
},
off: function(eventName, fn) {
if (this.events[eventName]) {
for (var i = 0; i < this.events[eventName].length; i++) {
if (this.events[eventName][i] === fn) {
this.events[eventName].splice(i, 1);
break;
}
};
}
},
emit: function (eventName, data) {
if (this.events[eventName]) {
this.events[eventName].forEach(function(fn) {
fn(data);
});
}
}
};
/*
* 要求:数组去重
* 参考:https://stackoverflow.com/questions/9229645/remove-duplicate-values-from-js-array
*/
/*
* 1. filter 和 indexof
* 有性能问题
*/
function unique(arr) {
retunr arr.filter(function(item, pos, self) {
return self.indexOf(item) == pos;
})
}
/*
* 2. hash table 和 filter
* javascript 中的对象键类型为 string,因此 "1" and 1 和被认为是重复的,可通过 es6 的 set 或 map 来优化
*/
function unique(arr) {
let hashTable = {}
arr.filter(function(item) {
return hashTable.hasOwnProperty(item) ? false : (hashTable[item] = true)
})
}
/*
* 3. 先排序后过滤
*/
function unique(arr) {
return arr.sort().filter(function(item, pos, ary) {
return !pos || item != ary[pos - 1];
})
}
/*
* 4. es6
*/
function unique(arr) {
return [...new Set(arr)]
}
/*
* 要求:实现一个简单的模板引擎
* 参考:http://blog.jobbole.com/56689/
*/
let template = "<p>你好,我是<%this.name%>,</p><i><%this.alias%></i>"
let data = {
name: '姚凯伦',
alias: 'ykl'
}
function templateEngine(tmpl, data) {
let sentence = convertTmplToSentence(tmpl, data)
return new Function(sentence).apply(data)
}
function convertTmplToSentence(tmpl, data) {
let regex = /<%([^%>]+)?%>/g
let grammarRegex = /(^( )?(if|for|else|switch|case|break|{|}))(.*)?/g
let code = 'var r=[];\n'
/*
* 三种情况:
* 字符串,以普通字符串形式 push 到 code
* 变量 <%%>,以变量形式 push 到 code
* 语句 <%if|for|else|switch|case|break|{|})%>,直接执行
*/
let cursor = 0
let match
while(match = regex.exec(tmpl)) {
let str = tmpl.slice(cursor, match.index)
code += 'r.push("' + str.replace(/"/g, '\\"') + '");\n'
if (match[1].match(grammarRegex)) {
code += match[1] + '\n'
} else {
code += 'r.push(' + match[1] + ');\n'
}
cursor = match.index + match[0].length;
}
code += 'r.push("' + tmpl.substr(cursor, tmpl.length - cursor) +'");\n'
code += 'return r.join("");';
return code.replace(/[\r\t\n]/g, '')
}
console.log('result', templateEngine(template, data))
/*
* 要求:求字符串的字节长度
* 参考:http://www.ruanyifeng.com/blog/2014/12/unicode.html
*/
// 方法一:
function byteLength(str) {
let len = str.length;
for (let i = len - 1; i >= 0; i--) {
let code = str.charCodeAt(i);
if (code > 0x7f && code <= 0x7ff) len++;
else if (code > 0x7ff && code <= 0xffff) len += 2;
if (code >= 0xDC00 && code <= 0xDFFF) i--; // trail surrogate (超过两个字节会被拆分为两个)
}
return s;
}
// 方法二:
new Blob(['𠮷']).size;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment