原文地址:http://www.cnblogs.com/zhaopei/p/6623460.html
阅读目录
在写面向对象编程思想-设计模式中的js部分的时候发现很多基础知识不了解的话,是很难真正理解和读懂js面向对象的代码。为此,在这里先快速补上。然后继续我们的面向对象编程思想-设计模式。
什么是鸭子类型
javascript是一门典型的动态类型语言,也就弱类型语言。
那什么是鸭子类型:【如果它走起路来像鸭子,叫起来也是鸭子,那么它就是鸭子】
var 鸭子 = {
走路: function () { },
咕咕咕: function () { }
}
var 鹦鹉 = {
走路: function () { },
咕咕咕: function () { }
}
这只鹦鹉同样有“走路”和“咕咕咕”的方法,那在js的世界里就可以把它当成鸭子。
可以这样调用:
var 鸭子们 = [];
鸭子们.push(鸭子);
鸭子们.push(鹦鹉);
for (var i = 0; i < 鸭子们.length; i++) {
鸭子们[i].走路();
}
所以js的世界没有抽象和接口,但可以约定“我们都是鸭子”。
javascript的面向对象
javascript不仅是直译式脚本语言、动态类型、弱类型语言、函数为一等公民的语言,它还是基于原型的面向对象语言。面向对象三大特性:封装、继承、多态,下面我们用js分别实现。
封装
var Person = (function () {
var sex = "纯爷们";
return {
name: "农码一生",
getInfo: function () {
console.log("name:" + this.name + ",sex:" + sex);
}
};
})();
虽然老的js语法没有提供private等关键字,但是我们可以利用闭包来实现私有字段,达到封装的目的。
继承
-
字面量表示:
var Person = {
name: "农码一生",
getName: function () {
console.log(this.name);
}
};
var obj = Person;
obj.getName(); 函数构造器:
var Person = function () {
this.name = "农码一生";
}
Person.prototype.getName = function () {
console.log(this.name);
}
var obj = function () { };
obj.prototype = new Person();//obj继承于Person
var o = new obj();
o.getName();//直接调用原型中的getName(类似于C#中的调用父类方法)
多态
对于多态,其实上面的鸭子类型已经表现的很清楚了。
var 鸭子们 = [];
鸭子们.push(鸭子);
鸭子们.push(鹦鹉);
for (var i = 0; i < 鸭子们.length; i++) {
鸭子们[i].走路();//对于鹦鹉来说,它可能是跳着走。对于鸭子来说,它可能左右摇摆着走。这就是多态的表现。
}
对于鹦鹉来说,它可能是跳着走。对于鸭子来说,它可能左右摇摆着走。这就是多态的表现。
原型
什么是原型?在js中是没有类的,那它怎么创建对象。在C#中我们可以通过new关键字实例化一个对象,在js中我们用new关键字构造一个原型对象。C#中一切对象继承于Object,js中一切对象的原型是Object。
var Person = function () {
this.name = "农码一生";
this.sex = "纯爷们";
};
console.log(Person.prototype);
我们很多时候给一个对象添加方法的时候就是写在原型上,这是为什么?直接写在对象里会有问题吗?下面我们试试:
var Person = function () {
this.name = "农码一生";
this.sex = "纯爷们";
this.getInfo = function () {
console.log("name:" + this.name + ",sex:" + this.sex);
}
};
好像并看不出什么问题。其实不然...
我们发现,每次构造出来的对象中的方法都会去开辟一个空间。但是对象的方法都是一样的,完全没有必要。 我们可以把方法放入原型。
这样一来,不过我们构造多少对象,其方法都是公用的(单例的)。
可是为什么会这样呢?
首先,想想原型这个词,很形象,原本的模型。我们来看一个继承的例子:
var Person = function () {
this.name = "农码一生";
this.sex = "纯爷们";
this.getInfo = function () {
console.log("name:" + this.name + ",sex:" + this.sex);
}
};
var Student = function () { };
Student.prototype = new Person();//继承
var s1 = new Student();
var s2 = new Student();
console.log(s1.getInfo === s2.getInfo);
虽然getInfo在Person里面是直接实现的,但是到了Student的原型(prototype)里面就是一个Person对象的单例了。也就是说无论构造多少个Student对象其中的getInfo方法都是同一个。
但是,构造多个Person就有多个getInfo方法。所以,我们应该把getInfo方法放入Person的原型中。
var Person = function () {
this.name = "农码一生";
this.sex = "纯爷们";
};
Person.prototype.getInfo = function () {
console.log("name:" + this.name + ",sex:" + this.sex);
};
我们仔细推敲下这句话“把getInfo方法放入Person的原型中”,Person的原型是Object,那也就是说getInfo方法放到Object里面去了?
是的,不信请看:
如果原型和原型的原型都实现了同样的方法呢?我们来猜猜下面会打印哪个版本
var Person = function () {
this.name = "农码一生";
};
var Student = function () { };
Student.prototype = new Person();//继承
var stu = new Student();
Student.prototype.getName = function () {
console.log("我的名字:" + this.name);
}
Person.prototype.getName = function () {
console.log("My name is:" + this.name);
}
stu.getName();
如果注释掉中文版呢?
有没有觉得特神奇,具体原因我们用图来回答:
从另个一角度说,如果对象实现了原型中已有的方法那就等效于C#中虚方法重写了。
this指向
var name = "张三";
var obj = {
name:"李四",
getName: function(){
console.log(this.name);
}
}
obj.getName();
这个结果大家应该没什么疑问。
接着看下面的:
window.name = "张三";
var obj = {
name:"李四",
getName: function(){
console.log(this.name);
}
}
//obj.getName();
window.func = obj.getName;
window.func();
晕了没有?没关系,告诉大家一个简单实用的方法:方法是被谁“.”出来的,this就指向的谁。
call
"方法是被谁“.”出来的,this就指向的谁",这个口诀不一定适用所有方法。为什么这么说呢?请看下面:
window.name = "张三";
var obj = {
name: "李四",
getName: function () {
console.log(this.name);
}
}
//obj.getName();
window.func = obj.getName;
window.func.call(obj);
虽然还是window点的,但this已经指向了obj。
因为call可以改变this执行。
这个特性非常有用。比如,我们要编写一个下拉选中事件。
function func() {
console.log("我点击了" + $(this).find("option:selected").text());
}
$("#element1").change(function () {
func.call(this);
});
$("#element2").change(function () {
func.call(this);
});
在写func方法的时候不用考虑具体是那个下拉框元素。
apply
apply和call区别不大。
function func(age, sex) {
console.log("name:" + this.name + ",age:" + age + ",sex:" + sex);
}
var obj = {
name: "晓梅"
}
func.call(obj, "18", "妹子");
func.apply(obj,["18","小美女"]);
call和apply第一个参数都是this指向的对象。call第二个和以后的参数对应方法func的参数。而apply的第二个参数是个数组,包含方法的所有参数。
band
function func(age, sex) {
console.log("name:" + this.name + ",age:" + age + ",sex:" + sex);
}
var obj = {
name: "晓梅"
}
var func1 = func.bind(obj, "18", "妹子");
func1();
和apply、call的区别是,只是改变this指向并不执行。且参数传入方式和call一样。
js中的闭包
什么是闭包?我的理解是存在不能被回收的变量就是闭包。
最常见最大的一个闭包就是全局变量,定义了就不会被销毁,除非自动设为null。
而我们平时说的和使用的闭包却非如此,但同样会产生不会被销毁的变量。比如我们之前说的私有变量示例:
var Person = (function () {
var sex = "纯爷们";
return {
name: "农码一生",
getInfo: function () {
console.log("name:" + this.name + ",sex:" + sex);
}
};
})();
之所以说它是闭包,那是因为sex这个字段是永远不会被销毁。你想想,如果被销毁了,那我们调用getInfo的时候岂不是找不到sex字段了。所以不是不会销毁,而是不能销毁。
闭包的作用不仅仅是私有化。我们再来一例:
for (var i = 0; i < 10; i++) {
var t = setTimeout(function () {
console.log(i);
}, 100);
}
并不是我们想象的那样打印0到9。
因为计时器还没开始循环就执行完了。而此时变量i已经是10。
我们可以通过闭包为每次循环保存一个闭包变量。
for (var i = 0; i < 10; i++) {
(function (i) {
var t = setTimeout(function () {
console.log(i);
}, 100);
})(i);
}
什么是高阶函数
“高阶函数”名字特牛逼。其实我们在js中经常使用。
还是私有变量的例子:
var Person = (function () {
var sex = "纯爷们";
return {
name: "农码一生",
getInfo: function () {
console.log("name:" + this.name + ",sex:" + sex);
}
};
})();
- 当函数做被return时,那么就是高阶函数。
var getInfo = function (callback) {
$.ajax('url', function (data) {
if (typeof callback === 'function') {
callback(data);
}
});
}
getInfo(function (data) {
alert(data.userName);
});
getInfo在执行的时候,传入的参数是个函数。
- 当函数被当成参数传递时,那么这也是高阶函数。
本文已同步至索引目录:《设计模式学习》
【demo】:https://github.com/zhaopeiym/BlogDemoCode
【推荐】:深入理解javascript原型和闭包系列
面向对象编程思想(前传)--你必须知道的javascript(转载)的更多相关文章
-
面向对象编程思想(前传)--你必须知道的javascript
在写面向对象编程思想-设计模式中的js部分的时候发现很多基础知识不了解的话,是很难真正理解和读懂js面向对象的代码.为此,在这里先快速补上.然后继续我们的面向对象编程思想-设计模式. 什么是鸭子类型 ...
-
《jQuery风暴》第2章 必须知道的JavaScript知识
第2章 必须知道的JavaScript知识 JavaScript是jQuery应用的基础,掌握JavaScript这门语言是使用jQuery的基础条件.本章不会全面细致的讲解JavaScript的全部 ...
-
从零开始学习jQuery(剧场版) 你必须知道的javascript
原文:从零开始学习jQuery(剧场版) 你必须知道的javascript 一.摘要 本文是jQuery系列教程的剧场版, 即和jQuery这条主线无关, 主要介绍大家平时会忽略的一些javascri ...
-
Javascript:必须知道的Javascript知识点之“单线程事件驱动”
heiboard: Javascript:必须知道的Javascript知识点之“单线程事件驱动”
-
你必须知道的Javascript 系列
JavaScript是见过最多人说它“有趣”,“好玩”的一门语言.不仅仅是因为它的灵活性,包括它本身很多的特性,比如说原型链,作用域链都是非常好玩的东西.现在已经有很多的JavaScript设计模式, ...
-
C语言编程学习:使用函数必须知道的3点注意事项
C语言是面向过程的,而C++是面向对象的 C和C++的区别: C是一个结构化语言,它的重点在于算法和数据结构.C程序的设计首要考虑的是如何通过一个过程,对输入(或环境条件)进行运算处理得到输出(或实现 ...
-
《你必须知道的javascript(上)》- 1.作用域和闭包
1 作用域是什么 1.1 编译原理 分词/词法分析(Tokenizing/Lexing) 将由字符组成的字符串分解成(对编程语言来说)有意义的代码块,这些代码块被称为词法单元(token). 解析/语 ...
-
《你必须知道的javascript(上)》- 2.this与对象原型
1 关于this 1.1 为什么使用this 随着你的使用模式越来越复杂,显式传递上下文对象会让代码变得越来越混乱,使用this则不会这样.当我们介绍对象和原型时,你就会明白函数可以自动引用合适的上下 ...
-
五个你必须知道的javascript和web debug技术
转:http://js8.in/2013/11/20/%E4%BA%94%E4%B8%AA%E4%BD%A0%E5%BF%85%E9%A1%BB%E7%9F%A5%E9%81%93%E7%9A%84j ...
随机推荐
-
C语言程序设计第4堂作业
大家注意:本次作业稍有增加,由于放假期间大家空闲时间比较充足,将之前学习过程中遗留的问题必须在假期解决. 本次课学习主要内容: 分支结构中的二分支结构.多分支结构和else-if语句 掌握字符型数 ...
-
玉渊潭赏樱花有感:从无到有写一个jQuery开源插件
“玉渊潭公园樱花节”是每年樱花绽放时,都会在玉渊潭公园樱举办樱花节,游客前往玉渊潭公园,可以欣赏到20个品种2000株樱花.2016玉渊潭樱花节时间:3月中旬-4月中旬观赏最佳,2016年3月23日开 ...
-
关于php的两个符号@和$
在写代码的时候,碰到了在函数和变量前家 @和$的的问题,于是就借这个机会,学习下php的传值和传引用这两种方式 首先 @ 运算符只对表达式有效.对新手来说一个简单的规则就是:如果能从某处得到值,就能在 ...
-
Archlinux 的U盘自动装载(二)升级到 udisks2
在安装 mysql-gui-tools 过程中,发现需要用到 udisks2.udisks和udisks2可以互相替换也可以共用.最后决定换用 udisks2 安装 先卸载原来的软件,如果有的话. p ...
-
IOS学习【VMware 12 安装 Mac OS X 10.11】-Day1
1.下载安装VMware 12 pro (32位不能安装) 虚拟机 VM12密钥 5A02H-AU243-TZJ49-GTC7K-3C61N 2.unlock206 用于VMware 12识别tac ...
-
AP INVOICES IMPORT API(NOT request)
PROCEDURE process_cux_to_ap(x_return_status OUT NOCOPY VARCHAR2, x_msg_count OUT NOCOPY NUMBER, x_ms ...
-
分享一个开源的网盘下载工具BaiduPCS-Go
大家在使用网盘的时候,一定忍受不了限速下载的速度.今天给大家分享一个开源的网盘下载项目BaiduPCS-Go.Go语言编写,仿 Linux shell 文件处理命令的百度网盘命令行客户端.多平台支持, ...
-
用随机投掷飞镖法计算Pi值(Randomness Throwing dart Pi Python)
画一个边长为r的正方形和半径为r的四分之一的圆(如下图所示),向上面随机投掷飞镖,通过计算落在星星区域和整体区域的飞镖比例,即可求出π值. 公式推导如下: 假设正方形的边长r为1,那么飞镖落在星星区域 ...
-
前端框架之Vue(8)-表单输入绑定
基础用法 你可以用 v-model 指令在表单 <input> . <textarea> 及 <select> 元素上创建双向数据绑定.它会根据控件类型自动选取正确 ...
-
简单方法解决bootstrap3 modal异步加载只一次的问题
用过bootstrap3自身的modal的remote属性的人可能都有相同的疑惑:就是点击弹出modal后再次点击会从缓存中加载内容,而不会再次走后台,解决办法就是只要让modal本身的属性发生变化, ...