前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >javascript模式 读书笔记一

javascript模式 读书笔记一

作者头像
lilugirl
发布2019-05-26 20:27:41
9770
发布2019-05-26 20:27:41
举报
文章被收录于专栏:前端导学前端导学

第一章 简介

模式

模式是指一个通用问题的解决方案。 模式分三种 设计模式 编码模式:javascript特有的

反模式:常见的 引发的问题比解决的问题更多的一种方法。

JavaScript:基本概念

面向对象

只有五种基本类型不是对象:数值类型,字符串类型,布尔类型,空类型和未定义类型。

函数实际上也是对象,函数有属性和方法。

对象主要有两种: 原生的(Native) 原生的对象分为内置对象(数组,日期等) 和用户自定义对象 (var o={}) 主机的(Host) 包含windows对象和所有的DOM对象。

没有类

JavaScript中没有类。

原型(Prototypes)

JavaScript没有继承,可以使用多种方法实现继承,通常使用原型。

原型是一个对象,并且创建的每一个都会自动获取一个Prototypes属性,该属性指向一个新的空对象。

该对象几乎等同于采用对象字面量或Object()创建的对象,区别在于它的constructor属性指向了所创建的函数,而不是指向内置的Object()函数。可以为该空对象增加成员变量,以后其他对象也可以从该对象继承并像使用自己的属性一样使用该对象的属性。

原型就是一个对象,每一个函数都有Prototype属性。

ECMAScript 5

核心的JavaScript编程语言(不包含DOM,BOM和额外的主机对象)是基于ECMAScript标准(缩写是ES).

strict模式

避免使用arguments.callee之类的构造函数

ES5 Object.create() 等同于ES3 Object()

暗示全局变量(implied globals):任何变量,如果未经声明,就为全局对象所有

JSLint

JavaScript代码质量检查工具

Console

Console对象不是JavaScript语言的一部分,而是浏览器提供的一个运行环境。

P15 另一种创建隐式全局变量的反模式是带有var声明的链式赋值。

代码语言:javascript
复制
function foo(){
  var a=b=0;
  // 等于 var a=(b=0);
}

隐含全局变量不是真正的变量,而是全局对象的属性。属性可以通过delete操作符删除,但变量不可以。 P16 访问全局对象,可以按如下方式访问

代码语言:javascript
复制
var global=(function(){return this;}());

P18 提升:JavaScript允许在函数的任意地方声明多个变量,无论在哪里声明,效果都等于在函数顶部进行申明。 P19 在所有的浏览器中,通过将HTML容器上需要遍历的次数缓存起来都会大大提高速度。 P21 使用正常的for循环来处理数组,并使用for-in循环来处理对象。

P23 不要给内置的原型增加属性

P24使用===和!====操作符对数值和类型进行比较 P26 避免使用eval(),可使用new Function()代替eval(). P27 使用paresInt()

P45 不要使用new Object()构造函数

第二章 基本技巧

编写可维护的代码

尽量少用全局变量

Javascript使用函数管理作用域。变量在函数内生命,只在函数内有效。全局变量在函数外部生命,在函数内部无需声明即可食用。

每个Javascript环境都有全局对象,可在函数外部使用this进行访问。

创建的每一个全局变量都为全局对象所有。

代码语言:javascript
复制
myglobal="hello";  //反模式
console.log(myglobal);
console.log(window.myglobal);
console.log(window['myglobal']);
console.log(this.myglobal);

全局变量的问题

自执行立即生效函数 the self-executing immediate functions

Javascript特性: 1 Javascript可直接使用变量,甚至无需声明 2 Javascript有个暗示全局变量(implied globals)的概念,任何变量,如果未经声明,就为全局对象所有。

代码语言:javascript
复制
function sum(x,y){
   //反模式:暗示全局变量 result
   result=x+y;
   return result;
}
代码语言:javascript
复制
function sum(x,y){
  //正确的写法
  var result=x+y;
  return result;
}

另一种创建隐式全局变量的反模式是带有var声明的链式赋值

代码语言:javascript
复制
function foo(){
   var a=b=0;
   //反模式 a是局部变量 b是全局变量
}

首先,优先级较高的是表达式b=0,此时b未经声明。表达式的返回值为0,它被赋予给局部变量a 。相当于var a=(b=0);

代码语言:javascript
复制
function foo(){
   //正确的赋值方式 对链式赋值的所有变量都进行了声明
   var a,b;
   a=b=0; 
}

变量释放时的副作用

隐含全局变量与明确定义的全局变量的细微不同:能否删除

  • 使用var创建的全局变量(这类变量在函数外部创建)不能删除
  • 不使用var创建的隐性全局变量(尽管是在函数内部创建)可以删除

这表明隐含全局变量是全局对象的属性,属性可以通过delete操作符删除,但变量不可以。

代码语言:javascript
复制
//定义三个全局变量
var global_var=1;
global_novar=2; //反模式
(function(){
	global_fromfunc=3 //反模式
}());


//企图删除
delete global_var; //false
delete global_novar; //true;
delete global_fromfunc; //true;

//测试删除情况
typeof global_var; //number类型
typeof global_novar; //undefined 类型
typeof global_fromfunc; //undefined类型

访问全局对象

代码语言:javascript
复制
var global=(function(){
	return this;
}());

从内嵌函数的作用域访问window对象 (不带硬编码的方式)

单一var模式(Single var Pattern)

只使用一个var在函数顶部进行变量声明的模式。

代码语言:javascript
复制
function func(){
	var a=1,
	    b=2,
	    sum=a+b,
	    myobject={},
	    i,
	    j;

	    //函数体
}
代码语言:javascript
复制
function updateElement(){
	var el=document.getElementById('result'),
	    style=el.style;

	    //使用el和style再做其他事...
	   
}

提升:零散变量的问题

Javascript允许在函数的任意地方声明多个变量,无论在哪里声明,效果都等于在函数顶部进行声明。所以容忍先使用后声明的情况。

代码语言:javascript
复制
//反模式
myname="global";//全局变量
function func(){
	alert(myname); //未定义
	var myname="local";
	alert(myname); //局部变量
}
func();

前面的代码等同于下面的代码

代码语言:javascript
复制
myname="global"; //全局变量
function func(){
	var myname; //等同于->var myname=undefined;
	alert(myname); //未定义
	myname="local";
	alert(myname); //局部
}
func();

for循环

for循环经常用在遍历数组或类数组对象。

好的for循环模式是将已经遍历过的数组(或容器)的长度缓存起来。如以下代码所示。

代码语言:javascript
复制
for(var i=0, max=myarray.length;i<max;i++){
   //对myarray[i]进行处理
}

单变量模式,可以将变量放到循环以外

代码语言:javascript
复制
function looper(){
  var i=0,
      max,
      myarray=[];
  //...

  for(i=0,max=myarray.length;i<max;i++){
     //处理myarray[i]
  }
}

++和--提倡 excessive trickiness 过分棘手

改进版,逐步将至0,这样更快

代码语言:javascript
复制
var i,myarray=[];
for(i=myarray.length;i--;){
   //处理myarray[i]
}
代码语言:javascript
复制
var myarray=[],
    i=myarray.length;

while(i--){
   //处理 myarray[i]
}

for-in循环

for-in循环应该用来遍历非数组对象。使用for-in循环也被称为枚举enumeration

代码语言:javascript
复制
//对象

var woman={
	hands:4
};
var man={
	hands:2,
	legs:2,
	heads:1
};

//代码的其他部分
//将一个方法添加到所有对象上
if(typeof Object.prototype.clone==="undefined"){
	Object.prototype.clone=function(){
		alert('克隆');
	};
}




//1 
//for-in循环
for(var i in man){
	if(man.hasOwnProperty(i)){  //filter
		console.log(i,":",man[i]);
	}
	
}
/* 
控制台中的结果
hands:2
legs:2
heads:1
*/

//2
//反模式
//不适用hasOwnProperty()进行检查后使用for-in循环的结果 
for(var i in man){
	console.log(i,":",man[i]);
}

/* 
控制台中的结果
hands:2
legs:2
heads:1
clone:function Object.clone()
*/

另外一种使用hasOwnProperty()的模式是在Object.prototype中调用该函数

代码语言:javascript
复制
for(var i in man){
	if(Object.prototype.hasOwnProperty.call(man,i)){  //过滤
		console.log(i,":",man[i]);
	}
	
}

使用hasOwnProperty对man对象进行精炼后,可以避免命名冲突,也可以使用一个本地变量来缓存比较长的属性名。

代码语言:javascript
复制
var i,
    hasOwn=Object.prototype.hasOwnProperty;
for(var i in man){
	if(hasOwn.call(man,i)){  //过滤
		console.log(i,":",man[i]);
	}
	
}

变种 略过花括号

代码语言:javascript
复制
//警告 :不能通过JSLint检查
var i,
    hasOwn=Object.prototype.hasOwnProperty;
    for(i in man) if(hasOwn.call(man,i)){  //过滤
    	console.log(i,":",man[i]);

    }

不要增加内置的原型

增加构造函数的原型属性是一个增强功能性的强大的方法,但有时候该方法过于强大。

增加内置构造函数(例如Object(),Array(),Function()等)的原型是很有诱惑的,但这可能会严重影响可维护性。

实在需要增加自定义方法可以用如下代码:

代码语言:javascript
复制
if(typeof Object.prototype.myMethod!=="function"){
	Object.prototype.myMethod=function(){
		//implementation....
	}
}

switch模式

代码语言:javascript
复制
var inspect_me=0,
     result='';

 switch(inspect_me){
 	case 0:
 	   result="zero";
 	   break;
 	case 1:
 	   result="one";
 	   break
 	default:
 	   result="unknown";
 }

避免使用瘾式类型转换

使用=== 和!==操作符

代码语言:javascript
复制
var zero=0;
if(zero===false){
	//因为zero是0,而不是false,所以代码未执行
	
}
//反模式
if(zero==false){
	//该代码会被执行。。。
	
}

避免使用eval()

代码语言:javascript
复制
var obj={
	name:"lilu",
}

//反模式
var property="name";
alert(eval("obj."+property));


//推荐的方法
var property="name";
alert(obj[property]);

eval()包含安全隐患,这样做有可能执行被篡改过的代码。 通过setInterval(), setTimeout()和function()等构造函数传递参数,也会导致类似eval的隐患。

代码语言:javascript
复制
//反模式
setTimeout("myFunc()",1000);
setTimeout("myFunc(1,2,3)",1000);

//推荐模式
setTimeout(myFunc,1000);
setTimeout(function(){
	myFunc(1,2,3);
},1000);

eval()中任何采用var定义的变量会自动变成全局变量。因此可以通过使用Function()或者将eval()调用封装到一个即时函数中。

代码语言:javascript
复制
console.log(typeof un); //未定义
console.log(typeof deux); //未定义
console.log(typeof trois); //未定义

var jsstring="var un=1;console.log(un);";
eval(jsstring); //logs "1"

jsstring="var deux=2; console.log(deux);";
new Function(jsstring)(); //logs "2"

jsstring="var trois=3; console.log(trois);";
(function(){
	eval(jsstring);
}());  //logs "3";

console.log(typeof un); //数值类型
console.log(typeof deux); //未定义
console.log(typeof trois); //未定义

new Function()和eval()的区别在于eval()会影响到作用于链,而Function更多地类似于一个沙盒。无论在哪里执行Function,它都仅仅能看到全局作用域。 Function的使用和new Function是一样的。

代码语言:javascript
复制
(function(){
	var local=1;
	eval("local=3; console.log(local)"); //logs 3
	console.log(local); //logs 3
}());



(function(){
	var local=1;
	Function("console.log(typeof local);")(); //logs 未定义
}());

使用parseInt()的数值约定

每次具体制定进制参数

代码语言:javascript
复制
var month="06",
    year="09";
month=parseInt(month,10);

year=parseInt(year,10);

//另外一个将字符串转换为数值的方法是 +"08" //结果是8 Number("08") //8

编码约定

一致遵循约定比这个具体约定是什么更为重要。

缩进

JSLint默认值 4个空格缩进

代码语言:javascript
复制
function outer(a, b){
	var c = 1,
	    d = 2,
	    inner;
	if (a > b){
        inner = function () {
        	return {
        		r: c - d
        	};
        };
	} else {
		inner = function () {
			return {
				r: c + d
			};
		};
	}
	return inner;
}

大括号

应该经常使用大括号

开放的大括号位置

分号插入机制 semicolon insertion mechanism

空格

命名约定

构造函数的首字母大写

分割单词

构造函数可以用使用大驼峰命名法

函数和方法名可以用小驼峰命名法

函数的变量可以用小写单词和下划线连接

其他命名默模式

变量名全部大写代表该变量在生命周期中不可变

编写注释

编写API文档

代码语言:javascript
复制
/**
* @tag value
*/

/**
 * 反转一个字符串
 *
 * @param {String} 输入血药反转的字符串
 * @return {String} 反转后的字符串
 */
var reverse=function(input){
	//...
	return output;
};

YUIDoc范例

http://www.jspatterns.com/book/2/

代码语言:javascript
复制
/**
 * 我的JavaScript应用程序
 *
 * @module myapp
 */

 var MYAPP = {};

 /**
  * 一个数字工具
  * @namespace MYAPP
  * @class math_stuff
  */
MYAPP.math_stuff={
	/**
	 * Sums two numbers
	 *
	 * @method sum
	 * @param {Number} 是第一个数
	 * @param {Number} 是第二个数
	 * @return {Number} 两个输入的总和
	 */
	sum: function (a, b) {
		return a + b;
	},
	/**
	 * Multiplies two numbers
	 *
	 * @method multi
	 * @param {Number} 是第一个数
	 * @param {Number} 是第二个数
	 * @return {Number} 两个输入相乘后结果
	 */
	 multi: function (a, b) {
         return a * b;
	 }

};
 /**
  * Constructs Person objects
  * @class Person
  * @constructor
  * @namespace MYAPP
  * @param {String} first 是名字
  * @param {String} last 是姓氏
  */
 MYAPP.Person =function (first, last){
 	/**
 	 * 人的姓名
 	 * @property first_name
 	 * @type String
 	 */
 	this.first_name=first;
 	/**
 	 * Last (family) name of the person
 	 * @property last_name
 	 * @type String
 	 */
 	this.last_name=last;



 };
/**
 * Returns the name of the person object
 *
 * @method getName
 * @return {String} 人的姓名
 */
MYAPP.Person.prototype.getName = function () {
	return this.first_name + ' ' + this.last_name;
};

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 第一章 简介
    • 模式
      • JavaScript:基本概念
        • 面向对象
        • 没有类
        • 原型(Prototypes)
      • ECMAScript 5
        • JSLint
          • Console
          • 第二章 基本技巧
            • 编写可维护的代码
              • 尽量少用全局变量
                • 全局变量的问题
                  • 变量释放时的副作用
                    • 访问全局对象
                      • 单一var模式(Single var Pattern)
                        • 提升:零散变量的问题
                          • for循环
                            • for-in循环
                              • 不要增加内置的原型
                                • switch模式
                                  • 避免使用瘾式类型转换
                                    • 使用parseInt()的数值约定
                                      • 编码约定
                                        • 缩进
                                          • 大括号
                                            • 开放的大括号位置
                                              • 空格
                                                • 命名约定
                                                  • 构造函数的首字母大写
                                                    • 分割单词
                                                      • 其他命名默模式
                                                        • 编写注释
                                                          • 编写API文档
                                                            • YUIDoc范例
                                                            相关产品与服务
                                                            容器服务
                                                            腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
                                                            领券
                                                            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档