你认为每个程序员都应该知道JavaScript的哪些“隐藏特性”?
在看到以下问题的优质答案后,我认为是时候向JavaScript请求它了。
HTML的隐藏特性 CSS的隐藏特性 PHP的隐藏特性 ASP的隐藏特性。网 c#的隐藏特性 Java的隐藏特性 Python的隐藏特性
尽管JavaScript可以说是目前最重要的客户端语言(问问谷歌就知道了),但令人惊讶的是,大多数web开发人员很少意识到它的强大。
你认为每个程序员都应该知道JavaScript的哪些“隐藏特性”?
在看到以下问题的优质答案后,我认为是时候向JavaScript请求它了。
HTML的隐藏特性 CSS的隐藏特性 PHP的隐藏特性 ASP的隐藏特性。网 c#的隐藏特性 Java的隐藏特性 Python的隐藏特性
尽管JavaScript可以说是目前最重要的客户端语言(问问谷歌就知道了),但令人惊讶的是,大多数web开发人员很少意识到它的强大。
当前回答
这里有一个简单的思考“this”的方法。函数中的'This'将引用该函数的未来对象实例,通常使用operator new创建。所以很明显,内部函数的“this”永远不会指向外部函数的实例。
以上建议可以让你远离麻烦。但是你可以用“this”做更复杂的事情。
示例1:
function DriveIn()
{
this.car = 'Honda';
alert(this.food); //'food' is the attribute of a future object
//and DriveIn does not define it.
}
var A = {food:'chili', q:DriveIn}; //create object A whose q attribute
//is the function DriveIn;
alert(A.car); //displays 'undefined'
A.q(); //displays 'chili' but also defines this.car.
alert(A.car); //displays 'Honda'
规则如下:
当一个函数作为一个对象的属性被调用时,在函数内部(但在任何内部函数之外)出现的任何'this'都指向该对象。
我们需要明确,即使使用operator new,“The Rule of This”也适用。在幕后,new通过对象的构造函数属性将“this”附加到对象上。
示例2:
function Insect ()
{
this.bug = "bee";
this.bugFood = function()
{
alert("nectar");
}
}
var B = new Insect();
alert(B.constructor); //displays "Insect"; By "The Rule of This" any
//ocurrence of 'this' inside Insect now refers
//to B.
为了更清楚地说明这一点,我们可以不使用operator new创建一个Insect实例。
示例3:
var C = {constructor:Insect}; //Assign the constructor attribute of C,
//the value Insect.
C.constructor(); //Call Insect through the attribute.
//C is now an Insect instance as though it
//were created with operator new. [*]
alert(C.bug); //Displays "bee."
C.bugFood(); //Displays "nectar."
[*]我能辨别的唯一实际区别是,在示例3中,'constructor'是一个可枚举属性。当使用operator new时,'constructor'变成一个属性,但不是可枚举的。如果for-in操作"for(var name in object)"返回该属性的名称,则该属性是可枚举的。
其他回答
除了公共成员外,还可以使用闭包创建具有私有(在“类”定义之外不可访问)静态成员和非静态成员的“类”。
注意,下面的代码中有两种类型的公共成员。特定于实例的(在构造函数中定义),可以访问私有实例成员,共享成员(在原型对象中定义)只能访问私有静态成员。
var MyClass = (function () {
// private static
var nextId = 1;
// constructor
var cls = function () {
// private
var id = nextId++;
var name = 'Unknown';
// public (this instance only)
this.get_id = function () { return id; };
this.get_name = function () { return name; };
this.set_name = function (value) {
if (typeof value != 'string')
throw 'Name must be a string';
if (value.length < 2 || value.length > 20)
throw 'Name must be 2-20 characters long.';
name = value;
};
};
// public static
cls.get_nextId = function () {
return nextId;
};
// public (shared across instances)
cls.prototype = {
announce: function () {
alert('Hi there! My id is ' + this.get_id() + ' and my name is "' + this.get_name() + '"!\r\n' +
'The next fellow\'s id will be ' + MyClass.get_nextId() + '!');
}
};
return cls;
})();
测试这段代码:
var mc1 = new MyClass();
mc1.set_name('Bob');
var mc2 = new MyClass();
mc2.set_name('Anne');
mc1.announce();
mc2.announce();
如果您有Firebug,您会发现除了在定义私有成员的闭包中设置断点之外,没有其他方法可以访问私有成员。
当定义需要严格验证值和完全控制状态更改的类时,这种模式非常有用。
要扩展这个类,你可以把MyClass.call(this);在扩展类的构造函数的顶部。您还需要复制MyClass。prototype对象(不要重用它,因为你也会改变MyClass的成员。
如果要替换announce方法,则需要调用MyClass。MyClass.prototype.announce.call(this);
可以将JavaScript对象绑定为HTML元素属性。
<div id="jsTest">Klick Me</div>
<script type="text/javascript">
var someVariable = 'I was klicked';
var divElement = document.getElementById('jsTest');
// binding function/object or anything as attribute
divElement.controller = function() { someVariable += '*'; alert('You can change instance data:\n' + someVariable ); };
var onclickFunct = new Function( 'this.controller();' ); // Works in Firefox and Internet Explorer.
divElement.onclick = onclickFunct;
</script>
JavaScript的通用性-覆盖默认功能
下面是覆盖窗口的代码。使用jQuery UI的对话框小部件的警报功能。我把它作为一个jQuery插件来实现。你可以在我的博客上读到;altAlert,一个用于个性化警报消息的jQuery插件。
jQuery.altAlert = function (options)
{
var defaults = {
title: "Alert",
buttons: {
"Ok": function()
{
jQuery(this).dialog("close");
}
}
};
jQuery.extend(defaults, options);
delete defaults.autoOpen;
window.alert = function ()
{
jQuery("<div />", {
html: arguments[0].replace(/\n/, "<br />")
}).dialog(defaults);
};
};
闭包的禅意
其他人也提到了关闭。但令人惊讶的是,有那么多人知道闭包,使用闭包编写代码,但仍然对闭包的真正含义有错误的认识。有些人混淆了一级函数和闭包。但也有人认为它是一种静态变量。
对我来说,闭包是一种“私有”全局变量。这是一种变量,一些函数将其视为全局变量,而其他函数则看不到。现在,我知道这是在快速和松散地描述底层机制,但这就是它的感觉和行为。说明:
// Say you want three functions to share a single variable:
// Use a self-calling function to create scope:
(function(){
var counter = 0; // this is the variable we want to share;
// Declare global functions using function expressions:
increment = function(){
return ++counter;
}
decrement = function(){
return --counter;
}
value = function(){
return counter;
}
})()
现在,增量、减量和值这三个函数共用一个变量counter,而不是一个实际的全局变量counter。这是闭包的真正本质:
increment();
increment();
decrement();
alert(value()); // will output 1
以上并不是闭包的真正有用的用法。事实上,我认为这样使用它是一种反模式。但是它对于理解闭包的性质是有用的。例如,大多数人在尝试做以下事情时会被发现:
for (var i=1;i<=10;i++) {
document.getElementById('span'+i).onclick = function () {
alert('this is span number '+i);
}
}
// ALL spans will generate alert: this span is span number 10
这是因为他们不理解闭包的本质。他们认为他们把i的值传递给了函数,而实际上这些函数共享一个变量i,就像我之前说的,一个特殊的全局变量。
为了解决这个问题,你需要分离*闭包:
function makeClickHandler (j) {
return function () {alert('this is span number '+j)};
}
for (var i=1;i<=10;i++) {
document.getElementById('span'+i).onclick = makeClickHandler(i);
}
// this works because i is passed by reference
// (or value in this case, since it is a number)
// instead of being captured by a closure
*注:我不知道这里的正确术语。
函数可以有方法。
我使用AJAX表单提交的这种模式。
var fn = (function() {
var ready = true;
function fnX() {
ready = false;
// AJAX return function
function Success() {
ready = true;
}
Success();
return "this is a test";
}
fnX.IsReady = function() {
return ready;
}
return fnX;
})();
if (fn.IsReady()) {
fn();
}