Javascript知识点记录(二)
Javascript入门易,精通难,基本上是共识的一个观点。在这个篇幅里,主要对一些难点进行记录。
鸭子类型
Javascript属于动态类型语言的一种。对变量类型的宽容,给了很大的灵活性。由于无需类型检测,则无需考虑他是否被设计拥有该方法。
鸭子类型通俗说法:如果它走起路来像鸭子,叫起来也是鸭子,那么他就是鸭子
鸭子类型指导我们只关注对象的行为,而不关注对象本身。关注HAS-A 而不是 IS-A。
如下例子,不管什么动物,只要他会duckSinging,并且是方法,就可以加入。
var duck = {
duckSinging: function () {
console.log("鸭子叫");
}
};
var chicken = {
duckSinging: function () {
console.log("鸭子叫");
}
};
var joinChoir = function(animal){
if(animal && animal.duckSinging instanceof Function)
{
//可以加入
}
}
多态
同一个操作用于不同的对象上,可以产生不同的解释和不同的结果。举例:动作都会叫,那么叫就是操作。猫叫和狗叫的结果不一样,这就是多态。
Sound是同一个操作,所以使用prototype来在原型链上进行定义。将Cat生成为方法,是为了给他的原型链添加方法。如Dog就不属于多态。
!(function () {
var makeSound = function (animal) {
animal.Sound();
};
var Cat = function(){};
Cat.prototype.Sound = function () {
console.log("喵");
};
var Dog = {}; //不属于多态
Dog.Sound = function () {
console.log("汪");
}
makeSound(Dog);
})()
一种动物能否发出叫声,取决于他有没有Sound方法,而不是取决于他是那种对象。不存在任何类型耦合,这就是鸭子类型的典型。
原型模式
原型模式是通过克隆来创建对象的。我们只需要调用克隆方法,就可以完成功能。使用Object.Create方法,来实现克隆。
!(function () {
var Plance = function () {
this.blood = 100
};
var plane = new Plance();
plane.blood = 200;
var clonePlane = Object.create(plane);
console.log(clonePlane.blood);
})()
可以重写拷贝方法,来进行自定义
Object.create = Object.create || function(obj){ //Object.create || 意思是如果没有此方法
var F = function () {};
F.prototype = obj;
return new F();
};
继承
原型编程的基本规则
1.所有的数据都是对象
2.要得到一个对象,需要找到一个对象作为原型进行克隆。
3.对象会记住他的原型
4.如果对象无法响应某个请求,则会把这个请求委托给它自己的原型
javascript中绝大多数数据都是对象,除了undefined之外,都可以通过包装类的方式编程对象类型数据。
javascript中根对象是Object.prototype对象,他是一个空的对象。任何对象都是通过这个克隆而来的。
var obj = function(){};
var obj1 = {};
console.log(Object.getPrototypeOf(obj) === Function.prototype);
console.log(Object.getPrototypeOf(obj1) === Object.prototype);
Javascript中没有类的概念,那么new Person()这种,实际上是调用他的函数构造器,来进行初始化。函数既可以作为普通函数,也可以作为构造器。
!(function () {
var obj = function(na){
this.name = na;
};
var obj1 = new obj();
var obj2 = new obj('a');
console.log(obj1.name); //undefined
console.log(obj2.name); //a
})()
请求可以在链条中往后传递,那么每个节点都必须知道它的下一个节点。Javascript给对象提供了一个名为_proto_的隐藏属性。
这个属性会默认指向它的构造器的原型对象。
var obj = function(na){};
console.log(obj.__proto__ === Function.prototype); //true
当对象无法响应某个请求的时候,他会顺着原型链把请求传递下去,直到有可以处理的请求对象为止。
以下是最常用的原型继承
首先obj2找,然后obj2对象构造器原型obj1原型,obj1原型找obj原型
!(function () {
var obj = function(){};
obj.prototype = {name:'sven'};
var obj1 = function () {};
obj1.prototype = new obj();
var obj2 = new obj1();
console.log(obj2.name); //sven
})()
对象构造器创建与对象克隆
对象构造器创建,只会创建该对象实体,不会创建该对象对应的原型。而克隆则是将原型也一并拷贝过去。
!(function () {
var obj1 = function(){
this.name = 'sven'
};
var obj2 = obj1;
var obj3 = Object.create(obj1);
var obj4 = new obj1();
console.log(typeof obj2.prototype); //object
console.log(typeof obj3.prototype); //object
console.log(typeof obj4.prototype); //undefined
})()
this
this总是指向一个对象,对象是在运行时基于函数执行环境动态绑定的。
this指向大致分为四种
1.作为对象调用时,this指向该对象。
var obj = {
a:1,
getA:function()
{console.log(this.a);}
};
obj.getA();
2.作为普通函数调用时,this指向windows对象。
window.a = 1;
var getA = function(){
return this.a;
};
console.log(getA());
3.作为构造器调用时,this指向他本身。
!(function () {
var myCla = function(){
this.name = 'sven';
};
var obj = new myCla();
console.log(obj.name); //sven
})()
但是,如果在方法中,进行闭包返回,那么结果就是最终返回的这个对象。
!(function () {
var myCla = function(){
this.name = 'sven';
return {
name : "an"
};
};
var obj = new myCla();
console.log(obj.name); //an
})()
4.作为call或apply调用时,可以动态的改变传入函数this.
!(function () {
var obj1 = {
name:'sven',
getName:function(){
return this.name;
}
};
var obj2 = { name : "an"};
console.log(obj1.getName()); //sven
console.log(obj1.getName.call(obj2)); //an
})()
需要注意一点,就是对象变换。当你把对象引用到一个变量后,就会变成普通函数调用方法。例如:var get = obj1.getName; get(); //undefind
使用Apply也可以做到借用其他对象的方法
!(function () {
var A = function (name) {
this.name = name;
};
var B = function(){
A.apply(this,arguments);
};
B.prototype.getName=function(){
return this.name;
};
var b = new B('save');
console.log(b.getName());
})()
闭包
闭包两大知识点就是变量的作用域以及变量的生命周期
变量的作用域
作用域是指变量的有效范围。
在函数中声明变量的时候,该变量前面没有var,则变为全局变量,任何地方都可以访问到。
使用var关键字在函数内声明,即是局部变量。只要函数内部才能访问。函数外面是访问不到的。
var a = 1;
var func = function(){
var b =2;
var func2 = function(){
var c = 3;
console.log(a);
console.log(b);
};
console.log(c); //is not defined
};
变量的生命周期
对于全局变量来说,声明周期是永久的,除非主动销毁这个全局变量。
对于函数内的局部变量来说,当退出函数时就会销毁。
使用闭包的话会一直存在在匿名函数的引用中,则不会销毁。因为,v返回了一个匿名函数的引用,可以访问到func()方法里面,局部变量a一直处在这个环境里。所以能被外界访问。
!(function () {
var func = function(){
var a =1;
return function(){
a++;
console.log(a);
};
};
var v = func();
var b = func();
var c = v;
v();
b();
c();
})()
绑定事件
因为javascript事件都是异步触发的,当事件被触发的时候,循环就结束了,所以i会保持循环最后的数值。可以添加立即执行函数,来进行执行。
var nodes = document.getElementsByTagName('div');
for (var i = 0; i < nodes.length; i++) {
(function (i) {
nodes[i].onclick = function () {
alert(i);
}
})(i)
}
闭包和面向对象
使用对象以方法的形式包含过程,闭包是在过程中以环境的形式包含数据。两个都可以达到一样的目的。
!(function () {
var extent = function(){
var value = 0;
return {
call:function(){
value++;
console.log(value);
}
};
};
var extent = extent();
extent.call();extent.call();extent.call();
//上为闭包写法,下为面向对象写法
var extent2 = {
value:0,
call:function(){
this.value++;
console.log(this.value);
}
};
extent2.call();extent2.call();extent2.call();
})()
高级函数
currying(函数柯里化)
currying又称部分求值,当你传入函数的时候,不会立刻求值。会等到真正需要求值的时候,一次性求值。
//封装计算框架,其中算法使用参数传递
var currying = function (fn) {
var args = [];
return function () {
if (arguments.length === 0) {
return fn.apply(this, args);
} else {
[].push.apply(args, arguments);
return arguments.callee;
}
};
};
//定义实际算法
var cost = (function () {
var money = 0;
return function () {
for (var i = 0; i < arguments.length; i++) {
money += arguments[i];
}
return money;
};
})();
var cost = currying(cost);
cost(100);cost(100);cost(100);
console.log(cost());
函数节流
某些场合下,函数被非常频繁的调用,会造成巨大的性能影响。比如说,瀑布流,窗口大小等。
使用函数节流,可以按照我们需要的时间忽略掉一些请求。使用setTimeout方法。
//函数节流方法,第一个参数,执行函数。第二个参数,延迟时间
var throttle = function (fn, interval) {
var _self = fn, timer, firstTime; //定义函数引用,定时器,是否首次调用
return function () {
var args = arguments, _me = this;
if (firstTime) { //第一次调用不延迟
_self.apply(_me, args); //修正方法,传递参数
return firstTime = false; //不进行延迟
}
if (timer) { //判断计时器是否存在
return false; //存在代表尚在延迟时间内,忽略
}
timer = setTimeout(function () { //延迟执行一次
clearTimeout(timer); //取消方法
timer = null;
_self.apply(_me, args);
}, interval || 500);
};
};
window.onresize = throttle(function(){
console.log(1);
},500);
分时函数
页面渲染DOM时候,为了避免一次性加载过多的节点,添加的分时函数操作。
!(function () {
//分时函数.参数1,创建节点数据。2.封装节点逻辑,3,每一批节点数量
var timeChunk = function (ary, fn, count) {
var obj, t;
var len = ary.length;
var start = function () {
for (var i = 0; i < Math.min(count || 1, ary.length); i++) {
var obj = ary.shift(); //删除一个数
fn(obj);
}
};
return function () {
t = setInterval(function () {
if (ary.length === 0) {
return clearInterval(t);
}
start();
}, 200);
};
};
//实际调用方法
var ary = [];
for (var i = 1; i <= 1000; i++) {
ary.push(i);
}
var renderFirendList = timeChunk(ary, function (n) {
var div = document.createElement('div');
div.innerHTML = n;
document.body.appendChild(div);
}, 2);
renderFirendList();
})()
Javascript知识点记录(二)的更多相关文章
- JavaScript学习记录二
title: JavaScript学习记录二 toc: true date: 2018-09-13 10:14:53 --<JavaScript高级程序设计(第2版)>学习笔记 要多查阅M ...
- Javascript知识点记录(三)设计模式
Javascript设计模式记录,这个方面确实是没写过,工作中也没有用到js设计模式的地方. prototype与面向对象取舍 使用prototype原型继承和使用面向对象,都可以实现闭包的效果.那么 ...
- javascript知识点记录(1)
javascript一些知识点记录 1.substring,slice,substr的用法 substring 和slice 都有startIndex 和 endIndex(不包括endInex),区 ...
- javascript知识点记录(2)
1.js 异步加载和同步加载 异步加载模式也叫非阻塞模式,浏览器在下载js的同时,同时还会执行后续的页面处理, 在script标签内,用创建一个script元素,并插入到document中,这样就是异 ...
- 高性能javascript(记录二)
js中有四种基本的数据存取位置.分别是:字面量.本地变量.数组元素.对象成员. 字面量:只代表自身,不存储在特定位置.js的字面量有:字符串.数字.布尔值.对象.数组.函数.正则表达式.以及特殊的nu ...
- 【千纸诗书】—— PHP/MySQL二手书网站后台开发之知识点记录
前言:使用PHP和MySQL开发后台管理系统的过程中,发现有一些通用的[套路小Tip],这里集中记录一下.结合工作中ing的后台业务,我逐渐体会到:除了技术知识外.能使用户体验好的“使用流程设计”积累 ...
- JavaScript算法与数据结构知识点记录
JavaScript算法与数据结构知识点记录 zhanweifu
- C#知识点记录
用于记录C#知识要点. 参考:CLR via C#.C#并发编程.MSDN.百度 记录方式:读每本书,先看一遍,然后第二遍的时候,写笔记. CLR:公共语言运行时(Common Language Ru ...
- JavaScript基本概念(二)
JavaScript 基本概念(二) 操作符和语句 目录 操作符 一元操作符 位操作符 布尔操作符 乘性操作符 其他操作符 语句部分 说起操作符,回忆下上一篇文章末尾说的话. 操作符 一元操作符 ++ ...
随机推荐
- 1、软件工程师要阅读的书籍 - IT软件人员书籍系列文章
软件工程师要阅读的书籍估计是项目组内最多的.软件工程师处于项目组中最基础的人员储备阶层,与项目的关系最密切.当然,现在是大数据时代,我们无法全部看完所有相关的书籍,只能够先学习工作需要的知识,然后在项 ...
- 使用 Async 和 Await 的异步编程(C# 和 Visual Basic)[msdn.microsoft.com]
看到Microsoft官方一篇关于异步编程的文章,感觉挺好,不敢独享,分享给大家. 原文地址:https://msdn.microsoft.com/zh-cn/library/hh191443.asp ...
- Linux内核的文件预读readahead
Linux的文件预读readahead,指Linux系统内核将指定文件的某区域预读进页缓存起来,便于接下来对该区域进行读取时,不会因缺页(page fault)而阻塞.因为从内存读取比从磁盘读取要快很 ...
- 【转】Hive内部表、外部表
hive内部表.外部表区别自不用说,可实际用的时候还是要小心. 1. 内部表: create table tt (name string , age string) location '/input/ ...
- win7升win10,初体验
跟宿舍哥们聊着聊着,聊到最近发布正式版的win10,听网上各种评论,吐槽,撒花的,想想,倒不如自己升级一下看看,反正不喜欢还可以还原.于是就开始了win10的初体验了,像之前装黑苹果双系统一样的兴奋, ...
- redis 源码阅读 内部数据结构--字符串
redis的内部数据结构主要有:字符串,双端链表,字典,跳跃表. 这里主要记录redise字符串的设计.相关的源码位于:src/sds.h 和 src/sds.c. 一 字符串 sds的结构体 s ...
- linux下使用denyhosts防止ssh暴力破解
1.DenyHosts介绍 DenyHosts是Python语言写的一个程序,它会分析sshd的日志文件(/var/log/secure),当发现重 复的攻击时就会记录IP到/etc/hosts.de ...
- [转]推荐highcharts学习网址
highcharts学习网址1:http://www.hcharts.cn/docs/index.php?doc=basic(百度highcharts中文教程即可) highcharts学习网址2:h ...
- [百度经验]window下连接mysql 错误代码 1045
连接mysql时出现错误代码 1045 Access denied for user 'root'@'localhost' (using password:YES) 百度经验:jingyan.baid ...
- 利用epoll写一个"迷你"的网络事件库
epoll是linux下高性能的IO复用技术,是Linux下多路复用IO接口select/poll的增强版本,它能显著提高程序在大量并发连接中只有少量活跃的情况下的系统CPU利用率.另一点原因就是获取 ...