-
Notifications
You must be signed in to change notification settings - Fork 2
JavaScript 深入浅出
慕课网 学习javascript的部分笔记:)
- number
- string
- boolean
- null
- undefined
- object
- Function
- Array
- Date
- ……
-
a==b
- "1.23"==1.23
- 0==false
- null==undefined
- new Object()==new Object()
- [1,2]==[1,2]
-
a===b
-
类型不同,返回false
-
类型相同
-
NaN 不等于 NaN
-
new Object 不等于 new Object
-
null === null
-
undefined === undefined
-
-
当类型相同 ,同===
当类型不同,尝试类型转化和比较:
- null==undefined
- number==string //**转number** 1=="1.0" true
- boolean==? //**转number** 1==true //true
- object == number|string //尝试对象转为基本类型 new String("hi") =="hi" //true
- 其他:false
- typeof
- instanceof
- Object.prototype.toString
- constructor
- duck type
typeof 100 === "number"
typeof true === "boolean"
typeof function () {} === "function"
typeof(undefined) ) === "undefined"
typeof(new Object() ) === "object"
typeof( [1, 2] ) === "object"
typeof(NaN ) === "number"
typeof(null) === "object"typeof null === "object" obj instanceof Object
//例
[1, 2] instanceof Array === true
new Object() instanceof Array === falseObject.prototype.toString.apply(null).slice(7,12);
Object.prototype.toString.apply([]); === "[object Array]";
Object.prototype.toString.apply(function(){}); === "[object Function]";
Object.prototype.toString.apply(null); === "[object Null]"
Object.prototype.toString.apply(undefined); === "[object Undefined]"
// IE6/7/8 Object.prototype.toString.apply(null) 返回"[object Object]"
// bugstypeof
适合基本类型及function检测,遇到null失效。
[[Class]]
通过{}.toString拿到,适合内置对象和基元类型,遇到null和undefined失效(IE678等返回[object Object])。
instanceof
适合自定义对象,也可以用来检测原生对象,在不同iframe和window间检测时失效。
<!--任务
请在index.html文件中,编写arraysSimilar函数,实现判断传入的两个数组是否相似。具体需求:
1. 数组中的成员类型相同,顺序可以不同。例如[1, true] 与 [false, 2]是相似的。
2. 数组的长度一致。
3. 类型的判断范围,需要区分:String, Boolean, Number, undefined, null, 函数,日期, window.
当以上全部满足,则返回"判定结果:通过",否则返回"判定结果:不通过"。
-->
<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Untitled Document</title>
</head>
<body>
<script type="text/javascript">
/*
* param1 Array
* param2 Array
* return true or false
*/
function arraysSimilar(arr1, arr2){
var t1=[];
var t2=[];
var flag=true;
if (arr1 instanceof Array && arr2 instanceof Array && arr1.length == arr2.length ) {
for (var i = arr1.length - 1; i >= 0; i--) {
if (Object.prototype.toString.apply(arr1) !==Object.prototype.toString.apply(arr2) ) {
flag=false;
break;
}
}
}
if (flag) {
return true;
}
return false;
}
//方法2
function arraysSimilar(arr1, arr2) {
var t1 = [];
var t2 = [];
if (arr1 instanceof Array && arr2 instanceof Array && arr1.length === arr2.length) {
for (var i in arr1) {
t1.push(getType(arr1[i]));
t2.push(getType(arr2[i]));
}
return t1.sort().toString() === t2.sort().toString();
} else {
return false;
}
}
function getType(o) {
var _opt = Object.prototype.toString.apply(o);
/\[object (\w+)\]/.test(_opt);
return RegExp.$1;
}
</script>
<script src="testData.js"></script>
</body>
</html>
## 表达式与运算符
-
原始表达式( 常量,直接量 / 关键字 / 变量)
-
数组,对象的初始化表达式
-
函数表达式
var fe = function(){}; (function(){console.log('hello world');})();
-
属性访问表达式
var o={x:1}; o.x; o['x'];
-
创建对象表达式
new Func(1,2) new Object
var p;
var obj = {x : 1, y: 2}
for (p in obj) {
}
for in 的需要注意的地方
- 顺序不确定
- enumerable为false时不会出现
- forin对象属性时受原型链影响
with ({x : 1}) {
console.log(x);
}
with (document.forms[0]) {
console.log(name.value);
}
var form = document.forms[0];
console.log(form.name.value);
不推荐
- 让JS引擎优化更难
- 可读性差
- 可被变量定义代替
- 严格模式下被禁用
Note:严格模式是一种特殊的执行模式,它修复了部分语言上的不足,它修复了部分语言上的不足,提供更强的错误检查,并增强安全性。
定义方式
function func() {
'use strict';
}
或者
'use strict';
function func() {
}
严格模式下:
-
不允许用with
-
不允许未声明的变量被赋值
-
arguments变为参数的静态副本
!function(a) { arguments[0] = 100; console.log(a); }(1); // 1=>100 // 不传 => undefined !function(a) { 'use strict'; arguments[0] = 100; console.log(a); }(1); // 1 !function(a) { 'use strict'; arguments[0].x = 100; console.log(a.x); }({x:1}); // 100
-
delete参数、函数名报错
-
delete不可配置的属性报错
-
对象字面量重复属性名报错
-
禁止八进制字面量
-
eval, arguments变为关键字,不能作为变量、函数名
-
eval独立作用域
严格模式-小结
- 不允许用with
- 所有变量必须声明, 赋值给为声明的变量报错,而不是隐式创建全局变量。
- eval中的代码不能创建eval所在作用域下的变量、函数。而是为eval单独创建一个作用域,并在eval返回时丢弃。
- 函数中得特殊对象arguments是静态副本,而不像非严格模式那样,修改arguments或修改参数变量会相互影响。
- 删除configurable=false的属性时报错,而不是忽略
- 禁止八进制字面量,如010 (八进制的8)
- eval, arguments变为关键字,不可作为变量名、函数名等
- 一般函数调用时(不是对象的方法调用,也不使用apply/call/bind等修改this)this指向null,而不是全局对象。
- 若使用apply/call,当传入null或undefined时,this将指向null或undefined,而不是全局对象。
- 试图修改不可写属性(writable=false),在不可扩展的对象上添加属性时报TypeError,而不是忽略。
- arguments.caller, arguments.callee被禁用
## 对象
对象中包含一系列属性,这些属性是无序的。
每个属性都有一个字符串key和对应的value。
var obj = {};
obj[1] = 1;
obj['1'] = 2;
obj; // Object {1: 2}
obj[{}] = true;
obj[{x : 1}] = true;
obj; // Object {1: 2, [object Object]: true}
///创建对象 new/原型链
function foo(){}
foo.prototype.z = 3;
var obj =new foo();
obj.y = 2;
obj.x = 1;
obj.x; // 1
obj.y; // 2
obj.z; // 3
typeof obj.toString; // ‘function'
'z' in obj; // true
obj.hasOwnProperty('z'); // false
obj.z=5;
obj.hasOwnProperty('z'); // true
foo.prototype.z; // still 3
obj.z; // 5
obj.z = undefined;
obj.z; // undefined
delete obj.z; // true
obj.z; // 3
delete obj.z; // true
obj.z; // still 3!!!
//创建对象 Object.create
var obj = Object.create({x : 1});
obj.x // 1
typeof obj.toString // "function"
obj.hasOwnProperty('x');// false
var obj = Object.create(null);
obj.toString // undefined
-
读写对象属性
-
属性异常
-
删除属性
-
检测属性
-
枚举属性
var obj = {x : 1, y : 2};
obj.x; // 1
obj["y"]; // 2
obj["x"] = 3;
obj.y = 4;
var obj = {x1 : 1, x2 : 2};
var i = 1, n = 2;
for (; i <= n; i++) {
console.log(obj['x' + i]);
}
// 输出: 1, 2
var p;
for (p in obj) {
console.log(obj[p]);
}
属性读写-异常
var obj = {x : 1};
obj.y; // undefined
var yz = obj.y.z; // TypeError: Cannot read property 'z' of undefined
obj.y.z = 2; // TypeError: Cannot set property 'z' of undefined
//异常解除
var yz;
if (obj.y) {
yz = obj.y.z;
}
//或者
var yz = obj && obj.y && obj.y.z;
属性删除
var person = {age : 28, title : 'fe'};
delete person.age; // true
delete person['title']; // true
person.age; // undefined
delete person.age; // true
delete Object.prototype; // false,
var descriptor = Object.getOwnPropertyDescriptor(Object, 'prototype');
descriptor.configurable; // false
//global属性
var globalVal = 1;
delete globalVal; // false
(function() {
var localVal = 1;
return delete localVal;
}()); // false
function fd() {}
delete fd; // false
(function() {
function fd() {};
return delete fd;
}()); // false
//全局属性的删除
ohNo = 1;
window.ohNo; // 1
delete ohNo; // true
属性检测
var cat = new Object;
cat.legs = 4;
cat.name = "Kitty";
'legs' in cat; // true
'abc' in cat; // false
"toString" in cat; // true, inherited property!!!
hasOwnProperty方法
cat.hasOwnProperty('legs'); // true
cat.hasOwnProperty('toString'); // false
cat.propertyIsEnumerable('legs'); // true
cat.propertyIsEnumerable('toString'); // false
defineProperty检测
Object.defineProperty(cat, 'price', {enumerable : false, value : 1000});
cat.propertyIsEnumerable('price'); // false
cat.hasOwnProperty('price'); // true
if (cat && cat.legs) {
cat.legs *= 2;
}
if (cat.legs !== undefined) {
// only if cat.legs is not undefined
}
//Notes:
if (cat.legs != undefined) {
// !== undefined, or, !== null
}
属性枚举
obj.propertyIsEnumerable
var o = {x : 1, y : 2, z : 3};
'toString' in o; // true
o.propertyIsEnumerable('toString'); // false
var key;
for (key in o) {
console.log(key); // x, y, z
}
var obj = Object.create(o);
obj.a = 4;
var key;
for (key in obj) {
console.log(key); // a, x, y, z
}
var obj = Object.create(o);
obj.a = 4;
var key;
for (key in obj) {
if (obj.hasOwnProperty(key)) {
console.log(key); // a
}
}
Notes: 用getter,setter方法,更可以看到成员变量的 私有属性
var man = {
name : 'Bosn',
weibo : '@Bosn',
get age() {
return new Date().getFullYear() - 1988;
},
set age(val) {
console.log('Age can\'t be set to ' + val);
}
}
console.log(man.age); // 27
man.age = 100; // Age can't be set to 100
console.log(man.age); // still 27
var man = {
weibo : '@Bosn',
$age : null,
get age() {
if (this.$age == undefined) {
return new Date().getFullYear() - 1988;
} else {
return this.$age;
}
},
set age(val) {
val = +val;
if (!isNaN(val) && val > 0 && val < 150) {
this.$age = +val;
} else {
throw new Error('Incorrect val = ' + val);
}
}
}
console.log(man.age); // 27
man.age = 100;
console.log(man.age); // 100;
man.age = 'abc'; // error:Incorrect val = NaN
get/set与原型链
function foo() {}
Object.defineProperty(foo.prototype, 'z',
{get : function(){return 1;}});
var obj = new foo();
obj.z; // 1
obj.z = 10;
obj.z; // still 1
Object.defineProperty(obj, 'z',
{value : 100, configurable: true});
obj.z; // 100;
delete obj.z;
obj.z; // back to 1
var o = {};
Object.defineProperty(o, 'x', {value : 1}); // writable=false, configurable=false
var obj = Object.create(o);
obj.x; // 1
obj.x = 200;
obj.x; // still 1, can't change it
Object.defineProperty(obj, 'x', {writable:true, configurable:true, value : 100});
obj.x; // 100
obj.x = 500;
obj.x; // 500
Object.getOwnPropertyDescriptor({pro : true}, 'pro');
// Object {value: true, writable: true, enumerable: true, configurable: true}
Object.getOwnPropertyDescriptor({pro : true}, 'a'); // undefined
var person = {};
Object.defineProperty(person, 'name', {
configurable : false,
writable : false,
enumerable : true,
value : "Bosn Ma"
});
person.name; // Bosn Ma
person.name = 1;
person.name; // still Bosn Ma
delete person.name; // false
Object.defineProperty(person, 'type', {
configurable : true,
writable : true,
enumerable : false,
value : "Object"
});
Object.keys(person); // ["name"]
Object.defineProperties(person, {
title : {value : 'fe', enumerable : true},
corp : {value : 'BABA', enumerable : true},
salary : {value : 50000, enumerable : true, writable : true}
});
Object.getOwnPropertyDescriptor(person, 'salary');
// Object {value: 50000, writable: true, enumerable: true, configurable: false}
Object.getOwnPropertyDescriptor(person, 'corp');
// Object {value: "BABA", writable: false, enumerable: true, configurable: false}
Object.defineProperties(person, {
title : {value : 'fe', enumerable : true},
corp : {value : 'BABA', enumerable : true},
salary : {value : 50000, enumerable : true, writable : true},
luck : {
get : function() {
return Math.random() > 0.5 ? 'good' : 'bad';
}
},
promote : {
set : function (level) {
this.salary *= 1 + level * 0.1;
}
}
});
Object.getOwnPropertyDescriptor(person, 'salary');
// Object {value: 50000, writable: true, enumerable: true, configurable: false}
Object.getOwnPropertyDescriptor(person, 'corp');
// Object {value: "BABA", writable: false, enumerable: true, configurable: false}
person.salary; // 50000
person.promote = 2;
person.salary; // 60000
标签原型:proto
var toString = Object.prototype.toString;
function getType(o){
return toString.call(o).slice(8,-1);
};
toString.call(null); // "[object Null]"
getType(null); // "Null"
getType(undefined); // "Undefined"
getType(1); // "Number"
getType(new Number(1)); // "Number"
typeof new Number(1); // "object"
getType(true); // "Boolean"
getType(new Boolean(true)); // "Boolean"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 failed
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
//冻结
Object.freeze(obj);
Object.getOwnPropertyDescriptor(obj, 'x');
// Object {value: 1, writable: false, enumerable: true, configurable: false}
Object.isFrozen(obj); // true
// [caution] not affects prototype chain!!!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}"
obj = {val : undefined, a : NaN, b : Infinity, c : new Date()};
JSON.stringify(obj); // "{"a":null,"b":null,"c":"2015-01-20T14:15:43.910Z"}"
obj = JSON.parse('{"x" : 1}');
obj.x; // 1
序列化-自定义
var obj = {
x : 1,
y : 2,
o : {
o1 : 1,
o2 : 2,
toJSON : function () {
return this.o1 + this.o2;
}
}
};
JSON.stringify(obj); // "{"x":1,"y":2,"o":3}"•对象的结构
•创建对象
•属性操作
•getter setter
•属性标签
•对象标签
•序列化
•对象方法
数组是值的有序集合。每个值叫做元素,每个元素在数组中都有数字位置编号,也就是索引。JS中的数组是弱类型的,数组中可以含有不同类型的元素。数组元素甚至可以是对象或其它数组。
var arr = [1, true, null, undefined, {x : 1}, [1, 2, 3]];创建数组-字面量
var BAT = ['Alibaba', 'Tencent', 'Baidu'];
var students = [{name : 'Bosn', age : 27}, {name : 'Nunnly', age : 3}];
var arr = ['Nunnly', 'is', 'big', 'keng', 'B', 123, true, null];
var arrInArr = [[1, 2], [3, 4, 5]];
var commasArr1 = [1, , 2]; // 1, undefined, 2
var commasArr2 = [,,]; // undefined * 2创建数组-new Array
var arr = new Array();
var arrWithLength = new Array(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];
arr[1]; // 2
arr.length; // 5
arr[5] = 6;
arr.length; // 6
delete arr[0];
arr[0]; // undefined数组的增删
动态的,无需指定大小
var arr = [];
arr[0] = 1;
arr[1] = 2;
arr.push(3);
arr; // [1, 2, 3]
arr[arr.length] = 4; // equal to arr.push(4);
arr; // [1, 2, 3, 4]
arr.unshift(0);
arr; // [0, 1, 2, 3, 4];
delete arr[2];
arr; // [0, 1, undefined, 3, 4]
arr.length; // 5
2 in arr; // false
arr.length -= 1;
arr; // [0, 1, undefined, 3, 4], 4 is removed
arr.pop(); // 3 returned by pop
arr; // [0, 1, undefined], 3 is removed
arr.shift(); // 0 returned by shift
arr; // [1, undefined]
数组迭代
var i = 0, n = 10;
var arr = [1, 2, 3, 4, 5];
for (; i < n; i++) {
console.log(arr[i]); // 1, 2, 3, 4, 5
}
for(i in arr) {
console.log(arr[i]); // 1, 2, 3, 4, 5
}
Array.prototype.x = 'inherited';
for(i in arr) {
console.log(arr[i]); // 1, 2, 3, 4, 5, inherited
}
for(i in arr) {
if (arr.hasOwnProperty(i)) {
console.log(arr[i]); // 1, 2, 3, 4, 5
}
}var arr = [[0, 1], [2, 3], [4, 5]];
var i = 0, j = 0;
var row;
for (; i < arr.length; i++) {
row = arr[i];
console.log('row ' + i);
for (j = 0; j < row.length; j++) {
console.log(row[j]);
}
}
稀疏数组并不含有从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
var arr = [,,];
0 in arr; // false
{} => Object.prototype
[] => Array.prototype
Array.prototype.join()
将数组转化成字符串
var arr = [1, 2, 3];
arr.join(); // "1,2,3"
arr.join("_"); // "1_2_3"
function repeatString(str, n) {
return new Array(n + 1).join(str);
}
repeatString("a", 3); // "aaa"
repeatString("Hi", 5); // "HiHiHiHiHi"
Notes:原数组被修改
var arr = ["a", "d", "c", "b"];
arr.sort(); // ["a", "b", "c", "d"]
arr = [13, 24, 51, 3];
arr.sort(); // [13, 24, 3, 51]
arr; // [13, 24, 3, 51]
arr.sort(function(a, b) {
return a - b;
}); // [3, 13, 24, 51]
arr = [{age : 25}, {age : 39}, {age : 99}];
arr.sort(function(a, b) {
return a.age - b.age;
});
arr.forEach(function(item) {
console.log('age', item.age);
});
// result:
// age 25
// age 39
// age 99
Notes:原数组不被修改
var arr = [1, 2, 3];
arr.concat(4, 5); // [1, 2, 3, 4, 5]
arr; // [1, 2, 3]
arr.concat([10, 11], 13); // [1, 2, 3, 10, 11, 13]
arr.concat([1, [2, 3]]); // [1, 2, 3, 1, [2, 3]]
Notes:原数组未被修改
var arr = [1, 2, 3, 4, 5];
arr.slice(1, 3); // [2, 3]
arr.slice(1); // [2, 3, 4, 5]
arr.slice(1, -1); // [2, 3, 4]
arr.slice(-4, -3); // [2]
Notes:原数组被修改
var arr = [1, 2, 3, 4, 5];
arr.splice(2); // returns [3, 4, 5]
arr; // [1, 2];
arr = [1, 2, 3, 4, 5];
arr.splice(2, 2); // returns [3, 4]
arr; // [1, 2, 5];
arr = [1, 2, 3, 4, 5];
arr.splice(1, 1, 'a', 'b'); // returns [2]
arr; // [1, "a", "b", 3, 4, 5]
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
Array.prototype.map
var arr = [1, 2, 3];
arr.map(function(x) {
return x + 10;
}); // [11, 12, 13]
arr; // [1, 2, 3]
Array.prototype.filter)
var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
arr.filter(function(x, index) {
return index % 3 === 0 || x >= 8;
}); // returns [1, 4, 7, 8, 9, 10]
arr; // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Array.prototype.indexOf&lastIndexOf
var arr = [1, 2, 3, 2, 1];
arr.indexOf(2); // 1
arr.indexOf(99); // -1
arr.indexOf(1, 1); // 4
arr.indexOf(1, -3); // 4
arr.indexOf(2, -1); // -1
arr.lastIndexOf(2); // 3
arr.lastIndexOf(2, -2); // 3
arr.lastIndexOf(2, -3); // 1
Array.isArray
Array.isArray([]); // true
[] instanceof Array; // true
({}).toString.apply([]) === '[object Array]'; // true
[].constructor === Array; // true
字符串和数组
var str = "hello world";
str.charAt(0); // "h"
str[1]; // e
Array.prototype.join.call(str, "_");
// "h_e_l_l_o_ _w_o_r_l_d"
var str = "hello world";
str.charAt(0); // "h"
str[1]; // e
Array.prototype.join.call(str, "_");
// "h_e_l_l_o_ _w_o_r_l_d"
## 函数
函数是一块JavaScript代码,被定义一次,但可执行和调用多次。 JS中的函数也是对象,所以JS函数可以像其它对象那样操作和传递 所以我们也常叫JS中的函数为函数对象。
- this
- arguments
- 作用域
- 不同 的调用方法
- 不同 的创建方法
- 直接调用 foo();
- 对象方法 obj.method();
- 构造器 new Foo();
- call/apply/bind func.call(obj);
函数声明
function add (a, b) {
a = +a;
b = +b;
if (isNaN(a) || isNaN(b)) { return;
}
return a + b;
}
函数表达式
// function variable 最常用
var add = function (a, b) {
// do sth
};
// IEF(Immediately Executed Function) 经常用
(function() {
// do sth
})();
// first-class function 很少用
return function() {
// do sth
};
// NFE (Named Function Expression) 很少用,递归的时候会用到
var add = function foo (a, b) {
// do sth
};
变量与函数的声明前置
var num=add(1,2) //3
console.log(num);
function add(a,b){
a=+a;
b=+b;
if(isNaN(a) || isNaN(b)){
return;
}
return a+b;
}
**Notes:**函数表达式方式这么做是错的.
命名函数表达
var func = function nfe() {};
alert(func === nfe);
// 递归调用
var func = function nfe() {
/** do sth.**/
nfe();
}
var func = new Function('a', 'b', 'console.log(a + b);');
func(1, 2); // 3
var func = Function('a', 'b', 'console.log(a + b);');
func(1, 2); // 3
//CASE1 localVal 仍为局部变量
Function('var localVal="local";console.log(localVal);')();
console.log(typeof localVal);
//result: local,undefined
//CASE2 local 不可访问,全局变量global可以访问 .原因,想想闭包
var globalVal='global';
(function(){
var localVal='local';
Function('console.log(typeof localVal,typeof globalVal);')();
})();
## this
-
全局的this (浏览器) ,指向window/浏览器.
console.log(this.document === document); // true console.log(this === window); // true this.a = 37; console.log(window.a); // 37 -
一般函数的this(浏览器),指向浏览器/window.
function f1(){ return this; } f1() === window; // true, global object function f2(){ "use strict"; // see strict mode return this; } f2() === undefined; // true -
作为对象方法的函数的this,指向所创建的对象
var o = { prop: 37, f: function() { return this.prop; } }; console.log(o.f()); // logs 37 var o = {prop: 37}; function independent() { return this.prop; } o.f = independent; console.log(o.f()); // logs 37
-
对象原型链上的this 指向最具体层的对象,虽然在这里是this是p的原型链p上的this,创建过程中指向了p
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 -
get/set方法与this 指向get/set的对应的对象
function modulus(){
return Math.sqrt(this.re * this.re + this.im * this.im);
}
var o = {
re: 1,
im: -1,
get phase(){
return Math.atan2(this.im, this.re);
}
};
Object.defineProperty(o, 'modulus', {
get: modulus, enumerable:true, configurable:true});
console.log(o.phase, o.modulus); // logs -0.78 1.4142-
构造器中的this
function MyClass(){ this.a = 37; } var o = new MyClass(); //new 若没有返回值或返回值为基本类型,则将this作为返回值,返回给新创建的对象 console.log(o.a); // 37,来资源原型链中查找到,而不是自身的 function C2(){ this.a = 37; return {a : 38}; } /*当我们使用new(作为构造器)来创建对象的时候, 这时this会指向一个空的对象,这个空对象的原型会指向是Myclass.porotary this会指向MyClass.porototype的空对象 但是当有返回值时,如果返回的是个对象的话,那么会把对象作为返回值,所以这里o.a =38,这里的o的this指向返回的对象{a:38},所以o.a=38 */ o = new C2(); console.log(o.a); // 38 -
call/apply方法与this
function add(c, d){ return this.a + this.b + c + d; } var o = {a:1, b:3}; add.call(o, 5, 7); // 1 + 3 + 5 + 7 = 16 add.apply(o, [10, 20]); // 1 + 3 + 10 + 20 = 34 function bar() { console.log(Object.prototype.toString.call(this)); } bar.call(7); // "[object Number] //Notes:call(this,arg[0],arg[1],...);我们用这个函数去调用没法直接调用的方法 -
bind方法与this
作用同call/apply,更简单高效ES5支持
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## 参数属性与arguments
function foo(x,y) {
console.log(x,y,this);
}
foo.call(100,1,2);//1,2,Number(100)
foo.apply(true,[3,4]);//3,4,Boolean(true)
foo.apply(null);//undefined,undefined,window (注意第三个量)
foo.apply(undefined);//undefined,undefined,window (注意第三个量)apply/call 方法(浏览器)
function foo(x,y){
'use sttic';
console.log(x,y,this);
}
foo.apply(null); // undefined, undefined, null
foo.apply(undefined); // undefined, undefined, undefinedbind方法
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();//81bing与currying
function add(a,b,c){
return a+b+c;
}
var func=add.bind(undefined,100);
func(3);//103
var func2=func.bind(undefined,200);
func2(10);//310function getConfig(colors,size,otherOptions){
console.log(colors,size,otherOptions);
}
var defaultConfig=getConfig.bind(null,"#CC0000","1024*768");
defaultConfig("123");
degaultConfig("456");
bind 与 new
function foo(){
this.b=100;
return this.a;
}
var func = foo.bind({a:1});
func(); //1,这里返回1,并且函数对象获得一个b=100的属性,但不作为返回值
new func(); //{b:100}。new之后会有一个空对象,空对象的原型会指向foo.prototype.这样一个空对象的b属性会被设置为b=100,整个空对象作为返回值返回,忽略掉return this.a的一个return.用new调用,对于这种this的情况,会被忽略掉.
## 闭包
!function(){
var localData="localData here";
document.addEventListener('click',
function(){
console.log(localData);
});
}();
!function(){
var localData="localData here";
var url="http://www.baidu.com/";
$.ajax({
url:url,
sucess:function(){
//do sth...
console.log(localData);
}
});
}();
document.body.innerHTML="<div id=div1>aa</div>"+"<div id=div2>bbb</div><div id=div3>ccc</div>";
for(var i=0;i<4;i++){
document.getElementById('div'+i).addEventListener('click',function(){
alert(i);//all are 4
});
}
改正如下:
document.body.innerHTML="<div id=div1>aa</div>"
+"<div id=div2>bbb</div><div id=div3>ccc</div>";
for(var i=1;i<4;i++){
!function(i){
document.getElementById('div'+i).addEventListener('click',function(){
alert(i);//1,2,3
});
}(i);
}
!function(){
var _userId=2345;
var _typeId='item';
var export={};
function converter(userId){
return +userId;
}
export.getUserId=function(){
return converter(_userId);
}
export.getTypeId=function(){
return _typeId;
}
window.export=export;
}());
export.getUserId();//2345
export.getTypeId();//item
export._userId; //undefined
export._typeId; //undefined
export.converter;//undefined
在计算机科学中,闭包(也称词法闭包或函数闭包)是指一个函数或函数的引用,与一个引用环境绑定在一起。这 个引用环境是一个存储该函数每个非局部变量(也叫自由变量)的表。 闭包,不同于一般的函数,它允许一个函数在立即词法作用域外调用时,仍可访问非本地变量。
from 维基百科
优点
- 灵活和方便
- 封装
缺点
- 空间浪费
- 内存泄漏
- 性能消耗
## 作用域
作用域(全局、函数、eval)
var a = 10; //全局
(function() {
var b = 20; //函数
})();
console.log(a); // 10
console.log(b); // error, b in not defined
for (var item in {a : 1, b : 2}) {
console.log(item);
}
console.log(item); // item still in scope
eval("var a = 1;");function outer2(){
var local2=1;
function outer1(){
var local1=1;
//visit local1,local2,or global3
console.log(local1,local2,global3);
}
outer1();
}
var global3=1;
outer2();
function outer(){
var i=1;
var func=new Function("console.log(typeof i);");
func();//undefined
}
outer();
(function(){
//to do sth here
var a,b;
})();
!function(){
var a,b;
}();
// 继承
function Person() {
//todo
}
function Student( ) {
//todo
}
Student.prototype=Person.prototype;//1
Student.prototype=new Person();//2
Student.prototype=Object.create(Person.prototype);//
// Notes:这三种方法中,第一种错误的,破坏了原型链上其他的原型,
//第二种,不好,Student 是个类,往上面加函数加对象都很奇怪
//ji 的写,不向上查找的属性。 问题是ES5 之后才有的
//ES4 的兼容模式:
if (!Object.create) {
Object.create=function(proto) {
function F(){}
F.prototype=proto;
return new F;
}
}
个人心得: 以前在学C++,Java的时候没觉得面向对象怎么怎么样,觉得继承也好,重载也好,就应该是那样的,没什么了不起的.现在学Javascript感慨JavaScript是彻头彻尾的面向对象啊(嗯?我知道它也可以是函数式啦),各种设计模式满天飞啊~~