1. bind方法
bind() 函数会创建一个新函数(称为绑定函数)
- bind是ES5新增的一个方法
- 传参和call类似
- 不会执行对应的函数,call或apply会自动执行对应的函数
- 返回对函数的引用
- 语法
fun.bind(thisArg[, arg1[, arg2[, ...]]])
<script>
var obj = {
name: "阿马"
}
function add(a, b) {
console.log(this);
console.log(a + b)
}
var new1 = add.bind(obj, 1, 2)
new1();
//返回的不是同一个函数
console.log(new1 === add);
</script>
2. querySelector和getxxxByxxx的区别
getXXXByXXX 获取的是动态集合,querySelector获取的是静态集合。
简单的说就是,动态就是选出的元素会随文档改变,静态的不会,取出来之后就和文档的改变无关了。
3. 函数的递归
前提:
arguments.callee
打印出来的就是函数本身,它可以在函数递归调用的时候,派上用场
arguments.callee 打印出来的就是函数本身,它可以在函数递归调用的时候,派上用场
function fn(){
console.log(arguments.length);
console.log(arguments.callee);
}
fn();
能用递归的地方都可以不用。
函数的递归调用,就是函数在内部自己调自己
函数的递归调用是一把双刃剑,如果设计的好,可以帮我们简单的处理事情,如果设计不好就是灾难
- 函数的递归要想设计好必须有两个条件
- 必须有一个明显的结束条件,不能一直递归下去
- 每一次调用都要有一个趋近结束条件的趋势
// 递归实现阶乘
function f(n){
if(n == 1){
return 1
}
return n * f(n-1);
}
var a = f(5);
console.log(a); // 120
4. 终极原型链
任何的函数对象的prototype都和这个函数对象实例化的对象proto都指向同一个对象
5. 闭包
为什么要学习闭包?
先必须理解Javascript特殊的变量作用域。
变量的作用域无非就是两种:全局变量和局部变量。
- 全局变量 可以在局部作用域内访问
- 局部变量 不可以在全局作用域内访问的
- 函数内部声明变量的时候,一定要使用var命令。如果不用的话,实际上声明了一个全局变量
- 闭包的产生条件/使用步骤
- 在外部函数f1内 嵌套一个内部函数f2
- 内部函数f2 引用外部函数f1的局部变量a
- 外部函数f1 返回内部函数f2的函数体
- 内部函数f2和外部函数f1都要执行
function f1(){
var a = 1;
function f2(){
return a;
}
return f2;
}
// 返回的是就是f2的函数体
var result = f1();
var aaaa = result();
console.log(aaaa);
-
闭包到底是什么?
- 理解一: 闭包是嵌套的内部函数(绝大部分人)
- 理解二: 闭包是包含外部函数的局部变量的对象(极少数人)
- 理解三: 所谓的闭包是一个引用关系,该引用关系存在于内部函数中,引用的是外部函数的局部变量的对象(深入理解)
-
常见的闭包
- 将函数作为另一个函数的返回值
- 将内部函数作为外部函数的返回值
-
闭包的作用 ( 企业开发中我们不允许使用全局变量 )
- 延长外部函数变量的生命周期
- 让函数外部可以操作(读写)到函数内部的数据(变量/函数)/函数外部可以引用函数内部的变量
- 注意: 浏览器为了性能,后期将外部函数中不被内部函数使用的变量清除了
function buyLip(){
var money = 500;
function f2(){
money -= 100;
console.log(money);
}
return f2;
}
var result = buyLip();
result(); // 400
result(); // 300
- 闭包使用中的坑点 ( ()()会重置初始化原始外部变量的值 )
function buyLip(){
var money = 500;
function f2(){
money -= 100;
console.log(money);
}
return f2;
}
buyLip()(); // 500
buyLip()(); // 500
-
闭包的缺点和解决(内存泄漏和内存溢出)
- 内存泄漏 : 内存无法释放;
- 内存溢出 : 内存被撑爆;
- f = null; 解决方式;
function fn(){
var a = 0;
function fn1(){
a++;
console.log(a);
}
return fn1;
}
var f = fn();
f();
f();
f = null;//释放闭包
6. 面向对象
面向对象三大特性:封装、继承、多态
-
原型继承-方法继承
- 让父类的实例作为子类的原型,将子类的原型构造器补充完整 (为了让子类继承方法)
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<title>面向对象-原型继承-方法继承</title>
</head>
<body>
<script>
function Dog(){
}
Dog.prototype.eat = function(){
console.log('翔');
}
function Teddy(){
}
Teddy.prototype = new Dog();
Teddy.prototype.constructor = Teddy;
function ChaiQuan(){
}
ChaiQuan.prototype = new Dog();
ChaiQuan.prototype.constructor = ChaiQuan;
var t = new Teddy();
t.eat();
var c = new ChaiQuan();
c.eat();
</script>
</body>
</html>
-
构造器(函数)继承-属性继承
- 在子类当中去调用父类的构造函数(为了让子类继承属性)
-
组合继承
- 原型继承方法,借用构造函数继承属性一起使用
- 方法重写和方法重载(多态的表现形式)
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<script type="text/javascript">
//父类
function Dog(name,age){
this.name = name;
this.age = age;
}
//子类
function Teddy(name,age){
// this.name = name;
// this.age = age;
//借助父类的构造函数实现属性的继承
Dog.call(this,name,age);
}
Dog.prototype.run = function(){
console.log('跑的很快~');
}
//为了让子类去继承父类原型当中的方法
//我们需要用到原型继承,原型继承主要就是为了让子类继承方法使用的
//让子类的原型变成父类的一个实例
//手动给原型对象添加一个构造器,因为原型对象里面都是有构造器的,指向和自己匹配的构造函数
Teddy.prototype = new Dog();
Teddy.prototype.constructor = Teddy;
//方法重写和方法重载 是多态的两个表现形式
//方法重写;和父类同名方法功能不同,被称作方法重写
Teddy.prototype.run = function(flag){
//方法重载
if(typeof flag === 'number'){
console.log('跑的很慢~');
}else{
console.log('跑的很快~');
}
}
var d1 = new Dog('旺财',3);
d1.run();
var t1 = new Teddy('小黑',2);
t1.run(10);
console.log(t1);
</script>
</body>
</html>
7. web Workers
H5规范提供了js分线程的实现, 取名为: Web Workers
-
相关API
Worker: 构造函数, 加载分线程执行的js文件
Worker.prototype.onmessage: 用于接收另一个线程的回调函数
Worker.prototype.postMessage: 向另一个线程发送消息
每个线程可以向不同线程发送消息 也可以接收不同线程传来的消息
-
主线程操作
发送消息: worker.postMessage(消息可以是任何数据)
-
接受消息: worker.onmessage = function(e){
console.log(e.data)//接收到的消息或者数据在事件对象的data属性当中 }
-
子线程操作
发送消息: worker.postMessage(消息可以是任何数据)
-
接受消息: worker.onmessage = function(e){
console.log(e.data)//接收到的消息或者数据在事件对象的data属性当中 }
-
不足
- worker内代码不能操作DOM
- 不能跨域加载JS
- 不是每个浏览器都支持这个新特性
-
计算得到fibonacci数列中第n个数的值
- 在主线程计算: 当位数较大时, 会阻塞主线程, 导致界面卡死
function fib(n){
if(n <= 2){
return 1;
}
return fib(n- 1) + fib(n - 2);
}
- js代码-myThread.js :
function fib(n){
if(n <= 2){
return 1;
}
return fib(n- 1) + fib(n - 2);
}
self.onmessage = function(e){
e = e || window.event;
// console.log(e.data);//就 可以拿到主线程给我 发过来的消息内容
var result = fib(e.data);
self.postMessage(result);//分线程接受到主线程的消息,然后开始计算,把计算后的记过发消息再给主线程
}
- html代码 :
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<script type="text/javascript">
//第一步:实例化一个对象,初始化主线程和分线程关联对象
var worker = new Worker('./myThread.js');
worker.postMessage(100);//主线程发送消息给分线程,消息内容可以是任意类型
worker.onmessage = function(e){
e = e || window.event;
//等待接受分线程计算完的结果
console.log(e.data);
}
console.log('大哥 js Ending~');
</script>
</body>
</html>
面试题
// 当发生连等的时候 那么属性的优先级更高
var a = { n: 1 };
var b = a;
a.x = {n:2}
a = {n:2}
a.x = a = { n: 2 };
console.log(a.x); // 报错
console.log(b.x); // {n:2}
var b1 = {
b2:[2,'atguigu',console.log],
b3:function () {
alert('hello')
}
}
console.log(b1, b1.b2, b1.b3); // {b2: Array(3), b3: ƒ} b2: (3) [2, 'atguigu', ƒ] b3: ƒ ({alert('hello')})
console.log(b1 instanceof Object, typeof b1); // true 'object'
console.log(b1.b2 instanceof Array, typeof b1.b2); // true 'object'
console.log(b1.b3 instanceof Function, typeof b1.b3); // true 'function'
console.log(typeof b1.b2[2]); // 'function'
console.log(typeof b1.b2[2]('atguigu')); // 'atguigu' undefined
b1.b2[2]('atguigu'); // 'atguigu'
var a = {};
var obj1 = {
m: 2,
};
var obj2 = {
n: 2,
};
var obj3 = function () {};
a[obj1] = 4;
a[obj2] = 5;
a.name = 'kobe';
a[obj3] = 6;
console.log(a[obj1]); // 5
console.log(a); // {[object Object]: 5, name: 'kobe', function () {}: 6}
var name = 'The Window';
var object = {
name: 'My Object',
getNameFunc: function () {
return function () {
return this.name;
};
},
};
console.log(object.getNameFunc()); // f () { return this.name }
console.log(object.getNameFunc()()); // The Window
var name2 = 'The Window';
var object2 = {
name2: 'My Object',
getNameFunc: function () {
var that = this;
return function () {
return that.name2;
};
},
};
console.log(object2.getNameFunc()); // f () {return that.name2;}
console.log(object2.getNameFunc()()); // My Object