callee
和caller
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| function inner(){
console.log(arguments.callee);
console.log(arguments.callee.caller);
console.log(inner.caller);
}
function outer(){
inner();
}
outer();
|
callee
放回正在执行的函数本身的引用,它是arguments
的一个属性
caller
返回一个函数的引用,这个函数调用了当前的函数。
严格模式下,不允许访问arguments.callee
和arguments.caller
属性,主要体现在arguments.[[Get]]
内部方法
严格模式下,arguments,arguments.callee,arguments.caller,arguments.callee.caller
也不允许再被赋值。如下代码所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| 'use strict';
void function fn(a) {
console.log(arguments[0]);
a = 2;
console.log(arguments[0]);
}(1);
void function(){
console.log('hi');
}();
|
在使用立即执行的函数表达式时,可以利用 void
运算符让 JavaScript
引擎把一个函数识别成函数表达式
而不是函数声明(语句)。
实参和形参
1 2 3 4 5 6 7 8 9
| var add = function (a,b) {
console.log(arguments.length);
console.log(arguments.callee.length);
};
add(1,2,3);
|
Array.prototype.slice.call(arguments)
slice
有两个用法,一个是String.slice
,一个是Array.slice
,第一个返回的是字符串,第二个返回的是数组。
Array.prototype.slice.call(arguments)
能够将arguments
转成数组,那么就是arguments.toArray().slice()
;
因为arguments
并不是真正的数组对象,只是与数组类似而已,所以它并没有slice
这个方法,而Array.prototype.slice.call(arguments)
可以理解成是将arguments
转换成一个数组对象,让arguments
具有slice()
方法。 比如:
1 2 3
| var arr = [1,2,3,4];
console.log(Array.prototype.slice.call(arr,2));
|
同样,还有Array.prototype.forEach.call()
,forEach()
方法让数组的每一项都执行一次给定的函数。
String()
我们可以用String()
来确定某一变量是否是null
或者undefined
1 2 3 4 5 6
| var a , b = null;
String(a);
String(b);
|
直接调用String()
作为方法时,将会执行类型转换,返回经过toString(value)
得到的字符串字面量(与new String()
不同),或者空字符串(’’).
window 对象
1 2 3 4 5 6 7 8 9 10 11
| <script>
(function () {
var root = this;
console.log(root);
})();
</script>
|
打开控制台,你可以看到window
对象的一系列属性和方法:
new function
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| var a = function () {};
console.log(typeof a);
var b = new function () {};
console.log(typeof b);
var c = new Function ();
console.log(typeof c);
|
new function
是一个JavaScript
中用户自定义的对象
1 2 3 4 5 6 7 8 9
| var obj = function (name) {
this.name = name;
};
var b = new obj('trigkit4');
console.log(b.name);
|
js中的false和true
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
|
console.log(Boolean(''));
console.log(Boolean(null));
console.log(Boolean(undefined));
console.log(Boolean(0));
console.log(Boolean(false));
console.log(Boolean(NaN));
console.log(Boolean(' '));
console.log(Boolean('NaN'));
|
除了false,null,undefined
,空字符串''
,数字0和NaN
以外,其他所有值都被当做是真,包括true
,字符串""
里包含的值,以及所有对象。
valueOf()
和 toString()
valueOf()
和toString()
方法是所有ECMAScript
对象拥有的内置方法。操作对象时,valueOf()
和toString()
会被隐式的调用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
|
console.log(Object.valueOf());
console.log(Object.prototype.valueOf());
var boo = new Boolean(1);
console.log(boo.valueOf());
var bar = Boolean(0); console.log(bar.valueOf());
var str = String("trigkit4"); console.log(str.valueOf()); console.log(null.valueOf()); console.log(undefined.valueOf());
console.log(Object.prototype.toString());
console.log(Object.toString());
Object.prototype.toString.call(null);
Object.prototype.toString.call(undefined);
{a: 'b'}.toString();
|
valueOf()
方法的目的是将对象转换成最有意义的原始值([[PrimitiveValue]]
)。即ECMAScript
的5种基本类型中的三种,布尔值、数字、字符串
。
当valueOf
方法被调用时,会调用内置的ToObject
,并将this
作为参数传进去。ToObject
检测会根据参数类型进行数值的转换:
1 2 3 4 5 6 7 8 9 10 11
| Undefined - 抛出TypeError异常
Null - 抛出TypeError异常
Boolean - 创建一个Boolean对象,调用ToBoolean生成[[PrimitiveValue]]
Number - 创建一个Number对象,调用ToNumber生成[[PrimitiveValue]]
String - 创建一个String对象,调用ToString生成[[PrimitiveValue]]
Object - 对象本身
|
ECMAScript
对象的大多数操作的转换结果是字符串,这两个方法的结果是相同的。但是如果操作的对象为Number
、Boolean
或者Date
,结果就不同了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| var foo = {
toString: function () {
return "foo";
},
valueOf: function () {
return 5;
}
};
console.log(foo + "bar");
console.log([foo, "bar"].join(""));
|
在这个上下文环境中,我们使用"+"
操作符来使字符串连接,但是,foo
并没有使用toString
来转换成字符串,它使用valueOf
转换成一个number
,这并不是我们想要的,
但它是如何工作的,这是+
运算符的算术和字符串连接超载的副作用。"+"
操作符有一个明确的处理过程:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| 1.评估左手侧,并得到该值。
2.评估右手侧,并获得该值。
3.同时在左手和右手侧调用ToPrimitive(无提示)
4.如果任何原始值是一个字符串,然后跳到7。
5.在这两个值调用ToNumber。
6.返回值的总和。
7.在这两个值调用toString。
8.返回的值连接起来
|
setInterval和setTimeout
1 2 3 4 5 6 7 8 9 10 11 12
| alert(1);
setTimeout("alert(2)", 0);
alert(3);
执行顺序为:1,3,2,虽然延时了0ms
setTimeout 0
后面的语句执行完再执行本身,这时就可以用到setTimeout延时0ms来实现了。
|
cookie的创建和删除
cookie
可以跨越一个域名下的多个网页,但不能跨越多个域名使用。
1 2 3 4
| document.cookie = “user = 值;expires = 过期时间;path = 路径访问;
domain = 域名访问;secure = 安全的https限制通信"
|
cookie的创建方式
设置cookie
我们一般都封装成一个函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| function addCookie(sName,sValue,day) {
var expireDate = new Date();
expireDate.setDate(expireDate.getDate()+day);;
document.cookie = escape(sName) + '=' + escape(sValue) +';
expires=' + expireDate.toGMTString();6
}
|
删除cookie
为了删除一个cookie
,可以将其过期时间设定为一个过去的时间,例如:
1 2 3 4 5 6 7 8 9 10 11 12
|
var date=new Date();
date.setTime(date.getTime()-10000);
document.cookie="userId=828; expires="+date.toGMTString();
|
给cookie设置终止日期
到现在为止,所有的cookie
都是单会话cookie
,即浏览器关闭后这些cookie
将会丢失,事实上这些cookie
仅仅是存储在内存中,而没有建立相应的硬盘文件。
在实际开发中,cookie
常常需要长期保存,例如保存用户登录的状态。这可以用下面的选项来实现:
1
| document.cookie="userId=828; expiress=GMT_String";
|
其中GMT_String
是以GMT
格式表示的时间字符串,这条语句就是将userId
这个cookie
设置为GMT_String
表示的过期时间,超过这个时间,cookie
将消失,不可访问。例如:如果要将cookie
设置为10天后过期,可以这样实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| <script language="JavaScript" type="text/javascript">
var date=new Date();
var expiresDays=10;
date.setTime(date.getTime()+expiresDays*24*3600*1000);
document.cookie="userId=828; userName=hulk; expires="+date.toGMTString();
</script>
|
对象和函数可以如数组一样,用属性名或方法名作为下标来访问:
对象的创建
1 2 3 4 5 6 7 8
|
function MyFunc(){}
var obj1 = new MyFunc();
var obj2 = new MyFunc;
|
可以把上面的代码改写成这种等价形式:
1 2 3 4 5 6
| function MyFunc(){};
var obj1 = {};
MyFunc.call(obj1);
|
作用域
通过自执行的匿名函数你可以把所有原本属于全局的变量都隐藏起来:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
|
(function () {
var msg = "Thanks for visiting";
window.onunload = function () {
console.log(msg);
};
})();
|
上下文对象是通过this
变量体现的,这个变量永远指向当前代码所处的对象中。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| var obj = {
yes : function(){
this.val = true;
},
no : function(){
this.val = false;
}
};
console.log(obj.val == null);
obj.yes();
console.log(obj.val == true);
|
String 原型方法的扩展
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
|
String.prototype.Regular = function(reg){
var result = true;
if(this.length > 0){
if(!reg.test(this)){
result = false;
}
}
return result;
}
String.prototype.trim = function () {
return this.replace(/(^\s*)|(\s*$)/g,'');
};
|
^
表示字符串必须以后面的规则开头,而(^\s*)
表示的就是以0个空格或者多个空格开头,后面的(\s*$)
的意思就是, 以0个空格或者多个空格结尾。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
|
String.prototype.isNull = function(){
return this.trim().length == 0 ? true : false;
}
String.prototype.isVersion = function(){
var reg = /^([a-zA-Z_])([a-zA-Z0-9_.])*$/;
return this.Regular(reg);
}
String.prototype.isString = function(){
var reg = /^[^']*$/;
return this.Regular(reg);
}
String.prototype.isLetter = function(){
var reg = /^[a-zA-Z]+$/;
return this.Regular(reg);
}
|
constructor
属性
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| function User(){}
var me = new User();
console.log(me.constructor);
var you = new me.constructor();
console.log(me.constructor == you.constructor);
|
Object.create
1 2 3 4 5 6 7 8 9
| function Parent(){}
var o = Object.create(Parent.prototype);
console.log(o instanceof Parent);
console.log(o instanceof Object);
console.log(Object.prototype.toString.call(o));
|
“数据属性”是可获取且可设置值的属性。 数据属性描述符包含 value
特性,以及 writable、enumerable
和 configurable
特性。 如果未指定最后三个特性,则它们默认为 false
。
1 2 3 4 5 6 7 8
| function Parent(){}
var o = Object.create(Parent);
console.log(o instanceof Parent);
console.log(o instanceof Object);
|
另外一个实例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
| var book1 = {
title:"JS高级程序设计",
pages : 1001,
getTitle:function(){
console.log(this.title);
}
};
var book2 = Object.create(book1,{
title:{
configurable:true,
enumerable:true,
value:"JS权威指南",
wratable:true
}
});
book1.getTitle();
book2.getTitle();
console.log(book1.hasOwnProperty("getTitle"));
console.log('pages' in book2);
console.log(book2.hasOwnProperty("getTitle"));
console.log(book1.isPrototypeOf(book2));
|
再看另一个例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| function Constructor(){}
obj = new Constructor();
obj = Object.create(Constructor.prototype);
console.log(obj);
console.log(Object.create(Constructor.prototype));
console.log(obj instanceof Constructor);
console.log(Constructor.prototype.isPrototypeOf(obj));
var foo;
foo = {};
foo = Object.create(Object.prototype);
|
另外:
1 2 3
| console.log(Object.prototype);
console.log(Object.create(Object.prototype));
|
通过Object.create(Object.prototype)
创建的实例对象就继承了Object
原型下的属性和方法。
javascript
所有function
类型的对象都有一个prototype
属性。这个prototype
属性本身又是一个object
类型的对象,原型对象都包含一个指向构造函数的指针,而每一个实例也都包含一个指向原型对象内部的指针。
参考:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/create
prototype原型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| function User(){}
var u1 = new User();
console.log(u1.prototype);
console.log(User.prototype);
console.log(u1.__proto__);
User.prototype = {
name : "trigkit4",
age : 22
};
|
使用构造函数
创建原型对象和使用字面量
创建对象在使用上基本相同,但还是有些区别,字面量创建的方式使用constructor
属性不会指向实例,而会指向Object
,构造函数创建的方式则相反
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| function User(){}
User.prototype = {
name : "trigkit4",
age : 22
};
var u1 = new User();
console.log(u1.constructor);
console.log(u1 instanceof User);
console.log(u1.constructor == User);
console.log(u1.constructor == Object);
User.prototype = {
constructor : User;
}
|
字面量方式为什么constructor
会指向Object
?因为User.prototype = {};
这种写法其实就是创建了一个新对象:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| function User(){
User.prototype = {
constructor : User
};
var u1 = new User();
console.log(User.constructor);
console.log(u1.constructor == User);
|
另一个例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| (function () {
console.log(Object.prototype);
console.log(Array.prototype);
console.log(Array.prototype.push);
console.log(Function.prototype);
console.log(Function.prototype.bind);
})();
|
Object.prototype.toString
在toString()
方法被调用时,会执行下面的操作步骤:
1 2 3 4 5 6 7 8 9 10
| 如果this的值为undefined,则返回"[object Undefined]".
如果this的值为null,则返回"[object Null]".
让O成为调用ToObject(this)的结果.
让class成为O的内部属性[[Class]]的值.
返回三个字符串"[object ", class, 以及 "]"连接后的新字符串.
|
由于 JavaScript
中一切都是对象,任何都不例外,对所有值类型应用Object.prototype.toString.call()
方法结果如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| console.log(Object.prototype.toString.call(123))
console.log(Object.prototype.toString.call('123'))
console.log(Object.prototype.toString.call(undefined))
console.log(Object.prototype.toString.call(true))
console.log(Object.prototype.toString.call({}))
console.log(Object.prototype.toString.call([]))
console.log(Object.prototype.toString.call(function(){}))
|
所有类型都会得到不同的字符串,几乎完美。
在JavaScript
中,想要判断某个对象值属于哪种内置类型,最靠谱的做法就是通过Object.prototype.toString
方法.
面向对象
下面是来自Prototype.js
的一段代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
|
var Class = {
create: function(){
return function () {
this.initialize.apply(this,arguments);
}
}
};
Object.extend = function (destination,source) {
for(property in source){
destination[property] = source[property];
}
};
|
成员操作符
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| function aFunc(){}
aFunc.oProperty = "函数的一个属性";
aFunc.aMethod = function(){
console.log("函数的一个方法");
};
console.log(aFunc["oProperty"]);
console.log(aFunc["aMethod"]());
for(var s in aFunc){
console.log(s + "is a "+typeof(aFunc[s]));
}
|
特权方法与私有方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
| function Constructor(msg)
this.Message = msg;
//私有属性
var separator = '-';
var owner = this;
//私有方法
function alertMessage(){
console.log(owner.Message);
}
alertMessage();
this.aptMessage = function (str)
this.Message += separator + str;
alertMessage();
}
}
Constructor.prototype.clearMessage = function (str)
this.Message = '';
};
Constructor.name = 'trigkit4';
Constructor.alertName = function (name)
console.log(this.name);
};
|
特权方法
是指在构造函数的作用域中使用this
关键字定义的方法;与私有方法不同,特权方法能够被公开访问,而且还能够访问私有成员。
由于私有和特权成员在函数的内部,因此它们会被带到函数的每个实例中。
公有的原型成员是对象蓝图的一部分,适用于通过new
关键字实例化的该对象的每个实例 静态成员只适用于对象的一个特殊实例
使用对象字面量语法来向prototype
属性添加所有公有成员:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| function Constructor(){
}
Constructor.prototype = {
propertyA: 'value1',
propertyB: 'value2',
methodA: function(){},
methodB: function(){}
};
|
删除不要的节点
DOM
元素在浏览器中所占用的空间是非常大的,要及时回收不用的节点:
1 2 3 4 5 6
| var node = parentNode.removeChild(node);
node = null;
CollectGarbage();
|