Giter Site home page Giter Site logo

note-javascript's People

Contributors

mrweilian avatar

Watchers

 avatar

note-javascript's Issues

javaScript 路由

实现一个hash路由

  • 可以说最核心的就是onhashchange。监听地址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>

这里描述一下关于Routers这个类的构建
  • constructor中定义了一个routes对象,用来存放一个hash值对应的function。

  • route方法中,实例调用的时候传入hash值和期望执行的对应函数,添加到上述的routes对象中。

  • refresh方法:获取当前的hash值调用对应的routes的function

javaScript 列表

自己实现的一个列表

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)

javaScript 二叉树

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中序,注意递归的方式,分析递归的执行方式。这里扯到执行栈,最后被调用的最先执行!

javaScript 继承

原型链继承

  • 一个对象借助原型继承令一个对象的属性和方法
    加个代码
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

javaScript 模块化

模块化

记录下我自己对模块化的使用和理解吧

模块化的好处:1.避免命名冲突(减少命名空间污染);2.更好的分离, 按需加载;3.更高复用性;4.高可维护性

  1. 记得最开始接触模块化相关的内容时,应该是命名空间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!

2.IIFE模式:匿名函数自调用(闭包)
  • 实现数据私有,外部只能调用暴露的接口
(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

  1. IIFE引入依赖(参照别人的例子)
// 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)

这样做除了保证模块的独立性,还使得模块之间的依赖关系变得明显。 但是这样引发的问题是,页面多个script标签引入,且不清楚他们之间的联系,需要依赖加载顺序等
> 模块化规范

当下流行的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'

javaScript 冒泡排序

冒泡排序

#####概念:依次比较两个相邻的元素,后者比前者大即互换位置,否则进行下个相邻元素的比较。最后一轮下来,最大值已经在末端;此时再开始下一轮。

//实现冒泡排序需要两个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>

感觉看了动画效果更容易理解冒泡排序了

javaScript Object

Object.create()

  • 创建一个新对象,使用现有的对象来提供新创建的对象的__proto__。
    语法
Object.create(proto, [propertiesObject])
//proto指新创建对象的原型对象
//propertiesObject指要添加到新创建对象的可枚举属性
  • 用Object.create实现类式继承
    参考MDN的例子
// 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
};
  • Object.assign()实现浅拷贝
var obj = { a: 1 };
var copy = Object.assign({}, obj);
console.log(copy); // { a: 1 }
copy.a = 3
copy.a // 3
obj.a //1

JavaScript 执行机制

emmmmmmmm 记得当时自己花了好长时间理解这类东西,记录一波

简述执行顺序

  • js是按照语句出现的顺序执行,但又涉及到同步执行和异步执行,需要注意其执行顺序。

关于宏任务和微任务

  • macro-task(宏任务):包括整体代码script,setTimeout,setInterval
  • micro-task(微任务):Promise,process.nextTick

事件循环

  • 事件循环的顺序,决定js代码的执行顺序。进入整体代码(宏任务)后,开始第一次循环。接着执行所有的微任务。然后再次从宏任务开始,找到其中一个任务队列执行完毕,再执行所有的微任务。

分清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')
    })
})

javaScript 栈

基于数组实现一个栈功能

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的指向正确。出栈的时候是从当前索引最大的地方出栈。忘记了就回来看看代码吧哈哈哈

javaScript之定时器

定时器简单介绍

写到定时器,就不得不提起event loop,js的单线程特质。常用的定时器setTimeoutsetInterval,可以实现异步执行。

  • 定时器原理:经过指定时间后,把要执行的任务加入到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);

javaScript关于this指向

this的指向

  • 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的指向

  • apply、call、bind / 箭头函数 / 变量存储 _this = this

关于箭头函数

  • (借用别人文章的话)箭头函数中没有 this 绑定,必须通过查找作用域链来决定其值,如果箭头函数被非箭头函数包含,则 this 绑定的是最近一层非箭头函数的 this,否则,this 为 undefined

javaScript之作用域

作用域简介

感觉作用域还是比较关键的,需要好好掌握,应该也是面试的热点吧。
基本的作用域:全局、函数、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

javaScript 原型

原型感觉也是我学javascript以来比较模糊的东西,来个小总结加深一下吧

原型

  • 每个js对象都有__proto__属性,这个属性指向了原型。例如let obj = {},浏览器上打印出来可以看到有一个__proto__

原型也是一个对象

  • 展开的__proto__里面包含很多函数,最熟悉的当然是toString(),原型上有的方法我们可以直接调用。

constructor属性

  • constructor是构造函数,构造函数内有和该obj__proto__一样的属性。参考截图
    image
    image

  • 也就是:原型的 constructor 属性指向构造函数,构造函数又通过 prototype 属性指回原型

图形理解

嗯,这个图脉络还是很清晰的
image

理解对象的原型(可以通过Object.getPrototypeOf(obj)或者已被弃用的__proto__属性获得)与构造函数的prototype属性之间的区别是很重要的。前者是每个实例上都有的属性,后者是构造函数的属性。也就是说,Object.getPrototypeOf(new Foobar())和Foobar.prototype指向着同一个对象。

JavaScript 通过原型链继承的例子

 var myString = 'This is my string.';

myString 立即具有了一些有用的方法,如 split()indexOf()replace()

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.