mrweilian / note-javascript Goto Github PK
View Code? Open in Web Editor NEWjavaScript前端冲刺笔记
javaScript前端冲刺笔记
实现一个hash路由
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<ul>
<li>
<a href="#/">router yellow</a>
</li>
<li>
<a href="#/blue">router blue</a>
</li>
<li>
<a href="#/pink">router pink</a>
</li>
</ul>
<script type="text/javascript">
console.log(location.hash)
class Routers{
constructor() {
this.routes = {};
this.currentUrl = '';
this.refresh = this.refresh.bind(this);
window.addEventListener('load',this.refresh,false);
window.addEventListener('hashchange',this.refresh,false);
}
route(path,callback) {
this.routes[path] = callback || function() {};
}
refresh() {
// debugger
this.currentUrl = location.hash.slice(1) || '/';
this.routes[this.currentUrl]();
}
}
window.Router = new Routers();
var content = document.querySelector('body');
// change Page anything
function changeBgColor(color) {
content.style.backgroundColor = color;
}
Router.route('/', function() {
changeBgColor('yellow');
});
Router.route('/blue', function() {
changeBgColor('lightblue');
});
Router.route('/pink', function() {
changeBgColor('pink');
});
</script>
</body>
</html>
constructor中定义了一个routes对象,用来存放一个hash值对应的function。
route方法中,实例调用的时候传入hash值和期望执行的对应函数,添加到上述的routes对象中。
refresh方法:获取当前的hash值调用对应的routes的function
自己实现的一个列表
class List {
constructor(listCount, posIndex, dataStore) {
this.listCount = listCount || 0; //初始化元素个数为0
this.posIndex = 0; //初始化位置为0
this.dataStore = dataStore || []; //初始化空数组来保存列表元素
}
append(ele) {
//插入功能
this.dataStore[this.listCount++] = ele;
}
find(ele) {
//查询
for (let i = 0; i < this.dataStore.length; i++) {
if (ele === this.dataStore[i]) return i
}
return -1
}
remove(ele) {
//删除功能
let foundAt = this.find(ele)
if (foundAt > -1) {
this.dataStore.splice(foundAt, 1);
this.listCount --;
return true
}
return false
}
length() {
return this.listCount
}
toString() {
return this.dataStore
}
insert(ele, before) {
//在某个元素前插入
let foundAt = this.find(before);
if (foundAt > -1) {
this.dataStore.splice(foundAt+1, 0 ,ele)
return true
}
return false
}
clear() {
//清空列表
delete this.dataStore
this.dataStore = []
this.listCount = this.posIndex = 0
}
}
let arr = [1,2,3,4,5,6,7,8,9]
let list = new List(arr.length, 0, arr)
list.append(10)
console.log(list.toString())
console.log(list)
console.log(list.find(8))
list.remove(8)
console.log(list)
console.log(list.toString())
list.insert(13, 1)
console.log(list.toString())
list.clear()
console.log(list.toString())
console.log(list)
js实现简单二叉树
class Node {
constructor(data, left, right) {
this.data = data;
this.left = left;
this.right = right;
}
show() {
console.log(this.data);
}
}
class BST {
constructor() {
this.root = null;
}
insert(data) {
let n = new Node(data, null, null);
if (!this.root) {
this.root = n;
} else {
let currentNode = this.root;
let parentNode;
while (true) {
parentNode = currentNode;
if (data < currentNode.data) {
currentNode = currentNode.left;
if (currentNode == null) {
parentNode.left = n;
break;
}
} else {
currentNode = currentNode.right;
if (currentNode == null) {
parentNode.right = n;
break;
}
}
}
}
}
inOrder(node) {// 中序排序
if (node != null) {
this.inOrder(node.left);
node.show();
this.inOrder(node.right);
}
}
preOrder(node) {// 先序
if( !(node == null )){
node.show();
this.preOrder( node.left );
this.preOrder( node.right );
}
}
postOrder(node) {// 后序
if( !(node == null ) ){
this.postOrder( node.left );
this.postOrder( node.right );
console.log( node.show() + ' ');
}
}
getMin() {// 最小值
var current = this.root;
while ( !( current.left == null ) ){
current = current.left;
}
return current.show();
}
getMax() {// 最大值
var current = this.root;
while ( !( current.right == null ) ) {
current = current.right;
}
return current.show();
}
find(data) {// 查找给定值
var current = this.root;
while ( current != null ){
if( current.data == data ){
return current;
}else if( data < current.data ){
current = current.left;
}else{
current = current.right;
}
}
return null;
}
}
var nums = new BST();
//插入数据
nums.insert(23);
nums.insert(45);
nums.insert(16);
nums.insert(37);
nums.insert(3);
nums.insert(99);
nums.insert(22);
console.log(nums.root)
nums.inOrder(nums.root)
console.log(nums.find(99))
笔记笔记笔记
Node是创建一个二叉树的节点
二叉树插入节点insert中的currentNode = currentNode.left要注意啊
inOrder中序,注意递归的方式,分析递归的执行方式。这里扯到执行栈,最后被调用的最先执行!
原型链继承
function Person () {
this.type = 'person';
}
//父类
Person.prototype.sayType = function () {
console.log(this.type);
}
//父类的方法
function Jack () {
this.name = 'jack'
}
//子类
Jack.prototype = new Person();
//子类的prototype指向父类的地址
var jack = new Jack();
//jack实例层层向上访问就能拿到父类的方法
jack.sayType();
原型链继承的方法缺点1:实例jack无法向父类Person传递参数
原型链继承的方法缺点2:如果父类Person中存在值为引用类型的属性,会导致所有子类实例
共享同个引用类型。如:
function Person () {
this.type = {name:'personName',age: 'Number'};
}
function Jack () {
this.name = 'jack'
}
Jack.prototype = new Person();
var jack = new Jack();
var ben = new Jack();
jack.type.school = 'bj';
console.log(ben.type); //{name: "personName", age: "Number", school: "bj"}
这里可以发现,jack对type添加的属性,再ben里也可以取到
构造函数继承
子类的构造函数
中调用父类构造函数
function Father (name) {
this.name = name;
this.cash = [100,200,300];
}
Father.prototype.earnMoney = function () {
console.log(1000);
}
function Child (name) {
Father.call(this, name)
}
var childA = new Child('baby');
var childB = new Child('home');
var fa = new Father();
fa.earnMoney();
//调用father方法成功输出 1000
childA.cash.push(500);
console.log(childA,childB);
//A的cash = [100, 200, 300, 500]
//B的cash = [100, 200, 300]
childA.earnMoney();
// error:childA.earnMoney is not a function
这样虽然解决了原型链中引用类型的问题,但是可以发现。子类不能继承父类prototype原型对象中的属性和方法。
组合继承
原型链
继承和构造函数
继承。function Father (name) {
this.name = name;
this.cash = [100,200,300];
}
Father.prototype.earnMoney = function () {
console.log(1000);
}
function Child (name) {
Father.call(this, name)
}
// 调用构造函数继承,继承Father中的属性和方法
Child.prototype = new Father();
//原型链继承。子类的prototype能访问到父类的prototype
Child.prototype.constructor = Child;
//对象的constructor属性指向prototype所在的函数,由于Child.prototype = new Father();,导致Child.prototype.constructor被覆盖,这里修正指向
这样的继承方式会导致父类再一次实例中被调用两次。
原型式继承
-参考廖狗比的代码吧
function object(o) {
// 创建一个临时的构造函数
function F() {}
// 将传入的对象 o 作为该构造函数的原型
F.prototype = o;
// 返回一个 F 构造函数的示例
return new F();
}
var pens = {
type: 'pen',
colors: ['red', 'blue']
};
// pen1 和 pen2 是 F 构造函数的示例
// 可以通过内部属性 [[prototye]] 访问到 F.prototype ,既参数对象 pens
// 从本质上来说,object 对传入的对象执行了一次浅复制
var pen1 = object(pens);
var pen2 = object(pens);
console.log(pen1.type); // pen
pen1.colors.push('black');
console.log(pen2.colors); // red,blue,black
模块化
模块化的好处:1.避免命名冲突(减少命名空间污染);2.更好的分离, 按需加载;3.更高复用性;4.高可维护性
namespace
了。能减少全局变量,解决命名冲突
也存在问题,外部可以随意读取/修改内部数据
let weilianModule = {
name: 'weilian',
age: 23,
getName() {
console.log(`${this.name}`)
},
getAge() {
console.log(`${this.age}`)
}
}
weilianModule.getName(); //weilian
weilianModule.name = 'handsome!'; //修改模块内部的数据
weilianModule.getName(); //handsome!
(function(window) {
let name = 'weilian';
function getName() {
console.log(name)
}
function setName(newName) {
name = newName;
otherFun() //内部调用
}
function otherFun() {
//内部私有的函数
console.log('otherFun()')
}
//暴露行为
window.weilianModule = { getName, setName }
})(window)
weilianModule.getName() //weilian
weilianModule.name // undefined
weilianModule.setName('haha')
weilianModule.getName() //haha
// module.js文件
(function(window, $) {
let data = 'www.baidu.com'
//操作数据的函数
function foo() {
//用于暴露有函数
console.log(`foo() ${data}`)
$('body').css('background', 'red')
}
function bar() {
//用于暴露有函数
console.log(`bar() ${data}`)
otherFun() //内部调用
}
function otherFun() {
//内部私有的函数
console.log('otherFun()')
}
//暴露行为
window.myModule = { foo, bar }
})(window, jQuery)
当下流行的commonjs, AMD, ES6, CMD;
我只接触过commonjs和ES6的。这里主要记录一下ES6的吧。也主要是在vuejs中用得比较多
1.export命令用于规定模块的对外接口,import命令用于输入其他模块提供的功能。
/** 定义模块 math.js **/
var basicNum = 0;
var add = function (a, b) {
return a + b;
};
export { basicNum, add };
/** 引用模块 **/
import { basicNum, add } from './math';
function test(ele) {
ele.textContent = add(99 + basicNum);
}
上例所示,使用import命令的时候,用户需要知道所要加载的变量名或函数名,否则无法加载。为了给用户提供方便,让他们不用阅读文档就能加载模块,就要用到export default命令,为模块指定默认输出。
// export-default.js
export default function () {
console.log('foo');
}
// import-default.js
import customName from './export-default';
customName(); // 'foo'
冒泡排序
#####概念:依次比较两个相邻的元素,后者比前者大即互换位置,否则进行下个相邻元素的比较。最后一轮下来,最大值已经在末端;此时再开始下一轮。
//实现冒泡排序需要两个for循环
//arr.length - 1足够实现全倒序的排列。emmm这个想多一会就理解了
for (let i=0; i < arr.length - 1; i++) {
//第一层循环每次都能获取一个最大值,所以下面可以每次少循环一轮
for (let j=0; j < arr.length- i - 1;j++) {
if( arr[j] > arr[j+1] ) {
//es6交换复制
[arr[j], arr[j + 1]] = [arr[j + 1], arr[j]];
}
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
*{margin: 0;padding: 0;}
.bubble-wrapper{
position: relative;
width: 800px;
height: 500px;
background: #edecec;
margin: 100px auto;
display: flex;
align-items: flex-end;
}
.bubble-item{
width: 80px;
height: 200px;
background: #f56f65;
box-sizing: border-box;
border: 1px solid #000;
text-align: center;
position: absolute;
left: 0;
transition: all .5s linear;
}
</style>
</head>
<body>
<section class="bubble-wrapper">
<div class="bubble-item"></div>
<div class="bubble-item"></div>
<div class="bubble-item"></div>
<div class="bubble-item"></div>
<div class="bubble-item"></div>
<div class="bubble-item"></div>
<div class="bubble-item"></div>
<div class="bubble-item"></div>
<div class="bubble-item"></div>
<div class="bubble-item"></div>
</section>
<script src="./jquery-1.9.1.min.js"></script>
<script>
const bubbleArr = [105,200,306,400,160,80,99,506,360,330];
const WIDTH = 80;
let time = 0;
bubbleArr.forEach((item,index) => {
document.querySelectorAll('div')[index].style.height = item + 'px';
document.querySelectorAll('div')[index].style.transform = `translate3d(${index * WIDTH}px,0,0)`;
document.querySelectorAll('div')[index].innerText = item;
document.querySelectorAll('div')[index].setAttribute('data-index',index);
})
function bubble(arr) {
for (let i = 0; i < arr.length-1; i++) {
//每次循环都比上次循环少一轮
for (let j = 0; j < arr.length - i - 1; j++) {
if (arr[j] > arr[j + 1]) {
let k = j + 1;
$('div[data-index='+ j +']')[0].style.transform = `translate3d(${(j+1)*WIDTH}px,0,0)`;
$('div[data-index='+ k +']')[0].style.transform = `translate3d(${(j)*WIDTH}px,0,0)`;
$('div[data-index='+ j +']')[0].setAttribute('data-index', 'wait');
$('div[data-index='+ k +']')[0].setAttribute('data-index', j);
$('div[data-index=wait]')[0].setAttribute('data-index', k);
time += 1000;
// 值互换
[arr[j], arr[j + 1]] = [arr[j + 1], arr[j]];
debugger
}
}
}
}
setTimeout(()=>{
bubble(bubbleArr);
console.log(bubbleArr)
},1000)
</script>
</body>
</html>
感觉看了动画效果更容易理解冒泡排序了
Object.create()
Object.create(proto, [propertiesObject])
//proto指新创建对象的原型对象
//propertiesObject指要添加到新创建对象的可枚举属性
// Shape - 父类(superclass)
function Shape() {
this.x = 0;
this.y = 0;
}
// 父类的方法
Shape.prototype.move = function(x, y) {
this.x += x;
this.y += y;
console.info('Shape moved.');
};
// Rectangle - 子类(subclass)
function Rectangle() {
Shape.call(this); // call super constructor.
}
// 子类续承父类
Rectangle.prototype = Object.create(Shape.prototype);
Rectangle.prototype.constructor = Rectangle;
var rect = new Rectangle();
console.log('Is rect an instance of Rectangle?',
rect instanceof Rectangle); // true
console.log('Is rect an instance of Shape?',
rect instanceof Shape); // true
rect.move(1, 1); // Outputs, 'Shape moved.'
例子二
var o;
// 创建一个原型为null的空对象
o = Object.create(null);
o = {};
// 以字面量方式创建的空对象就相当于:
o = Object.create(Object.prototype);
o = Object.create(Object.prototype, {
// foo会成为所创建对象的数据属性
foo: {
writable:true,
configurable:true,
value: "hello"
},
// bar会成为所创建对象的访问器属性
bar: {
configurable: false,
get: function() { return 10 },
set: function(value) {
console.log("Setting `o.bar` to", value);
}
}
});
function Constructor(){}
o = new Constructor();
// 上面的一句就相当于:
o = Object.create(Constructor.prototype);
// 当然,如果在Constructor函数中有一些初始化代码,Object.create不能执行那些代码
// 创建一个以另一个空对象为原型,且拥有一个属性p的对象
o = Object.create({}, { p: { value: 42 } })
// 省略了的属性特性默认为false,所以属性p是不可写,不可枚举,不可配置的:
o.p = 24
o.p
//42
o.q = 12
for (var prop in o) {
console.log(prop)
}
//"q"
delete o.p
//false
//创建一个可写的,可枚举的,可配置的属性p
o2 = Object.create({}, {
p: {
value: 42,
writable: true,
enumerable: true,
configurable: true
}
});
Object.assjgn()
const object1 = {
a: 1,
b: 2,
c: 3
};
const object2 = Object.assign({c: 4, d: 5}, object1);
console.log(object2.c, object2.d);
// console.log: 3 5
// 继承一个类
MyClass.prototype = Object.create(SuperClass.prototype);
// 混合其它
Object.assign(MyClass.prototype, OtherSuperClass.prototype);
// 重新指定constructor
MyClass.prototype.constructor = MyClass;
MyClass.prototype.myMethod = function() {
// do a thing
};
var obj = { a: 1 };
var copy = Object.assign({}, obj);
console.log(copy); // { a: 1 }
copy.a = 3
copy.a // 3
obj.a //1
简述执行顺序
关于宏任务和微任务
事件循环
分清js执行顺序
console.log('1');
setTimeout(function() {
console.log('2');
process.nextTick(function() {
console.log('3');
})
new Promise(function(resolve) {
console.log('4');
resolve();
}).then(function() {
console.log('5')
})
})
process.nextTick(function() {
console.log('6');
})
new Promise(function(resolve) {
console.log('7');
resolve();
}).then(function() {
console.log('8')
})
setTimeout(function() {
console.log('9');
process.nextTick(function() {
console.log('10');
})
new Promise(function(resolve) {
console.log('11');
resolve();
}).then(function() {
console.log('12')
})
})
基于数组实现一个栈功能
class Stack{
constructor(dataStore) {
this.dataStore = dataStore || [];
this.top = this.dataStore.length || 0;
}
push(ele) {
this.dataStore[this.top++] = ele;
}
pop() {
let popItem = this.dataStore[--this.top];
this.dataStore.splice(this.top, 1);
return popItem;
}
peek() {
if (this.top > 0) return this.dataStore[this.top-1];
else return 'empty'
}
length() {
return this.dataStore.length
}
clear() {
delete this.dataStore;
this.dataStore = [];
this.top = 0
}
}
// 二进制转换 (入栈出栈)
function mulBase ( num , base ) {
var s = new Stack();
do{
s.push( num % base );
num = Math.floor( num /= base );
}while ( num > 0 );
var converted = '';
while (s.length() > 0){
converted += s.pop();
}
return converted;
}
console.log( mulBase( 125 , 2 ) ); // 1111101
console.log( mulBase( 125 , 8 ) );
// 判断回文
function isPalindrome (str) {
let s = new Stack(),
len = str.length,
strArr = str.split('');
console.log(strArr)
for (let i = 0; i < len; i++) {
s.push(strArr[i])
}
console.log(s)
let reStr = ''
while (len--) {
console.log(s.top)
reStr+= s.pop()
}
if (reStr === str) return true
else return false
}
console.log(isPalindrome('level'))
console.log(isPalindrome('100001'))
console.log(isPalindrome('abc'))
实现栈功能的核心就是先进后出,关键在于对例子中this.top的指向正确。出栈的时候是从当前索引最大的地方出栈。忘记了就回来看看代码吧哈哈哈
定时器简单介绍
写到定时器,就不得不提起event loop
,js的单线程特质。常用的定时器setTimeout
和setInterval
,可以实现异步执行。
Event Queue
中。(setInterval是循环执行)定时器引发的问题——定时不准
出现原因:js的单线程及event loop先关。主线程的耗时任务超过定时时长,定时器任务只能继续排队等待主线程执行栈清空。
解决定时不准方案
1.通过计算任务时间来减少定时误差
2.采用requestAnimationFrame(基于浏览器刷新时间(16.6ms)执行一次)自行封装定时器
自我封装一个setInterval,代码如下
function myInterval(callback, interval) {
let timer,
start = Date.now(),
end;
// 每16.6ms执行一次
const loop = () => {
timer = window.requestAnimationFrame(loop);
end = Date.now();
if (end - start >= interval) {
start = end = Date.now();
callback(timer);
}
}
window.requestAnimationFrame(loop);
return timer;
}
let a = 0;
myInterval((timer) => {
console.log(a)
a++;
if(a == 3) {
cancelAnimationFrame(timer);
}
}, 2000);
this的指向
例1
var name = "windowsName";
function a() {
var name = "Cherry";
console.log(this.name); // windowsName
console.log("inner:" + this); // inner: Window
}
a();
console.log("outer:" + this) // outer: Window
自己总结一个: a() = window.a()
,实际上是window调用的a,this指向window。
例2
var a = {
name: "aName",
fn : function () {
console.log(this.name); // aName
}
}
a.fn();
这里a调用的fn,this指向a。
例3
var name = "windowsName";
var a = {
fn : function () {
console.log(this.name); // undefined
}
}
window.a.fn();
这里a调用的fn,this指向a,a中没有name。
例4
var name = "windows";
var a = {
name: "functionA",
fn : function () {
console.log(this.name); // windows
}
}
var f = a.fn;
f();
这里a.fn复制给了f。最后调用的f() = window.f();this指向window
改变this的指向
关于箭头函数
作用域简介
感觉作用域还是比较关键的,需要好好掌握,应该也是面试的热点吧。
基本的作用域:全局、函数、eval内的代码块
列举几个自己学习作用域的例子吧
for( var i = 0; i < 5; i++ ) {
setTimeout(function(){
console.log(i)
},0)
}
//5
for( var j = 0; j < 5; j++ ) {
(function(j){
setTimeout(function(){
console.log(j)
},0)
})(j)
}
// 0 1 2 3 4 闭包
for( let k = 0; k < 5; k++ ) {
setTimeout(function(){
console.log(k)
},0)
}
//0 1 2 3 4 let块级作用域
自我总结一下吧:
第一个:setTimeout
异步执行,输出的是i,这里的i是全局作用域下的i。说说执行顺序,直接for循环完,此时i=5了;分别往事件队列放了5个setTimeout
的回调。然后setTimeout
再进行输出,此时的i=5,会输出5次5。
第二个:采取了闭包的方法。可以理解为setTimeout(B函数)访问自执行函数function(A函数)的变量,B函数可以访问A函数的变量,形成了函数作用域j。同理的还有一种方法就是setTimeout的第三个参数传for中的index值。
第三个:es6中let,形成块级作用域。只能在{}
内获取,在window下使用k会报错:k not defined。
记一个面试见过的题目,挺有意思
function print(){
var arrA = [1,2,3];
for(i = 0; i < arrA.length; i++) {
console.log(arrA[i]);
}
}
var arrB = [4,5,6];
for (var i = 0; i < arrB.length; i++) {
console.log(arrB[i]);
print();
}
print()中的i,是全局下的i。当全局中的for循环执行时,全局下的i = 0,当调用print的时候,i在print中的for执行完变成了3,此时全局下的i也变成了3。所以最后的输出结果:4 1 2 3
原型
__proto__
属性,这个属性指向了原型。例如let obj = {}
,浏览器上打印出来可以看到有一个__proto__
。原型也是一个对象
__proto__
里面包含很多函数,最熟悉的当然是toString()
,原型上有的方法我们可以直接调用。
constructor
属性
也就是:原型的 constructor 属性指向构造函数,构造函数又通过 prototype 属性指回原型
图形理解
理解对象的原型(可以通过Object.getPrototypeOf(obj)或者已被弃用的__proto__属性获得)与构造函数的prototype属性之间的区别是很重要的。前者是每个实例上都有的属性,后者是构造函数的属性。也就是说,Object.getPrototypeOf(new Foobar())和Foobar.prototype指向着同一个对象。
JavaScript 通过原型链继承的例子
var myString = 'This is my string.';
myString
立即具有了一些有用的方法,如 split()
、indexOf()
、replace()
等
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.