javascript我走过的坑 技术积累记录之下篇

前面我们已经介绍了《javascript我走过的坑 ?技术积累记录之上篇》,接下来我们继续给大家补充下篇,有关JavaScript自己走过的坑,大家借鉴,不要重蹈覆辙。

更多精彩内容请看web前端中文站
www.lisa33xiaoq.net 可按Ctrl + D 进行收藏

javascript我走过的坑  技术积累记录之下篇

JavaScript基础知识总结

12、属性标签

writable: 属性是否可修改或可写

enumerable:属性是否可以被遍历,被枚举,会影响for in中是否会出现

configurable:属性标签是否可以被修改,是否可以通过delete方式删除属性

属性标签

属性标签

13、对象标签

[[proto]]??原型标签

[[class]]

[[extensible]] ??对象是否可扩展

var obj = {x:1,y:2};
Object.isExtensible(obj);  // true
Object.preventExtensions(obj);
Object.isExtensible(obj);  // false
obj.z = 1;
obj.z;  // undefined, add new property false
Object.getOwnPropertyDescriptor(obj,'x');
//  Object {value: 1, writable: true, enumerable: true, configurable: true}

Object.seal(obj);
Object.getOwnPropertyDescriptor(obj,'x');
//  Object {value: 1, writable: true, enumerable: true, configurable: false}
Object.isSealed(obj);  // true www.lisa33xiaoq.net

Object.freeze(obj);
Object.getOwnPropertyDescriptor(obj,'x');
//  Object {value: 1, writable: false, enumerable: true, configurable: false}\
Object.isFrozen(obj);  // true

 

注意:这些方法只针对这个对象,并不能影响对象的原型链

 

序列化:

var obj = {x:1,y:true,z:[1,2,3],nullVal:null};

JSON.stringify(obj);??// ?”{“x”:1,”y”:true,”z”:[1,2,3],”nullVal”:null}”

若属性的值是undefined,将不会出现在序列化记过中。

若是NaN和Infinity,将会转化为null

若是Data();会转化为UTC格式

obj = {val:undefined,a:NaN,b:Infinity,c:new Date()};

JSON.stringify(obj);??// ?”{“a”:null,”b”:null,”c”:”2016-08-20T07:33:09.307Z”}”

 

将后端返回的json数据变为JS对象

obj = JSON.parse(‘{“x” : 1}’);

obj.x;??// ?1

合法的json必须属性用双引号“”

14、数组

JS中的数组是弱类型的,数组中可以含有不同类型的元素。数组元素甚至可以是对象或其他数组。

var commasArr1 = [1,,2]; ?// ?1,undefined,2

var commasArr1 = [,,]; ???// ?undefined*2 ?JS数组允许最后有一个多余的逗号,最后一个逗号后面被忽略掉(不建议使用)

数组大小:0~4,294,967,295(2^23-1)

var arrWithLength = new Array(100);   
//100是长度 undefined*100
var arrLikesLiteral = new Array(true,false,null,1,2,”hi”);  
//等价于[true,false,null,1,2,”hi”];

数组添加删除操作:

var arr = [1,2,3,4,5];
delete arr[0];
arr[0];   // undefined
arr.length; // 5
arr.unshift(0);  // 在数组头部添加元素
arr;  // [0,1,2,3,4,5]
arr.length -= 1;  //可以删除数组的最后一个元素
arr;  // [0,1,2,3,4]  5 is removed
arr.pop();  // 4 returned by pop
arr;  // [0,1,2,3]  4 is removed
arr.shift();  //  在头部删除元素 0 returned by shift
arr; //  [1,2,3]

稀疏数组并不含有从0开始的连续索引,一般length属性值比实际元素个数大。实际应用中不常见。

var arr1 = [undefined];
var arr2 = new Array(1);
0 in arr1;  // true
0 in arr2;  // false
arr1.length = 100;
arr1[99] = 123;
99 in arr1; // true
98 in arr1; // false

?15、数组方法

15.1 Array.prototype.join ?将数组转为字符串

var arr = [1,2,3];
arr.join();   // “1,2,3”
arr.join(“_”);   // “1_2_3”

15.2 Array.prototype.reverse ?将数组逆序,原数组被修改

15.3 Array.prototype.sort ?排序 ?默认是按照字母顺序排序,原数组被修改

arr = [13,24,51,3];
arr.sort();   // [13,24,3,51]
arr.sort(function(a,b){
	return a-b;
});     //  [3.13.24.51]

15.4 Array.prototype.concat ?// 合并数组,原数组并未被修改

15.5 Array.prototype.slice ?// ?返回部分数组,原数组未修改

15.6 Array.prototype.splice ?// ?数组拼接

var arr = [1,2,3,4,5];
arr.splice(2);  // 返回[3,4,5]
arr; //  [1,2]; 原数组被修改
var arr = [1,2,3,4,5];
arr.splice(2,2); // 返回[3,4]; 第二个参数表示想要删除元素的个数
arr;  // [1,2,5]
var arr = [1,2,3,4,5];
arr.splice(1,1,’a’,’b’);  //  返回[2]
arr;  // [1,”a”,”b”,3,4,5]

15.7 Array.prototype.forEach ?数组遍历

var arr = [1,2,3,4,5];
arr.forEach(function(x,index,a){
console.log(x+'_'+index+'_'+ (a === arr))
});  
//  1_0_true
//  2_1_true
//  3_2_true
//  4_3_true
//  5_4_true

15.8 Array.prototype.map ?数组映射,不会修改原数组

var arr = [1,2,3];
arr.map(function(x){
	return x +10;
});  //  [11,12,13]
arr;  // [1,2,3]

15.9?Array.prototype.filter ?数组过滤,不会修改原数组

15.10?Array.prototype.every & some ??数组判断

var arr = [1,2,3,4,5];
arr.every(function(x){
	return x <10;
});  // true
arr.every(function(x){
	return x<3;
});    // false
arr.some(function(x){
	return x === 3;
}); // true
arr.some(function(x){
	return x === 100;
});// false

15.11?Array.prototype.reduce & reduceRight ??不会改变原数组

var arr = [1,2,3];
var sum = arr.reduce(function(x,y){
	return x+y
},0);  //6 第一次x=0,y=1返回0+1;第二次x=1,y=2,返回1+2;第三次x=3,y=3,返回3+3,所以最后值为6
arr;  //[1,2,3]  
reduceRight是从数组的右边开始执行。
arr = [3,9,6]
var max = arr.reduce(function(x,y){
	console.log(x + “|” + y);
	return x>y? x:y;
});
// 3|9
// 9|6
max; // 9
max = arr.reduceRight(function(x,y){
	console.log(x + “|” + y);
	return x>y? x:y;
});
// 6|9
// 9|3
max; // 9

15.12?Array.prototype.indexOf & lastIndexOf ?数组检索

lastIndexOf是从右向左寻找

15.13?Array.isArray ?判断是否为数组

之前都是Array.prototype上的,这个是Array构造器对象上的属性,不可以直接拿变量.isArray来使用。

Array.isArray([]); ?// true

?16、数组和一般对象的比较

相同点:都可以继承;

16.1 数组是对象,对象不一定是数组;

16.2 都可以当作对象添加删除属性

不同点:

16.3 数组自动更新length;

16.4 按索引访问数组常常比访问一般对象属性明显迅速;

16.5 数组对象继承Array.prototype上的大量数组操作方法

17、函数

函数是一块JavaScript代码,被定义一次,但可执行和调用多次。JS中的函数也是对象,所以JS函数可以像其它对象那样操作和传递,所以我们也常叫JS中的函数为函数对象。

函数的返回值依赖于return语句,若没有,默认在所有代码执行完之后返回undefined。(指的是一般调用)

不同的调用方式:

直接调用:foo();

对象方法:o.method();

构造器:new?Foo();

call/apply/bind:func.call(o);

18、函数声明和函数表达式

函数声明:

function add(a,b){
	a = +a;
	b = +b;
	if(isNaN(a) || isNaN(b)){
	return;
}
	return a+b;
}

函数表达式:

var add = function(a,b){
};

立即执行函数表达式:

(function(){
})();
return function(){
};

命名式函数表达式,不太常见

var add = function foo(a,b){
}

函数声明和函数表达式的区别:

函数声明会被前置。

var num = add(1,2);
   console.log(num);   //  输出:3
   function add(a,b){
	   a = +a;
	   b = +b;
	   if (isNaN(a) || isNaN(b)) {
		return;
	}
	   return a+b;
   }
// VM182:1 Uncaught TypeError: add is not a function(…)
  var num = add(1,2);
   console.log(num);
   var add = function(a,b){
	   a = +a;
	   b = +b;
	   if (isNaN(a) || isNaN(b)) {
		return;
	}
	   return a+b;
   }

 

函数声明和变量声明会被提前,而赋值语句和表达式产生的函数的创建会在后面执行。

var?func = function nfe() {};

alert(func === nfe);

在IE6~8中会显示false,在IE9以及chrome等中会显示‘nfe’is?undefined;

19、this

19.1 全局的this(浏览器):指向全局对象,即window

console.log(this.document === document);  // true
console.log(this === window);  // true

19.2?一般函数的this(浏览器):指向全局对象window

function f1(){
return this;}
f1() === window; // true
严格模式下:指向undefined
function f2(){
"use strict";
return this;}
f2() === undefined; // true

19.3?作为对象方法的函数的this

var o = {
prop:37,
f:function(){
return this.prop;
}
};
console.log(o.f());  // 37
var o = {prop:37};
function independent() {
return this.prop;
}
o.f = independent;
console.log(o.f());  // 37

只要函数是对象的方法,那么this就会指向这个对象。

19.4?对象原型链上的this

var o = {f:function(){ return this.a + this.b;}};
var p = Object.create(o);
p.a = 1;
p.b = 4;
console.log(p.f());  // 5

19.5?构造器中的this

function MyClass(){
this.a = 37;
}
var o = new MyClass();
console.log(o.a);  //  37
function C2(){
this.a = 37;
return {a:38};
}
o = new C2();
console.log(o.a);  // 38

19.6?call/apply方法与this

function add(c,d){
return this.a + this.b + c + d;
}
var o = {a:1,b:3};
add.call(o,5,6);  // 15
add.apply(o,[10,20]);  // 34
function bar(){
console.log(Object.prototype.toString.call(this));
}
bar.call(7);  // [object Number]

19.7?bind方法与this(ES5以后提供,IE9+支持)

function f(){
return this.a;
}
var g = f.bind({a : "test"});
console.log(g());  // test

var o = {a:37,f:f,g:g};
console.log(o.f(),o.g());  // 37 "test"

?20、函数属性arguments

foo.name – 函数名
foo.length – 形参个数
arguments.length – 实参个数
function foo(x,y,z){
arguments.length; // 2
arguments[0]; // 1
arguments[0] = 10;
x; //变为 10

arguments[2] = 100;
z; // undefined !!!
arguments.callee === foo;  // true
}
foo(1,2);
foo.length; // 3
foo.name; // “foo”

arguments是一个类数组的对象,但并不是数组,没有Array.prototype的方法

传了参数才会和对应的形参绑定关系,若未传参数,失去绑定关系。

若在严格模式下,即’use strict’,arguments总是传入形参的副本,因此arguments[0] = 10;

并不会改变x的值。arguments.callee禁止使用。

20.1?apply/call方法(浏览器)

function foo(x,y){
console.log(x,y,this);
}
foo.call(100,1,2); // 1 2 Number {[[PrimitiveValue]]: 100}
foo.apply(true,[3,4]); // 3 4 Boolean {[[PrimitiveValue]]: true}
foo.apply(null);  // undefined,undefined,window
foo.apply(undefined); //  undefined,undefined,window
严格模式下:
function foo(x,y){
'use strict';
console.log(x,y,this);
}
foo.apply(null);  //  undefined,undefined,null
foo.apply(undefined); // undefined,undefined,undefined

20.2?bind方法

this.x = 9;
var module = {
x:81,
getX:function(){return this.x;}
};
module.getX(); // 81
var getX = module.getX;
getX();  // 9 指向全局变量
var boundGetX = getX.bind(module);
boundGetX();  //  81

20.3?bind与currying?函数柯里化

function add(a,b,c){
return a + b + c;
}
var func = add.bind(undefined,100);
func(1,2); // 103 a被改为100,1传给了b,2传给了c
var func2 = func.bind(undefined,200);
func2(10); // 310 b被改为200,10传给了c

20.4?bind与new

function foo() {
this.b = 100;
return this.a;
}
var func = foo.bind({a:1});
func(); // 1
new func(); // {b:100} bind会被忽略掉。

判断this的指向(1-4优先级逐级递减,1优先级最高,4优先级最低):
1、函数被new调用,this指向由new新构造出来的这个对象;
2、函数通过call()、apply()、bind()调用,this指向被绑定的对象;
3、函数作为方法被调用,this指向这个对象(即常说的对象上下文);
4、默认(非严格模式)情况下,this指向window, 严格模式下,this指向undefined。

bind方法模拟(难点):(颜色不同,有对应关系)

function foo() {
this.b = 100;
return this.a;
}
var func = foo.bind({a:1});
func(); // 1
new func(); // {b:100}

    if (!Function.prototype.bind) {
		Function.prototype.bind = function(oThis){
			if (typeof this != 'function') {
				// closest thing possible to the ECMAScript 5
				// internal IsCallable function
				throw new TypeError('what is trying to be bound is not callable');
			}
			var aArgs = Array.prototype.slice.call(arguments, 1),
			fToBind = this,
			fNOP = function(){},
			fBound = function(){
				return fToBind.apply(this instanceof fNOP? this:oThis,
						aArgs.concat(Array.prototype.slice.call(arguments)));
			};
			fNOP().prototype = this.prototype;
			fBound().prototype = new fNOP();
			
			return fBound;
		};
	}

?21、闭包和作用域

维基百科:在计算机科学中,闭包(也称词法闭包或函数闭包)是指一个函数或函数的引用,与一个引用环境绑定在一起。这个引用环境是一个存储该函数每个非局部变量(也叫自由变量)的表。

闭包,不同于一般的函数,它允许一个函数在立即词法作用域外调用时,仍可访问非本地变量。

优点:灵活和方便,封装

缺点:空间浪费,内存泄漏,性能消耗

JS没有块级作用域

for (var item in {a:1,b:2}){
	console.log(item);
}
console.log(item);     // item still in scope
在function前加!或者+,作用是把函数变成函数表达式而不是函数声明。
!function(){
	// do sth here
	var a,b;
}(); 

如果省略叹号,会理解为函数声明,会被前置处理掉,最后留下一对括号,或者省略名字的话会报语法错误。

JS作用域主要有三种:全局、函数、eval

变量对象(Variable?Object)是ige抽象概念中的“对象”,它用于存储执行上下文中的:变量、函数声明、函数参数

21.1?变量初始化阶段

VO按照如下顺序填充:1)函数参数(若未传入,初始化该参数值为undefined);2)函数声明(若发生命名冲突,会覆盖);3)变量声明(初始化变量值为undefined,若发生命名冲突,会忽略)。

21.2?代码执行阶段

alert(x);  // function
var x = 10;
alert(x);  // 10
x=20;
function x(){}
alert(x);  // 20
if (true){
var a = 1;
}else{
var b = true;
}
alert(a);  // 1
alert(b);  // undefined

?22、OOP(面向对象编程)

面向对象程序设计(Object-oriented programming,OOP)是一种程序设计范型,同时也是一种程序开发的方法。对象指的是类的实例。它将对象作为程序的基本单元,将程序和数据封装其中,以提高软件的重用性、灵活性和扩展性。 ??———维基百科

特点:继承、封装、多态、抽象

22.1?基于原型的继承:

function Foo(){
this.y = 2;
}
typeof Foo.ptototype; // “object”
Foo.prototype.x = 1; 
var obj3 = new Foo();
obj3.y; // 2
obj3.x; // 1
obj3继承了Foo.prototype

22.2?prototype属性与原型

function Foo(){}
typeof Foo.ptototype; // “object”
Foo.ptototype.x = 1;
Foo.prototype的结构:
Foo.prototype
{
	constructor:Foo,
	_protp_:Object.prototype,
	x:1
}

Foo函数有一个prototype对象属性,作用是当使用new?Foo()去构造Foo的实例时,prototype会用作new出来的对象的原型,即new出来的原型通常都是它构造器的prototype属性。

web前端中文站点评:

学习JavaScript,可以依据这三本书慢慢进修,《javascript权威指南》、《JavaScript DOM编程艺术》和《javascript高级程序设计》,以上这些就是自己在学习JavaScript遇到的坑,也算是JavaScript基础的总结分享吧,希望对大家有用。

 

 

 

0
如无特殊说明,文章均为原作者原创,转载请注明出处

该文章由 发布

这货来去如风,什么鬼都没留下!!!
发表我的评论

Hi,请填写昵称和邮箱!

取消评论
代码 贴图 加粗 链接 删除线 签到

(1)条精彩评论:
  1. <a href='http://www.baidu.com' rel='external nofollow' class='url'>xiaoq</a>
    不错,收藏收藏
    xiaoq2018-07-31 23:46 回复